Mercurial > minori
diff 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 |
line wrap: on
line diff
--- a/dep/animia/src/win/x11.cc Sat Nov 18 01:12:02 2023 -0500 +++ b/dep/animia/src/win/x11.cc Sun Nov 19 04:21:56 2023 -0500 @@ -8,7 +8,6 @@ #include <cstdint> #include <string> -#include <memory> #include <set> /* The code for this is very fugly because X11 uses lots of generic type names @@ -23,12 +22,16 @@ unsigned long leftover_bytes, num_of_items; ::Atom type; unsigned char* data; - if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype, - &type, &format, &num_of_items, &leftover_bytes, &data)) + + int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype, + &type, &format, &num_of_items, &leftover_bytes, &data); + if (status != Success || !(reqtype == AnyPropertyType || type == reqtype) || !num_of_items) return false; result = std::string((char*)data, num_of_items); + ::XFree(data); + return true; } @@ -39,19 +42,26 @@ ::Atom atom = ::XInternAtom(display, "_NET_WM_PID", False), type; unsigned char* data; - if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL, - &type, &format, &num_of_items, &leftover_bytes, &data)) + int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL, + &type, &format, &num_of_items, &leftover_bytes, &data); + if (status != Success || type != XA_CARDINAL || num_of_items < 1) return false; result = static_cast<pid_t>(*(uint32_t*)data); + ::XFree(data); + return true; } static bool FetchName(::Display* display, ::Window window, std::string& result) { /* TODO: Check if XInternAtom created None or not... */ if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "_NET_WM_NAME", False), - result, ::XInternAtom(display, "UTF8_STRING", False))) + result, ::XInternAtom(display, "UTF8_STRING", False))) + return true; + + if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "WM_NAME", False), + result, XA_STRING)) return true; /* Fallback to XGetWMName() */ @@ -69,7 +79,7 @@ int count; int status = ::XmbTextPropertyToTextList(display, &text, &list, &count); - if (status < Success || !count || !*list) + if (status != Success || !count || !*list) return false; } @@ -82,28 +92,55 @@ return true; } +static bool WalkWindows(::Display* display, std::set<::Window>& children, const std::set<::Window>& windows) { + if (windows.empty()) + return false; + + for (const ::Window& window : windows) { + unsigned int num_children = 0; + ::Window* children_arr = nullptr; + + ::Window root_return; + ::Window parent_return; + + int status = ::XQueryTree(display, window, &root_return, &parent_return, &children_arr, &num_children); + if (status < Success) + continue; + + if (num_children < 1) { + ::XFree(children_arr); + continue; + } + + for (int i = 0; i < num_children; i++) + if (!children.count(children_arr[i])) + children.insert(children_arr[i]); + + ::XFree(children_arr); + + std::set<::Window> children_children; + + if (!WalkWindows(display, children_children, children)) + children.insert(children_children.begin(), children_children.end()); + } + + return true; +} + bool X11WinTools::EnumerateWindows(window_proc_t window_proc) { if (!window_proc) return false; ::Display* display = ::XOpenDisplay(nullptr); + if (!display) + return false; + ::Window root = DefaultRootWindow(display); - unsigned int num_windows = 0; - ::Window* windows = nullptr; - - { - ::Window root_return; - ::Window parent_return; + std::set<::Window> windows; + WalkWindows(display, windows, {root}); - int status = ::XQueryTree(display, root, &root_return, &parent_return, &windows, &num_windows); - if (status < Success) - return false; - } - - for (long k = 0; k < num_windows; k++) { - const ::Window window = windows[k]; - + for (const auto& window : windows) { Window win; win.id = window; { @@ -113,7 +150,7 @@ ::XFree(hint); } } - FetchName(display, windows[k], win.text); + FetchName(display, window, win.text); Process proc; GetWindowPID(display, window, proc.pid); @@ -122,8 +159,6 @@ return false; } - ::XFree(windows); - return true; }