Self-Contained Utility Code (util.py
)¶
Helper functions and classes
-
class
Edge
[source]¶ Constants used by
StrutPartial.as_rects()
to communicate informationUsableRegion
needs to properly handle panel reservations on interior edges.The values of the enum’s members correspond to the tuple indexes in StrutPartial.
-
BOTTOM
= 4¶
-
LEFT
= 1¶
-
RIGHT
= 2¶
-
TOP
= 3¶
-
-
class
Gravity
[source]¶ Gravity definitions used by
Rectangle
-
BOTTOM
= (0.5, 1.0)¶
-
BOTTOM_LEFT
= (0.0, 1.0)¶
-
BOTTOM_RIGHT
= (1.0, 1.0)¶
-
CENTER
= (0.5, 0.5)¶
-
LEFT
= (0.0, 0.5)¶
-
RIGHT
= (1.0, 0.5)¶
-
TOP
= (0.5, 0.0)¶
-
TOP_LEFT
= (0.0, 0.0)¶
-
TOP_RIGHT
= (1.0, 0.0)¶
-
-
class
Rectangle
[source]¶ A representation of a rectangle with some useful methods
Fundamentally, this is a named tuple of the form
(x, y, width, height)
with some extra methods and properties to make it more useful.It supports being initialized with any mixture of
x
,width
, orx2
andy
,height
ory2
as long as sufficient information is provided to define a rectangle, and the constructor will ensure that the resulting width and height are always positive by adjustingx
andy
- Parameters
- Raises
ValueError – An invalid set of arguments was provided at construction. (eg.
width
andx2
)
>>> Rectangle(5, 2, -10, y2=10) Rectangle(x=-5, y=2, width=10, height=8) >>> Rectangle(x2=10, y2=12, width=5, height=6) Rectangle(x=5, y=6, width=5, height=6) >>> Rectangle(x2=10, y2=12, width=-5, height=-6) Rectangle(x=10, y=12, width=5, height=6)
Warning
Many of the methods on this type assume the correct use of
to_gravity()
andfrom_gravity()
and may give nonsensical answers if given rectangles which do not have top-left gravity.External users of this API are advised to contact the author to ensure any changes to make it more mistake-proof are made in a coordinated fashion.
-
__contains__
(other)[source]¶ A Rectangle is
in
another if one is entirely within the other.If
other
is not aRectangle
, this will always returnFalse
.If you need to check for overlap, check whether
intersect()
is truthy.This assumes top-left gravity.
- Return type
-
__mul__
(factor)[source]¶ Return a new Rectangle with all dimensions multiplied by
factor
This is used to apply scaling factors to monitor rectangles returned by GDK so they’ll be in the device pixel coordinates that the Wnck APIs expect.
-
closest_of
(candidates)[source]¶ Find and return the rectangle that
self
is closest to.(Unified definition of how to resolve edge cases in various operations in the most intuitive way possible.)
Based on empirical testing, the following definition of closeness has been chosen:
Choose the rectangle with the largest area area of overlap. (
self.intersect(candidate).area
)To break ties (eg. all motions result in no overlap), choose the motion with the shortest
euclidean_dist()
between the two rectangles’ centers.
(Using the center points is important when considering operations which both move and resize a rectangle.)
- Return type
-
classmethod
from_gdk
(gdk_rect)[source]¶ Factory function to convert from a
Gdk.Rectangle
This assumes top-left gravity.
-
from_gravity
(gravity)[source]¶ Treat
x
andy
as not referring to top-left corner and return a copy ofself
with them translated them so they do.Note
Almost every
Rectangle
method assumes top-left gravity, so this should be the first thing done.Note
This is intended for working in pixel values and will round any results to the nearest integer.
-
from_relative
(other_rect)[source]¶ Interpret self as relative to
other_rect
and make it absolute.(eg. Convert a window position that’s relative to a given monitor’s top-left corner into one that’s relative to the desktop as a whole)
This assumes top-left gravity.
-
intersect
(other)[source]¶ The intersection of two rectangles, assuming top-left gravity.
>>> rect1 = Rectangle(0, 0, 40, 40) >>> Rectangle(20, 20, 50, 60).intersect(rect1) Rectangle(x=20, y=20, width=20, height=20)
-
moved_into
(other)[source]¶ Attempt to return a new
Rectangle
of the same width and height that does not exceed the bounds of other.If
self
is wider/taller thanother
, line up the left/top edge as appropriate and allow the rest to overflow right/down-ward.It is your responsibility to call
intersect()
afterward if you would like to clip the rectangle to fit.>>> parent = Rectangle(0, 0, 40, 40) >>> Rectangle(10, 10, 10, 10).moved_into(parent) Rectangle(x=10, y=10, width=10, height=10) >>> Rectangle(50, 10, 10, 10).moved_into(parent) Rectangle(x=30, y=10, width=10, height=10) >>> Rectangle(50, 10, 50, 10).moved_into(parent) Rectangle(x=0, y=10, width=50, height=10) >>> Rectangle(50, 10, 10, 50).moved_into(parent) Rectangle(x=30, y=0, width=10, height=50)
-
moved_off_of
(other)[source]¶ Return a copy of
self
that has been moved as little as possible such that it no longer overlapsother
.This will move the rectangle either horizontally or vertically but not both and will rely on
closest_of()
to choose a direction.>>> panel = Rectangle(0, 0, 20, 600) >>> Rectangle(10, 10, 600, 400).moved_off_of(panel) Rectangle(x=20, y=10, width=600, height=400)
Note
If no change is needed, this will take advantage of the immutability of tuple subclasses by returning a reference to
self
without making a copy.Warning
This has no conception of “inside/outside the desktop” and may shove a window out of bounds if you don’t first ensure that it’s mostly on the correct side of a panel using something like
moved_into()
.
-
subtract
(other)[source]¶ Return a copy of
self
which has been shrunk along one axis such that it no longer overlapsother
.The edge to cut away is determined by calling
moved_off_of()
and thenintersect()
-ingself
with the result.(In effect, it will generate candidate rectangles for all four possible directions and then use
closest_of()
to choose the one that results in the smallest change.)>>> panel = Rectangle(0, 0, 20, 600) >>> Rectangle(10, 10, 600, 400).subtract(panel) Rectangle(x=20, y=10, width=590, height=400)
Note
If there is no overlap, this will take advantage of the immutability of tuple subclasses by returning a reference to
self
without making a copy.Warning
This has no conception of “inside/outside the desktop” and may make it entirely out-of-bounds rather than entirely in-bounds if you don’t first ensure that the target rectangle is more in-bounds than out-of-bounds.
-
to_gdk
()[source]¶ Helper to easily create a
Gdk.Rectangle
from aRectangle
.This assumes top-left gravity.
-
to_gravity
(gravity)[source]¶ Reverse the effect of
from_gravity()
Less concisely, this will interpret self’s
x
andy
members as referring to the top-left corner of the rectangle and then return a copy with them translated to refer to another point.Note
Almost every
Rectangle
method assumes top-left gravity, so this should be the last thing done.Note
This is intended for working in pixel values and will round any results to the nearest integer.
-
to_relative
(other_rect)[source]¶ Interpret self as absolute and make it relative to
other_rect
.(eg. Convert a window position that’s relative to the top-left corner of the desktop as a whole into one that’s relative to a single monitor)
This assumes top-left gravity.
-
class
StrutPartial
[source]¶ A simple wrapper for a sequence taken from _NET_WM_STRUT_PARTIAL. (or _NET_WM_STRUT thanks to default parameters)
Purpose: Minimize the chances of screwing up indexing into _NET_WM_STRUT_PARTIAL
- Method:
This namedtuple was created by copy-pasting the definition string from _NET_WM_STRUT_PARTIAL and then manually deleting the commas from it if necessary.
A
__new__
was added to createStrutPartial
instances from _NET_WM_STRUT data by providing default values for the missing fields.
- Parameters
left (int) – Thickness of the window’s panel reservation on the desktop’s left edge in pixels.
right (int) – Thickness of the window’s panel reservation on the desktop’s right edge in pixels.
top (int) – Thickness of the window’s panel reservation on the desktop’s top edge in pixels.
bottom (int) – Thickness of the window’s panel reservation on the desktop’s bottom edge in pixels.
left_start=0 (int) – Position of the left panel’s top edge in pixels.
left_end=sys.maxsize (int) – Position of the left panel’s bottom edge in pixels.
right_start=0 (int) – Position of the right panel’s top edge in pixels.
right_end=sys.maxsize (int) – Position of the right panel’s bottom edge in pixels.
top_start=0 (int) – Position of the top panel’s left edge in pixels.
top_end=sys.maxsize (int) – Position of the top panel’s right edge in pixels.
bottom_start=0 (int) – Position of the bottom panel’s left edge in pixels.
bottom_end=sys.maxsize (int) – Position of the bottom panel’s right edge in pixels.
-
as_rects
(desktop_rect)[source]¶ Resolve self into absolute coordinates relative to
desktop_rect
Note that struts are relative to the bounding box of the whole desktop, not the edges of individual screens.
(ie. if you have two 1280x1024 monitors and a 1920x1080 monitor in a row, with all the tops lined up and a 22px panel spanning all of them on the bottom, the strut reservations for the 1280x1024 monitors will be
22 + (1080 - 1024) = 56px
to account for the dead space below the 1024px-tall monitors.)
-
class
UsableRegion
[source]¶ A representation of the usable portion of a desktop
This stores a set of monitors and a set of
StrutPartial
instances and can be used to clip or move window rectangles to fit within the usable space.-
__bool__
()[source]¶ A
UsableRegion
is truthy if it has at least one monitor with nonzero area.- Return type
-
__repr__
()[source]¶ Override
repr
to be more useful for debugging.>>> print(repr(UsableRegion())) Region(<Monitors=[], Struts=[]>)
- Return type
-
_update
()[source]¶ Check input values and regenerate internal caches
This is internal code shared by
set_monitors()
andset_panels()
.- Raises
TypeError – The internal list of monitors contains an entry that is not a
Rectangle
or the internal list of struts contains an entry that is not aStrutPartial
.
-
clip_to_usable_region
(rect)[source]¶ Given a rectangle, return a copy that has been shrunk to fit inside the usable region of the monitor.
This is defined as a rectangle that:
Does not extend outside the monitor
Does not overlap any panels
The output rectangle will not extend outside the bounds of the input rectangle.
See
Rectangle.subtract()
for more information on how corner overlaps between windows and panels are resolved.
-
find_monitor_for
(rect)[source]¶ Find the full (including space reserved for panels)
Rectangle
for the monitor containingrect
usingRectangle.closest_of()
.
-
move_to_usable_region
(rect)[source]¶ Given a rectangle, return a copy that has been moved to be entirely within the nearest monitor and to not overlap any panels.
-
set_monitors
(monitor_rects)[source]¶ Set the list of monitor rectangles from which to calculate usable regions
-
set_panels
(panel_struts)[source]¶ Set the list of desktop struts to excluded from the usable regions
- Parameters
panel_struts (
Iterable
[StrutPartial
]) –
-
-
exception
XInitError
[source]¶ - Raised when something outside our control causes the X11 connection to
fail.
-
clamp_idx
(idx, stop, wrap=True)[source]¶ Ensure a 0-based index is within a given range [0, stop).
Uses the same half-open range convention as Python slices.
-
euclidean_dist
(vec1, vec2)[source]¶ Calculate the euclidean distance between two points
- Parameters
- Return type
- Returns
The euclidean distance between the two points.
Warning
This uses
zip()
. If one coordinate is of a higher dimensionality than the other, it will be silently truncated to match.
-
fmt_table
(rows, headers, group_by=None)[source]¶ Format a collection as a textual table.
- Parameters
>>> print(fmt_table([("Foo", "Wun"), ("Bar", "Too")], ... ("Things", "Numbers"))) Things Numbers ------ ------- Foo Wun Bar Too >>> print(fmt_table({"Foo": "Wun", "Bar": "Too"}, ... ("Things", "Numbers"))) Things Numbers ------ ------- Bar Too Foo Wun
Warning
This uses
zip()
to combine things. The number of columns displayed will be defined by the row with the fewest columns.- Return type