comparison dep/animia/src/win/x11.cc @ 166:54c5d80a737e

dep/animia: add libutil method I changed the "linux" method to be "proc", because it isn't exactly Linux specific this commit also has some changes to the x11 stuff: instead of enumerating over only top-level windows, we iterate over ALL of them this is because many X11 apps actually use multiple windows for some reason, I still can't get it to work with VLC, but it picks up Firefox...
author paper@DavesDouble.local
date Sun, 19 Nov 2023 04:21:56 -0500
parents 80d6b28eb29f
children 31735c8592bc
comparison
equal deleted inserted replaced
165:8937fb7f2d66 166:54c5d80a737e
6 #include <X11/Xutil.h> 6 #include <X11/Xutil.h>
7 #include <X11/Xatom.h> // XA_* 7 #include <X11/Xatom.h> // XA_*
8 8
9 #include <cstdint> 9 #include <cstdint>
10 #include <string> 10 #include <string>
11 #include <memory>
12 #include <set> 11 #include <set>
13 12
14 /* The code for this is very fugly because X11 uses lots of generic type names 13 /* The code for this is very fugly because X11 uses lots of generic type names
15 (i.e., Window, Display), so I have to use :: when defining vars to distinguish 14 (i.e., Window, Display), so I have to use :: when defining vars to distinguish
16 between Animia's types and X11's types */ 15 between Animia's types and X11's types */
21 static bool GetWindowPropertyAsString(::Display* display, ::Window window, ::Atom atom, std::string& result, ::Atom reqtype = AnyPropertyType) { 20 static bool GetWindowPropertyAsString(::Display* display, ::Window window, ::Atom atom, std::string& result, ::Atom reqtype = AnyPropertyType) {
22 int format; 21 int format;
23 unsigned long leftover_bytes, num_of_items; 22 unsigned long leftover_bytes, num_of_items;
24 ::Atom type; 23 ::Atom type;
25 unsigned char* data; 24 unsigned char* data;
26 if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype, 25
27 &type, &format, &num_of_items, &leftover_bytes, &data)) 26 int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype,
27 &type, &format, &num_of_items, &leftover_bytes, &data);
28 if (status != Success || !(reqtype == AnyPropertyType || type == reqtype) || !num_of_items)
28 return false; 29 return false;
29 30
30 result = std::string((char*)data, num_of_items); 31 result = std::string((char*)data, num_of_items);
32
33 ::XFree(data);
31 34
32 return true; 35 return true;
33 } 36 }
34 37
35 /* this should return CARDINAL, a 32-bit integer */ 38 /* this should return CARDINAL, a 32-bit integer */
37 int format; 40 int format;
38 unsigned long leftover_bytes, num_of_items; 41 unsigned long leftover_bytes, num_of_items;
39 ::Atom atom = ::XInternAtom(display, "_NET_WM_PID", False), type; 42 ::Atom atom = ::XInternAtom(display, "_NET_WM_PID", False), type;
40 unsigned char* data; 43 unsigned char* data;
41 44
42 if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL, 45 int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL,
43 &type, &format, &num_of_items, &leftover_bytes, &data)) 46 &type, &format, &num_of_items, &leftover_bytes, &data);
47 if (status != Success || type != XA_CARDINAL || num_of_items < 1)
44 return false; 48 return false;
45 49
46 result = static_cast<pid_t>(*(uint32_t*)data); 50 result = static_cast<pid_t>(*(uint32_t*)data);
51
52 ::XFree(data);
47 53
48 return true; 54 return true;
49 } 55 }
50 56
51 static bool FetchName(::Display* display, ::Window window, std::string& result) { 57 static bool FetchName(::Display* display, ::Window window, std::string& result) {
52 /* TODO: Check if XInternAtom created None or not... */ 58 /* TODO: Check if XInternAtom created None or not... */
53 if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "_NET_WM_NAME", False), 59 if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "_NET_WM_NAME", False),
54 result, ::XInternAtom(display, "UTF8_STRING", False))) 60 result, ::XInternAtom(display, "UTF8_STRING", False)))
61 return true;
62
63 if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "WM_NAME", False),
64 result, XA_STRING))
55 return true; 65 return true;
56 66
57 /* Fallback to XGetWMName() */ 67 /* Fallback to XGetWMName() */
58 XTextProperty text; 68 XTextProperty text;
59 69
67 77
68 { 78 {
69 int count; 79 int count;
70 80
71 int status = ::XmbTextPropertyToTextList(display, &text, &list, &count); 81 int status = ::XmbTextPropertyToTextList(display, &text, &list, &count);
72 if (status < Success || !count || !*list) 82 if (status != Success || !count || !*list)
73 return false; 83 return false;
74 } 84 }
75 85
76 ::XFree(text.value); 86 ::XFree(text.value);
77 87
80 ::XFreeStringList(list); 90 ::XFreeStringList(list);
81 91
82 return true; 92 return true;
83 } 93 }
84 94
95 static bool WalkWindows(::Display* display, std::set<::Window>& children, const std::set<::Window>& windows) {
96 if (windows.empty())
97 return false;
98
99 for (const ::Window& window : windows) {
100 unsigned int num_children = 0;
101 ::Window* children_arr = nullptr;
102
103 ::Window root_return;
104 ::Window parent_return;
105
106 int status = ::XQueryTree(display, window, &root_return, &parent_return, &children_arr, &num_children);
107 if (status < Success)
108 continue;
109
110 if (num_children < 1) {
111 ::XFree(children_arr);
112 continue;
113 }
114
115 for (int i = 0; i < num_children; i++)
116 if (!children.count(children_arr[i]))
117 children.insert(children_arr[i]);
118
119 ::XFree(children_arr);
120
121 std::set<::Window> children_children;
122
123 if (!WalkWindows(display, children_children, children))
124 children.insert(children_children.begin(), children_children.end());
125 }
126
127 return true;
128 }
129
85 bool X11WinTools::EnumerateWindows(window_proc_t window_proc) { 130 bool X11WinTools::EnumerateWindows(window_proc_t window_proc) {
86 if (!window_proc) 131 if (!window_proc)
87 return false; 132 return false;
88 133
89 ::Display* display = ::XOpenDisplay(nullptr); 134 ::Display* display = ::XOpenDisplay(nullptr);
135 if (!display)
136 return false;
137
90 ::Window root = DefaultRootWindow(display); 138 ::Window root = DefaultRootWindow(display);
91 139
92 unsigned int num_windows = 0; 140 std::set<::Window> windows;
93 ::Window* windows = nullptr; 141 WalkWindows(display, windows, {root});
94 142
95 { 143 for (const auto& window : windows) {
96 ::Window root_return;
97 ::Window parent_return;
98
99 int status = ::XQueryTree(display, root, &root_return, &parent_return, &windows, &num_windows);
100 if (status < Success)
101 return false;
102 }
103
104 for (long k = 0; k < num_windows; k++) {
105 const ::Window window = windows[k];
106
107 Window win; 144 Window win;
108 win.id = window; 145 win.id = window;
109 { 146 {
110 ::XClassHint* hint = ::XAllocClassHint(); 147 ::XClassHint* hint = ::XAllocClassHint();
111 if (::XGetClassHint(display, window, hint)) { 148 if (::XGetClassHint(display, window, hint)) {
112 win.class_name = hint->res_class; 149 win.class_name = hint->res_class;
113 ::XFree(hint); 150 ::XFree(hint);
114 } 151 }
115 } 152 }
116 FetchName(display, windows[k], win.text); 153 FetchName(display, window, win.text);
117 154
118 Process proc; 155 Process proc;
119 GetWindowPID(display, window, proc.pid); 156 GetWindowPID(display, window, proc.pid);
120 157
121 if (!window_proc(proc, win)) 158 if (!window_proc(proc, win))
122 return false; 159 return false;
123 } 160 }
124 161
125 ::XFree(windows);
126
127 return true; 162 return true;
128 } 163 }
129 164
130 } 165 }