def set_geometry(window: Wnck.Window, x=None, y=None, w=None, h=None, synchronous=False, raise_exceptions=True): if not w and not h: geometry = window.get_geometry() w = geometry.widthp h = geometry.heightp xo, yo, wo, ho = calculate_geometry_offset(window) x, y, w, h = x + xo, y + yo, w + wo, h + ho x, y, w, h = int(x), int(y), int(w), int(h) geometry_cache[window.get_xid()] = (x, y, w, h) adjustment_cache[window.get_xid()] = False window.set_geometry(Wnck.WindowGravity.STATIC, X_Y_W_H_GEOMETRY_MASK, x, y, w, h) if synchronous: synchronized = wait_configure_event(window.get_xid(), Gdk.EventType.CONFIGURE, Gdk.Display.get_default()) return synchronized return False
def reposition( self, # pylint: disable=too-many-arguments win: Wnck.Window, geom: Optional[Rectangle] = None, monitor: Rectangle = Rectangle(0, 0, 0, 0), keep_maximize: bool = False, geometry_mask: Wnck.WindowMoveResizeMask = ( Wnck.WindowMoveResizeMask.X | Wnck.WindowMoveResizeMask.Y | Wnck.WindowMoveResizeMask.WIDTH | Wnck.WindowMoveResizeMask.HEIGHT) ) -> None: """ Move and resize a window, decorations inclusive, according to the provided target window and monitor geometry rectangles. If no monitor rectangle is specified, the target position will be relative to the desktop as a whole. :param win: The window to reposition. :param geom: The new geometry for the window. Can be left unspecified if the intent is to move the window to another monitor without repositioning it. :param monitor: The frame relative to which ``geom`` should be interpreted. The whole desktop if unspecified. :param keep_maximize: Whether to re-maximize the window if it had to be un-maximized to ensure it would move. :param geometry_mask: A set of flags determining which aspects of the requested geometry should actually be applied to the window. (Allows the same geometry definition to easily be shared between operations like move and resize.) .. todo:: Look for a way to accomplish this with a cleaner method signature. :meth:`reposition` is getting a little hairy. .. todo:: Decide how to refactor :meth:`reposition` to allow for smarter handling of position clamping when cycling windows through a sequence of differently sized monitors. """ old_geom = Rectangle(*win.get_geometry()).to_relative( self.get_monitor(win)[1]) new_args = {} if geom: for attr in ('x', 'y', 'width', 'height'): if geometry_mask & getattr(Wnck.WindowMoveResizeMask, attr.upper()): new_args[attr] = getattr(geom, attr) # Apply changes and return to absolute desktop coordinates. new_geom = old_geom._replace(**new_args).from_relative(monitor) # Ensure the window is fully within the monitor # TODO: Make this remember the original position and re-derive from it # on each monitor-next call as long as the window hasn't changed # (Ideally, re-derive from the tiling preset if set) if bool(monitor) and not geom: clipped_geom = self.usable_region.clip_to_usable_region(new_geom) else: clipped_geom = new_geom if bool(clipped_geom): logging.debug(" Repositioning to %s)\n", clipped_geom) with persist_maximization(win, keep_maximize): # Always use STATIC because either WMs implement window gravity # incorrectly or it's not applicable to this problem win.set_geometry(Wnck.WindowGravity.STATIC, geometry_mask, *clipped_geom) else: logging.debug(" Geometry clipping failed: %r", clipped_geom)