Mercurial > minori
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 } |