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