| 1 |  |  | """Layout calculation code""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | __author__ = "Stephan Sokolow (deitarion/SSokolow)" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | __license__ = "GNU GPL 2.0 or later" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | import math | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from heapq import heappop, heappush | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | # Allow MyPy to work without depending on the `typing` package | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | # (And silence complaints from only using the imported types in comments) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | MYPY = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | if MYPY: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |     # pylint: disable=unused-import | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |     from typing import (Any, Dict, Iterable, Iterator, List, Optional,  # NOQA | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |                         Sequence, Sized, Tuple, Union) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     # pylint: disable=import-error, no-name-in-module | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     from gtk.gdk import Rectangle  # NOQA | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     from .util import GeomTuple, PercentRect  # NOQA | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     Geom = Union[Rectangle, GeomTuple]  # pylint: disable=invalid-name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  | del MYPY | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  | def check_tolerance(distance, monitor_geom, tolerance=0.1): | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |     """Check whether a distance is within tolerance, adjusted for window size. | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |     @param distance: An integer value representing a distance in pixels. | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |     @param monitor_geom: An (x, y, w, h) tuple representing the monitor | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |         geometry in pixels. | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |     @param tolerance: A value between 0.0 and 1.0, inclusive, which represents | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |         a percentage of the monitor size. | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |     """ | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |     # Take the euclidean distance of the monitor rectangle and convert | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |     # `distance` into a percentage of it, then test against `tolerance`. | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |     return float(distance) / math.hypot(*tuple(monitor_geom)[2:4]) < tolerance | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  | def closest_geom_match(needle, haystack): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |     # type: (Geom, Sequence[Geom]) -> Tuple[int, int] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     """Find the geometry in C{haystack} that most closely matches C{needle}. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     @return: A tuple of the euclidean distance and index in C{haystack} for the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |              best match. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     # Calculate euclidean distances between the window's current geometry | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     # and all presets and store them in a min heap. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     euclid_distance = []  # type: List[Tuple[int, int]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     for haystack_pos, haystack_val in enumerate(haystack): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         distance = sum([(needle_i - haystack_i) ** 2 for (needle_i, haystack_i) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |                         in zip(tuple(needle), tuple(haystack_val))]) ** 0.5 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         heappush(euclid_distance, (distance, haystack_pos)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |     # to the next configuration. Otherwise, use the first configuration. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     closest_distance, closest_idx = heappop(euclid_distance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     return closest_distance, closest_idx | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  | def resolve_fractional_geom(geom_tuple, monitor_geom, win_geom=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |     # type: (Optional[Geom], Geom, Optional[Geom]) -> Geom | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     """Resolve proportional (eg. 0.5) and preserved (None) coordinates. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     @param geom_tuple: An (x, y, w, h) tuple with monitor-relative values in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |                        the range from 0.0 to 1.0, inclusive. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |                        If C{None}, then the value of C{win_geom} will be used. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |     @param monitor_geom: An (x, y, w, h) tuple defining the bounding box of the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |                        monitor (or other desired region) within the desktop. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |     @param win_geom: An (x, y, w, h) tuple defining the current shape of the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |                        window, in absolute desktop pixel coordinates. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |     monitor_geom = tuple(monitor_geom) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |     if geom_tuple is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         return win_geom | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |     else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         # Multiply x and w by monitor.w, y and h by monitor.h | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         return tuple(int(i * j) for i, j in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |                      zip(geom_tuple, monitor_geom[2:4] + monitor_geom[2:4])) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  | class GravityLayout(object):  # pylint: disable=too-few-public-methods | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |     """Helper for translating top-left relative dimensions to other corners. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     Used to generate L{commands.cycle_dimensions} presets. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |     Expects to operate on decimal percentage values. (0 <= x <= 1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |     #: Possible window alignments relative to the monitor/desktop. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |     #: @todo 1.0.0: Normalize these to X11 or CSS terminology for 1.0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |     #:     (API-breaking change) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     GRAVITIES = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |         'top-left': (0.0, 0.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |         'top': (0.5, 0.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         'top-right': (1.0, 0.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         'left': (0.0, 0.5), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         'middle': (0.5, 0.5), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         'right': (1.0, 0.5), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |         'bottom-left': (0.0, 1.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |         'bottom': (0.5, 1.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         'bottom-right': (1.0, 1.0), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |     }  # type: Dict[str, Tuple[float, float]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |     def __init__(self, margin_x=0, margin_y=0):  # type: (int, int) -> None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         @param margin_x: Horizontal margin to apply when calculating window | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |             positions, as decimal percentage of screen width. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |         @param margin_y: Vertical margin to apply when calculating window | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |             positions, as decimal percentage of screen height. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         self.margin_x = margin_x | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |         self.margin_y = margin_y | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |     # pylint: disable=too-many-arguments | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     def __call__(self, | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |                  width,               # type: float | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |                  height,              # type: float | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |                  gravity='top-left',  # type: str | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |                  x=None,              # type: Optional[float] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |                  y=None               # type: Optional[float] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |                  ):  # type: (...) -> Tuple[float, float, float, float] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |         """Return an C{(x, y, w, h)} tuple relative to C{gravity}. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |         This function takes and returns percentages, represented as decimals | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |         in the range 0 <= x <= 1, which can be multiplied by width and height | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         values in actual units to produce actual window geometry. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         It can be used in two ways: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |           1. If called B{without} C{x} and C{y} values, it will compute a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |           geometry tuple which will align a window C{w} wide and C{h} tall | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |           according to C{geometry}. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |           2. If called B{with} C{x} and C{y} values, it will translate a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |           geometry tuple which is relative to the top-left corner so that it is | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |           instead relative to another corner. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |         @param width: Desired width | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |         @param height: Desired height | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |         @param gravity: Desired window alignment from L{GRAVITIES} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |         @param x: Desired horizontal position if not the same as C{gravity} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         @param y: Desired vertical position if not the same as C{gravity} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |         @returns: C{(x, y, w, h)} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |         @note: All parameters except C{gravity} are decimal values in the range | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |         C{0 <= x <= 1}. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |         x = x or self.GRAVITIES[gravity][0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         y = y or self.GRAVITIES[gravity][1] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |         offset_x = width * self.GRAVITIES[gravity][0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |         offset_y = height * self.GRAVITIES[gravity][1] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         return (round(x - offset_x + self.margin_x, 3), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |                 round(y - offset_y + self.margin_y, 3), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |                 round(width - (self.margin_x * 2), 3), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |                 round(height - (self.margin_y * 2), 3)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  | def make_winsplit_positions(columns): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |     # type: (int) -> Dict[str, List[PercentRect]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |     """Generate the classic WinSplit Revolution tiling presets | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |     @todo: Figure out how best to put this in the config file. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |     # TODO: Plumb GravityLayout.__init__'s arguments into the config file | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |     gvlay = GravityLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |     col_width = 1.0 / columns | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |     cycle_steps = tuple(round(col_width * x, 3) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |                         for x in range(1, columns)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |     middle_steps = (1.0,) + cycle_steps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |     edge_steps = (0.5,) + cycle_steps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |     positions = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |         'middle': [gvlay(width, 1, 'middle') for width in middle_steps], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |     for grav in ('top', 'bottom'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |         positions[grav] = [gvlay(width, 0.5, grav) for width in middle_steps] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |     for grav in ('left', 'right'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |         positions[grav] = [gvlay(width, 1, grav) for width in edge_steps] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |     for grav in ('top-left', 'top-right', 'bottom-left', 'bottom-right'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |         positions[grav] = [gvlay(width, 0.5, grav) for width in edge_steps] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 184 |  |  |     return positions | 
            
                                                        
            
                                    
            
            
                | 185 |  |  |  | 
            
                        
This check looks for invalid names for a range of different identifiers.
You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.
If your project includes a Pylint configuration file, the settings contained in that file take precedence.
To find out more about Pylint, please refer to their site.