# HG changeset patch # User Goffi # Date 1705398118 -3600 # Node ID 4af030d4d3d83b441400ba86a8e417a98ca9fde5 # Parent b263393430767b6e9141e4d8809e18736f2fe130 frontends (tools): module to handle display servers: rel 433 diff -r b26339343076 -r 4af030d4d3d8 libervia/frontends/tools/display_servers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libervia/frontends/tools/display_servers.py Tue Jan 16 10:41:58 2024 +0100 @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +# Libervia tools for display servers +# Copyright (C) 2009-2024 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +try: + from Xlib import X, display + from Xlib.xobject.drawable import Window +except ImportError: + pass +import os + +X11 = "X11" +WAYLAND = "Wayland" + + +def x11_list_windows() -> list[dict[str, object]]: + """Lists all X11 windows with their metadata. + + @param disp: The X11 display connection. + @return: A list of dictionaries with window metadata. Each dictionary contains the + metadata returned by [x11_get_window_metadata]. + """ + disp = display.Display() + window_list = [] + root = disp.screen().root + window_ids = root.get_full_property( + disp.intern_atom("_NET_CLIENT_LIST"), X.AnyPropertyType + ).value + + for window_id in window_ids: + window = disp.create_resource_object("window", window_id) + window_metadata = x11_get_window_metadata(window) + window_list.append(window_metadata) + + return window_list + + +def x11_get_window_metadata(window: Window) -> dict[str, object]: + """Extracts metadata from a given X11 window. + + @param window: The X11 window object. + @return: A dictionary with the window's metadata, including: + + ``id`` (int) + window id + ``type`` (str) + "application" or "virtual desktop" + ``title`` (str) + combined class name and window name, truncated if long + ``window_name`` (str|none) + original window name + ``class`` (tuple[str, str]|none) + window class + ``geometry`` (dict) + dictionary with keys ``x``, ``y``, ``width``, ``height`` + """ + window_id = window.id + window_name = window.get_wm_name() + window_class = window.get_wm_class() + geometry = window.get_geometry() + + # Q&D virtual desktop detection + virtual_desktop_classes = ["plasmashell", "gnome-shell", "xfdesktop", "mate-panel"] + window_type = ( + "virtual desktop" + if window_class and any(vc in window_class[1] for vc in virtual_desktop_classes) + else "application" + ) + + class_name = window_class[1] if window_class else "Unknown" + title = f"{class_name}: {window_name or ''}" + if len(title) > 50: + title = f"{title[:47]}…" + + return { + "id": window_id, + "type": window_type, + "title": title, + "window_name": window_name, + "class": window_class, + "geometry": { + "x": geometry.x, + "y": geometry.y, + "width": geometry.width, + "height": geometry.height, + }, + } + + +def detect() -> str | None: + """Detects the type of window manager or display server in use. + + @return: A string indicating the type of window manager/display server ("X11", + "Wayland", or None). + """ + if "WAYLAND_DISPLAY" in os.environ: + return WAYLAND + elif "DISPLAY" in os.environ: + return X11 + else: + return None diff -r b26339343076 -r 4af030d4d3d8 pyproject.toml --- a/pyproject.toml Sun Jan 14 17:48:02 2024 +0100 +++ b/pyproject.toml Tue Jan 16 10:41:58 2024 +0100 @@ -49,6 +49,7 @@ # "python-potr < 1.1", "pyxdg < 0.30", "pyyaml < 7.0.0", + "python-xlib ~= 0.33", "prompt_toolkit ~= 3.0", "rich ~= 13.5", "sat_tmp @ hg+https://repos.goffi.org/sat_tmp#egg=sat_tmp",