Self-Contained Utility Code (util.py)¶
Helper functions and classes
- class Edge(*values)[source]¶
Constants used by
StrutPartial.as_rects()to communicate informationUsableRegionneeds 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(*values)[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(x: int | None = None, y: int | None = None, width: int | None = None, height: int | None = None, x2: int | None = None, y2: int | None = None)[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, orx2andy,heightory2as 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 adjustingxandy- Parameters:
- Raises:
ValueError – An invalid set of arguments was provided at construction. (eg.
widthandx2)
>>> 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
inanother if one is entirely within the other.If
otheris 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
factorThis 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.
>>> Rectangle(320, 240, 640, 480) * 2 Rectangle(x=640, y=480, width=1280, height=960) >>> Rectangle(320, 240, 640, 480) * 0.5 Rectangle(x=160, y=120, width=320, height=240)
- closest_of(candidates)[source]¶
Find and return the rectangle that
selfis 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.)
- classmethod from_gdk(gdk_rect)[source]¶
Factory function to convert from a
Gdk.RectangleThis assumes top-left gravity.
- from_gravity(gravity)[source]¶
Treat
xandyas not referring to top-left corner and return a copy ofselfwith them translated them so they do.Note
Almost every
Rectanglemethod 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_rectand 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
Rectangleof the same width and height that does not exceed the bounds of other.If
selfis 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
selfthat 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
selfwithout 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
selfwhich 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()-ingselfwith 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
selfwithout 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.Rectanglefrom aRectangle.This assumes top-left gravity.
- to_gravity(gravity)[source]¶
Reverse the effect of
from_gravity()Less concisely, this will interpret self’s
xandymembers 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
Rectanglemethod 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(left=0, right=0, top=0, bottom=0, left_start_y=0, left_end_y=9223372036854775807, right_start_y=0, right_end_y=9223372036854775807, top_start_x=0, top_end_x=9223372036854775807, bottom_start_x=0, bottom_end_x=9223372036854775807)[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 createStrutPartialinstances 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_rectNote 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) = 56pxto 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
StrutPartialinstances and can be used to clip or move window rectangles to fit within the usable space.- __bool__()[source]¶
A
UsableRegionis truthy if it has at least one monitor with nonzero area.- Return type:
- __repr__()[source]¶
Override
reprto 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
Rectangleor the internal list of struts contains an entry that is not aStrutPartial.
- Return type:
- 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)
Rectanglefor the monitor containingrectusingRectangle.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:
- Return type:
>>> 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 >>> print(fmt_table([ ... ("Foo", "Wun", "Real Words. Really. Honestly."), ... ("Bar", "Too", "Fake Word"), ... ("Baz", "Fwee", "Real Words. Really. Honestly.")], ... ("Things", "Numbers", "Is Real Word?"), ... group_by=2)) Things Numbers ------ ----------------------- Fake Word Bar Too Real Words. Really. Honestly. Foo Wun Baz Fwee
Warning
This uses
zip()to combine things. The number of columns displayed will be defined by the row with the fewest columns.


Install Dependencies