comparison libervia/frontends/tools/display_servers.py @ 4203:4af030d4d3d8

frontends (tools): module to handle display servers: rel 433
author Goffi <goffi@goffi.org>
date Tue, 16 Jan 2024 10:41:58 +0100
parents
children
comparison
equal deleted inserted replaced
4202:b26339343076 4203:4af030d4d3d8
1 #!/usr/bin/env python3
2
3 # Libervia tools for display servers
4 # Copyright (C) 2009-2024 Jérôme Poisson (goffi@goffi.org)
5
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Affero General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Affero General Public License for more details.
15
16 # You should have received a copy of the GNU Affero General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19
20 try:
21 from Xlib import X, display
22 from Xlib.xobject.drawable import Window
23 except ImportError:
24 pass
25 import os
26
27 X11 = "X11"
28 WAYLAND = "Wayland"
29
30
31 def x11_list_windows() -> list[dict[str, object]]:
32 """Lists all X11 windows with their metadata.
33
34 @param disp: The X11 display connection.
35 @return: A list of dictionaries with window metadata. Each dictionary contains the
36 metadata returned by [x11_get_window_metadata].
37 """
38 disp = display.Display()
39 window_list = []
40 root = disp.screen().root
41 window_ids = root.get_full_property(
42 disp.intern_atom("_NET_CLIENT_LIST"), X.AnyPropertyType
43 ).value
44
45 for window_id in window_ids:
46 window = disp.create_resource_object("window", window_id)
47 window_metadata = x11_get_window_metadata(window)
48 window_list.append(window_metadata)
49
50 return window_list
51
52
53 def x11_get_window_metadata(window: Window) -> dict[str, object]:
54 """Extracts metadata from a given X11 window.
55
56 @param window: The X11 window object.
57 @return: A dictionary with the window's metadata, including:
58
59 ``id`` (int)
60 window id
61 ``type`` (str)
62 "application" or "virtual desktop"
63 ``title`` (str)
64 combined class name and window name, truncated if long
65 ``window_name`` (str|none)
66 original window name
67 ``class`` (tuple[str, str]|none)
68 window class
69 ``geometry`` (dict)
70 dictionary with keys ``x``, ``y``, ``width``, ``height``
71 """
72 window_id = window.id
73 window_name = window.get_wm_name()
74 window_class = window.get_wm_class()
75 geometry = window.get_geometry()
76
77 # Q&D virtual desktop detection
78 virtual_desktop_classes = ["plasmashell", "gnome-shell", "xfdesktop", "mate-panel"]
79 window_type = (
80 "virtual desktop"
81 if window_class and any(vc in window_class[1] for vc in virtual_desktop_classes)
82 else "application"
83 )
84
85 class_name = window_class[1] if window_class else "Unknown"
86 title = f"{class_name}: {window_name or ''}"
87 if len(title) > 50:
88 title = f"{title[:47]}…"
89
90 return {
91 "id": window_id,
92 "type": window_type,
93 "title": title,
94 "window_name": window_name,
95 "class": window_class,
96 "geometry": {
97 "x": geometry.x,
98 "y": geometry.y,
99 "width": geometry.width,
100 "height": geometry.height,
101 },
102 }
103
104
105 def detect() -> str | None:
106 """Detects the type of window manager or display server in use.
107
108 @return: A string indicating the type of window manager/display server ("X11",
109 "Wayland", or None).
110 """
111 if "WAYLAND_DISPLAY" in os.environ:
112 return WAYLAND
113 elif "DISPLAY" in os.environ:
114 return X11
115 else:
116 return None