示例#1
0
def workspace_send_window(winman: WindowManager, win: Wnck.Window,
                          state: Dict[str, Any], motion: Union[MotionDirection,
                                                               int]) -> None:
    """Move the active window to another workspace.

    (Integer values for ``motion`` may cause wrap-around behaviour depending
    on the value of :ref:`MovementsWrap <MovementsWrap>`.)

    :param state: Used to access the :ref:`MovementsWrap <MovementsWrap>`
        configuration key.
    :param motion: The direction to move the window on the workspace grid or
        the distance to move it by numerical ordering. Accepts
        :class:`Wnck.MotionDirection` or :any:`int`.
    :param win: The window to operate on.
    """
    # Have to specify types in the description pending a fix for
    # https://github.com/agronholm/sphinx-autodoc-typehints/issues/124

    target = winman.get_workspace(win,
                                  motion,
                                  wrap_around=state['config'].getboolean(
                                      'general', 'MovementsWrap'))

    if not target:
        # `target` will be None if `win` is pinned or on no workspaces or if
        # there is no workspace matching `motion`.
        return

    win.move_to_workspace(target)
示例#2
0
def is_visible(window: Wnck.Window,
               workspace: Wnck.Workspace = None,
               monitor: Gdk.Monitor = None) -> bool:
    workspace = workspace if workspace else Wnck.Screen.get_default(
    ).get_active_workspace()
    return (is_buffer(window) and not window.is_minimized()
            and window.is_in_viewport(workspace)
            and window.is_visible_on_workspace(workspace)
            and (not monitor or intersect(window, monitor)))
示例#3
0
def move_to_position(
    winman: WindowManager,
    win: Wnck.Window,
    state: Dict[str, Any],
    gravity: Gravity,
) -> None:
    """Move the active window to a position on the screen, preserving its
    dimensions.

    :param win: The window to operate on.
    """
    monitor_rect = state['monitor_geom']
    win_rect = Rectangle(*win.get_geometry())

    # Build a target rectangle
    # TODO: Think about ways to refactor scaling for better maintainability
    target = Rectangle(x=gravity.value[0] * monitor_rect.width,
                       y=gravity.value[1] * monitor_rect.height,
                       width=win_rect.width,
                       height=win_rect.height).from_gravity(
                           gravity).from_relative(monitor_rect)

    # Push it out from under any panels
    logging.debug("Clipping rectangle %r\n\tto usable region %r", target,
                  winman.usable_region)
    confined_target = winman.usable_region.move_to_usable_region(target)

    # Actually reposition the window
    # (and be doubly-sure we're not going to resize it by accident)
    logging.debug("Calling reposition() with dimensions %r", confined_target)
    winman.reposition(win,
                      confined_target,
                      keep_maximize=True,
                      geometry_mask=Wnck.WindowMoveResizeMask.X
                      | Wnck.WindowMoveResizeMask.Y)
示例#4
0
文件: wm.py 项目: Gazer/quicktile
    def get_monitor(self, win: Wnck.Window) -> Tuple[int, Rectangle]:
        """Given a window, retrieve the ID and geometry of the monitor it's on.

        :param win: The window to find the containing monitor for.
        :returns: ``(monitor_id, geometry)``

        .. todo:: Look for a way to get the monitor ID without having to
           instantiate a :class:`Gdk.Window`.

           Doing so would also remove the need to set ``self.gdk_display`` as
           this is the only user of it.
        """
        if not isinstance(win, Gdk.Window):
            win = GdkX11.X11Window.foreign_new_for_display(
                self.gdk_display, win.get_xid())

        # TODO: How do I retrieve the root window from a given one?
        # (Gdk.Display.get_default_screen().get_root_window()... now why did
        # I want to know?)
        monitor_id = self.gdk_screen.get_monitor_at_window(win)
        monitor_geom = Rectangle.from_gdk(
            self.gdk_screen.get_monitor_geometry(monitor_id))

        # TODO: Unit test this
        monitor_geom *= self.gdk_screen.get_monitor_scale_factor(monitor_id)

        logging.debug(" Window is on monitor %s, which has geometry %s",
                      monitor_id, Rectangle.from_gdk(monitor_geom))
        return monitor_id, monitor_geom
示例#5
0
def cycle_monitors_all(winman: WindowManager,
                       win: Wnck.Window,
                       state: Dict[str, Any],
                       step: int = 1,
                       force_wrap: bool = False) -> None:
    """Cycle all windows between monitors.

    (Apply :func:`cycle_monitors` to all windows.)

    Attempts to preserve each window's position but will ensure that it doesn't
    get placed outside the available space on the target monitor.

    :param win: The window to operate on.
    :param step: Passed to :func:`cycle_monitors`
    :param force_wrap: Passed to :func:`cycle_monitors`
    """
    # Have to specify types in the description pending a fix for
    # https://github.com/agronholm/sphinx-autodoc-typehints/issues/124

    n_monitors = winman.gdk_screen.get_n_monitors()
    curr_workspace = win.get_workspace()

    if not curr_workspace:
        logging.debug("get_workspace() returned None")
        return

    for window in winman.get_relevant_windows(curr_workspace):
        cycle_monitors(winman, window, state, step, force_wrap, n_monitors)
示例#6
0
def toggle_decorated(
        winman: WindowManager,
        win: Wnck.Window,
        state: Dict[str, Any]  # pylint: disable=unused-argument
) -> None:
    """Toggle window decoration state on the active window.

    :param win: The window to operate on.
    :param state: Unused
    """
    # Have to specify types in the description pending a fix for
    # https://github.com/agronholm/sphinx-autodoc-typehints/issues/124

    # TODO: Switch to setting this via python-xlib
    display = winman.gdk_screen.get_display()
    win = GdkX11.X11Window.foreign_new_for_display(display, win.get_xid())
    win.set_decorations(
        Gdk.WMDecoration(0) if win.get_decorations()[1] else Gdk.WMDecoration.
        ALL)
示例#7
0
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
示例#8
0
    def get_window_meta(window: Wnck.Window, state: Dict[str, Any],
                        winman: WindowManager) -> bool:
        """Gather information about ``window`` to pass to the command

        :param window: The window to inspect.
        :param state: The metadata dict to :meth:`dict.update` with gathered
            values.
        :returns: A boolean indicating success or failure.

        .. todo:: Is the MPlayer safety hack in :meth:`get_window_meta` still
            necessary with the refactored window-handling code?
        .. todo:: Can the :func:`logging.debug` call in :meth:`get_window_meta`
            be reworked to call :meth:`Wnck.Window.get_name` lazily?
        """
        # Bail out early on None or things like the desktop window
        if not winman.is_relevant(window):
            return False

        win_rect = Rectangle(*window.get_geometry())
        logging.debug(
            "Operating on window %r with title \"%s\" "
            "and geometry %r", window, window.get_name(), win_rect)

        monitor_id, monitor_geom = winman.get_monitor(window)

        # MPlayer safety hack
        if not winman.usable_region:
            logging.debug(
                "Received a worthless value for largest "
                "rectangular subset of desktop (%r). Doing "
                "nothing.", winman.usable_region)
            return False

        state.update({
            "monitor_id": monitor_id,
            "monitor_geom": monitor_geom,
        })
        return True
示例#9
0
文件: wm.py 项目: Gazer/quicktile
    def get_workspace(
        self,
        window: Wnck.Window = None,
        direction: Union[Wnck.MotionDirection, int] = None,
        wrap_around: bool = True,
    ) -> Optional[Wnck.Workspace]:
        """Get a workspace (virtual desktop) relative to the one containing
        the given or active window.

        :param window: The point of reference. :any:`None` for the
            active workspace.
        :param direction: The direction in which to look, relative to the point
            of reference. Accepts the following types:

            - :any:`Wnck.MotionDirection`: Absolute direction (will not cycle
              around when it reaches the edge)
            - :any:`int`: Relative position in the list of workspaces (eg.
              ``1`` or ``-2``).
            - :any:`None`: The workspace containing ``window``
        :param wrap_around: Whether relative indexes should wrap around.
        :returns: The workspace object or :any:`None` if no match was found.
        """
        if window:
            cur = window.get_workspace()
        else:
            cur = self.screen.get_active_workspace()

        if not cur:
            return None  # It's either pinned or on no workspaces

        if isinstance(direction, Wnck.MotionDirection):
            nxt = cur.get_neighbor(direction)
        elif isinstance(direction, int):
            # TODO: Deduplicate with the wrapping code in commands.py
            n_spaces = self.screen.get_workspace_count()

            nxt = self.screen.get_workspace(
                clamp_idx(cur.get_number() + direction, n_spaces, wrap_around))

        elif direction is None:
            nxt = cur
        else:
            nxt = None
            logging.warning("Unrecognized direction: %r", direction)

        return nxt
示例#10
0
def resize(window: Wnck.Window,
           rectangle: Gdk.Rectangle = None,
           l=0,
           t=0,
           w=0,
           h=0):
    """
	:param l: distance from left edge
	:param t: distance from top edge
	"""

    if not rectangle:
        rectangle = monitor_of(window.get_xid()).get_workarea()

    new_x = int(rectangle.width * l) + rectangle.x
    new_y = int(rectangle.height * t) + rectangle.y
    new_width = int(rectangle.width * w)
    new_height = int(rectangle.height * h)

    set_geometry(window, x=new_x, y=new_y, w=new_width, h=new_height)
def get_window_attributes(window: Wnck.Window):
    window_dir = dir(window)
    attributes = []
    if "get_application" in window_dir and "get_name" in dir(
            window.get_application()):
        attributes.append(("application", window.get_application().get_name()))
    if "get_name" in window_dir:
        attributes.append(("name", window.get_name()))
    if "get_class_group_name" in window_dir:
        attributes.append(("class_group", window.get_class_group_name()))
    if "get_class_instance_name" in window_dir:
        attributes.append(("class_instance", window.get_class_instance_name()))
    if "get_icon_name" in window_dir:
        attributes.append(("icon", window.get_icon_name()))
    return dict(attributes)
示例#12
0
def activateWindow(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    Window.get(xid).activate(time())
示例#13
0
def closeWindow(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    Window.get(xid).close(time())
示例#14
0
def getWindowGroup(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    return Window.get(xid).get_class_group_name()
示例#15
0
def getWindowIcon(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    image = Window.get(xid).get_icon()
    buf = image.save_to_bufferv("png", [], [])[1]
    return b64encode(buf).decode(), "image/png;base64"
示例#16
0
def getWindowName(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    Window.get(xid).get_name()
示例#17
0
    def wnck_to_x(self, window: Wnck.Window) -> GdkX11.X11Window:

        xid = window.get_xid()
        x_window = GdkX11.X11Window.foreign_new_for_display(self.display, xid)
        return x_window
示例#18
0
def decoration_delta(window: Wnck.Window):
    with Trap():
        wx, wy, ww, wh = window.get_geometry()
        cx, cy, cw, ch = window.get_client_window_geometry()
    return cx - wx, cy - wy, cw - ww, ch - wh
示例#19
0
	def position_of(self, window: Wnck.Window):
		return window.get_geometry().xp if self is HORIZONTAL else window.get_geometry().yp
示例#20
0
	def get_active(self, window: Wnck.Window = None) -> Monitor:
		if not window:
			window = get_active_managed_window()
		return self.of(window.get_workspace(), monitor_of(window.get_xid())) if window else self.get_primary()
示例#21
0
	def contains(self, window: Wnck.Window):
		rect = self.visible_area
		xp, yp, widthp, heightp = window.get_geometry()
		return rect[0] <= xp < (rect[0] + rect[2]) and rect[1] <= yp < (rect[1] + rect[3])
示例#22
0
def is_buffer(window: Wnck.Window) -> bool:
    return window.get_pid() != os.getpid() and not window.is_skip_tasklist()
示例#23
0
def create_icon_image(window: Wnck.Window, size):
	icon = Gtk.Image()
	icon.set_from_pixbuf(window.get_mini_icon() if size < 14 else window.get_icon())
	icon.get_style_context().add_class('application-icon')
	return icon
示例#24
0
    def add_window(self, window: Wnck.Window):

        combobox = self.get("windows-combobox")
        name = window.get_name()
        combobox.append_text(name)
        self.windows[name] = window
示例#25
0
def minimizeWindow(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    Window.get(xid).minimize()
示例#26
0
def isWindowMinimized(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    return Window.get(xid).is_minimized()
示例#27
0
def gdk_window_for(window: Wnck.Window = None,
                   xid: int = None) -> GdkX11.X11Window:
    return window_for(window.get_xid())
示例#28
0
def getWindowNeedsAttention(xid=None):
    ensureArguments(xid)
    xid = int(xid)
    return Window.get(xid).needs_attention()
示例#29
0
文件: wm.py 项目: Gazer/quicktile
    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)
示例#30
0
def cycle_dimensions(
    winman: WindowManager, win: Wnck.Window, state: Dict[str, Any],
    *dimensions: Optional[Tuple[float, float, float, float]]
) -> Optional[Rectangle]:
    """Cycle the active window through a list of positions and shapes.

    Takes one step each time this function is called.

    Keeps track of its position by storing the index in an X11 property on
    ``win`` named ``_QUICKTILE_CYCLE_POS``.

    :param dimensions: A list of tuples representing window geometries as
        floating-point values between 0 and 1, inclusive.
    :param win: The window to operate on.
    :returns: The new window dimensions.

    .. todo:: Refactor :func:`cycle_dimensions` to be less of a big pile.
    .. todo:: Consider replacing the ``dimensions`` argument to
        :func:`cycle_dimensions` with a custom type.
    """
    monitor_rect = state['monitor_geom']
    win_rect_rel = Rectangle(*win.get_geometry()).to_relative(monitor_rect)

    logging.debug("Selected preset sequence:\n\t%r", dimensions)

    # Resolve proportional (eg. 0.5) and preserved (None) coordinates
    dims = [
        resolve_fractional_geom(i or win_rect_rel, monitor_rect)
        for i in dimensions
    ]
    if not dims:
        return None

    logging.debug(
        "Selected preset sequence resolves to these monitor-relative"
        " pixel dimensions:\n\t%r", dims)

    try:
        cmd_idx, pos = winman.get_property(win, '_QUICKTILE_CYCLE_POS',
                                           Xatom.INTEGER)
        logging.debug("Got saved cycle position: %r, %r", cmd_idx, pos)
    except (ValueError, TypeError):  # TODO: Is TypeError still possible?
        logging.debug("Restarting cycle position sequence")
        cmd_idx, pos = None, -1

    if cmd_idx == state.get('cmd_idx', 0):
        pos = (pos + 1) % len(dims)
    else:
        pos = 0

    winman.set_property(win,
                        '_QUICKTILE_CYCLE_POS',
                        [int(state.get('cmd_idx', 0)), pos],
                        prop_type=Xatom.INTEGER,
                        format_size=32)

    result = None  # type: Optional[Rectangle]
    result = Rectangle(*dims[pos]).from_relative(monitor_rect)

    logging.debug("Target preset is %s relative to monitor %s", result,
                  monitor_rect)

    # If we're overlapping a panel, fall back to a monitor-specific
    # analogue to _NET_WORKAREA to prevent overlapping any panels and
    # risking the WM potentially meddling with the result of resposition()
    test_result = winman.usable_region.clip_to_usable_region(result)
    if test_result != result:
        result = test_result
        logging.debug(
            "Result exceeds usable (non-rectangular) region of "
            "desktop. (overlapped a non-fullwidth panel?) Reducing "
            "to within largest usable rectangle: %s", test_result)

    logging.debug(
        "Calling reposition() with default gravity and dimensions "
        "%r", result)
    winman.reposition(win, result)
    return result