Self-Contained Utility Code (util.py)

Helper functions and classes

class Edge[source]

Constants used by StrutPartial.as_rects() to communicate information UsableRegion 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, or x2 and y, height or y2 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 adjusting x and y

Parameters
  • x=None (int) –

  • y=None (int) –

  • width=None (int) –

  • height=None (int) –

  • x2=None (int) –

  • y2=None (int) –

Raises

ValueError – An invalid set of arguments was provided at construction. (eg. width and x2)

>>> 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() and from_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.

__bool__()[source]

A rectangle is truthy if it has a nonzero area

Return type

bool

__contains__(other)[source]

A Rectangle is in another if one is entirely within the other.

If other is not a Rectangle, this will always return False.

If you need to check for overlap, check whether intersect() is truthy.

This assumes top-left gravity.

Return type

bool

__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.

Parameters

factor (Union[int, float]) –

Return type

Rectangle

property area

Convenience helper for calculating area of the rectangle

Return type

int

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:

  1. Choose the rectangle with the largest area area of overlap. (self.intersect(candidate).area)

  2. 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.)

Parameters

candidates (List[Rectangle]) – Rectangles to consider for closeness.

Return type

Rectangle

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 and y as not referring to top-left corner and return a copy of self 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.

Parameters

other_rect (Rectangle) – The reference frame to which this rectangle’s x and y coordinates should be interpreted as relative to.

Return type

Rectangle

Returns

An absolute-coordinates version of this rectangle.

intersect(other)[source]

The intersection of two rectangles, assuming top-left gravity.

Raises

TypeErrorother was not a Rectangle

>>> rect1 = Rectangle(0, 0, 40, 40)
>>> Rectangle(20, 20, 50, 60).intersect(rect1)
Rectangle(x=20, y=20, width=20, height=20)
Parameters

other (Rectangle) –

Return type

Rectangle

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 than other, 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)
Parameters

other (Rectangle) – The rectangle to move inside

Raises

TypeErrorother was not a Rectangle

Return type

Rectangle

moved_off_of(other)[source]

Return a copy of self that has been moved as little as possible such that it no longer overlaps other.

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().

Parameters

other (Rectangle) –

Return type

Rectangle

subtract(other)[source]

Return a copy of self which has been shrunk along one axis such that it no longer overlaps other.

The edge to cut away is determined by calling moved_off_of() and then intersect()-ing self 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.

Parameters

other (Rectangle) –

Return type

Rectangle

to_gdk()[source]

Helper to easily create a Gdk.Rectangle from a Rectangle.

This assumes top-left gravity.

to_gravity(gravity)[source]

Reverse the effect of from_gravity()

Less concisely, this will interpret self’s x and y 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_point()[source]

Return a copy of this Rectangle with zero width and height.

Return type

Rectangle

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.

Parameters

other_rect (Rectangle) – The reference frame to make this rectangle’s x and y coordinates relative to.

Return type

Rectangle

Returns

A relative-coordinates version of this rectangle.

union(other)[source]

Assuming top-left gravity, return the smallest rectangle that both self and other fit inside. (ie. the bounding box)

Raises

TypeErrorother was not a Rectangle

>>> Rectangle(0, 0, 1, 1).union(Rectangle(5, 5, 1, 1))
Rectangle(x=0, y=0, width=6, height=6)
Parameters

other (Rectangle) –

Return type

Rectangle

property x2

X coordinate of the bottom-right corner assuming top-left gravity

Return type

int

property xy

Convenience helper to retrieve an (x, y) tuple

Return type

Tuple[int, int]

property y2

Y coordinate of the bottom-right corner assuming top-left gravity

Return type

int

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 create StrutPartial 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.)

Parameters

desktop_rect (Rectangle) –

Return type

List[Tuple[Edge, Rectangle]]

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

bool

__repr__()[source]

Override repr to be more useful for debugging.

>>> print(repr(UsableRegion()))
Region(<Monitors=[], Struts=[]>)
Return type

str

_trim_strut(strut)[source]

Trim a strut rectangle to just the monitor it applies to

Parameters

strut (Tuple[Edge, Rectangle]) –

Return type

Rectangle

_update()[source]

Check input values and regenerate internal caches

This is internal code shared by set_monitors() and set_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 a StrutPartial.

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:

  1. Does not extend outside the monitor

  2. 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.

Parameters

rect (Rectangle) – A rectangle representing desired window geometry that should be shrunk to not overlap any panels or None if there was no overlap.

Return type

Optional[Rectangle]

find_monitor_for(rect)[source]

Find the full (including space reserved for panels) Rectangle for the monitor containing rect using Rectangle.closest_of().

Parameters

rect (Rectangle) – A rectangle (possibly of zero width and height), representing a point of reference for the monitor search.

Return type

Optional[Rectangle]

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.

Parameters

rect (Rectangle) –

Return type

Optional[Rectangle]

set_monitors(monitor_rects)[source]

Set the list of monitor rectangles from which to calculate usable regions

Parameters

monitor_rects (Iterable[Rectangle]) –

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.

__str__()[source]

Augment str output to clarify that a user should look outside QuickTile for the cause.

XInitError: Hello, I am your usual exception message
    (The cause of this error lies outside of QuickTile)
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.

Parameters
  • idx (int) – The value to adjust.

  • stop (int) – The value to ensure idx is below.

  • wrap (bool) – If True, wrap around rather than saturating.

Return type

int

Returns

The adjusted value.

euclidean_dist(vec1, vec2)[source]

Calculate the euclidean distance between two points

Parameters
  • vec1 (Iterable) – The first coordinate point.

  • vec2 (Iterable) – The second coordinate point.

Return type

float

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
  • rows (Union[Dict, Iterable[List]]) – A dict or iterable of lists representing a sequence of rows. If a dict is provided, it will be sorted() using Python’s default collation behaviour to ensure consistent output.

  • headers (Sequence[str]) – Header labels for the columns

  • group_by (Optional[int]) – Index of the column to group results by.

>>> 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

str

powerset(iterable)[source]

Return an iterator over the power set of the given iterable.

>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Parameters

iterable (Iterable[Any]) –

Return type

Iterator[Sequence[Any]]