diff --git a/src/x11.cc b/src/x11.cc index 30798c3a..1be28c74 100644 --- a/src/x11.cc +++ b/src/x11.cc @@ -1429,39 +1429,47 @@ std::vector x11_atom_window_list(Display *display, Window window, return std::vector{}; } -std::vector query_x11_windows(Display *display) { +std::vector query_x11_windows(Display *display, bool eager) { Window root = DefaultRootWindow(display); - Atom clients_atom = ATOM(_NET_CLIENT_LIST_STACKING); - std::vector result = - x11_atom_window_list(display, root, clients_atom); - if (result.empty()) { return result; } + std::vector result; - clients_atom = ATOM(_NET_CLIENT_LIST); - result = x11_atom_window_list(display, root, clients_atom); - if (result.empty()) { return result; } + Atom clients_atom = XInternAtom(display, "_NET_CLIENT_LIST_STACKING", True); + if (clients_atom != 0) { + result = x11_atom_window_list(display, root, clients_atom); + if (!result.empty()) { return result; } + } + + clients_atom = XInternAtom(display, "_NET_CLIENT_LIST", True); + if (clients_atom != 0) { + result = x11_atom_window_list(display, root, clients_atom); + if (!result.empty()) { return result; } + } // slowest method - std::vector queue = {DefaultVRootWindow(display)}; + if (eager) { + std::vector queue = {DefaultVRootWindow(display)}; - Window _ignored, *children; - std::uint32_t count; + Window _ignored, *children; + std::uint32_t count; - const auto has_wm_hints = [&](Window window) { - auto hints = XGetWMHints(display, window); - bool result = hints != NULL; - if (result) XFree(hints); - return result; - }; + const auto has_wm_hints = [&](Window window) { + auto hints = XGetWMHints(display, window); + bool result = hints != NULL; + if (result) XFree(hints); + return result; + }; - while (!queue.empty()) { - Window current = queue.back(); - queue.pop_back(); - if (XQueryTree(display, current, &_ignored, &_ignored, &children, &count)) { - for (size_t i = 0; i < count; i++) queue.push_back(children[i]); - if (has_wm_hints(current)) result.push_back(current); - if (count > 0) XFree(children); + while (!queue.empty()) { + Window current = queue.back(); + queue.pop_back(); + if (XQueryTree(display, current, &_ignored, &_ignored, &children, + &count)) { + for (size_t i = 0; i < count; i++) queue.push_back(children[i]); + if (has_wm_hints(current)) result.push_back(current); + if (count > 0) XFree(children); + } } } @@ -1486,13 +1494,13 @@ Window query_x11_window_at_pos(Display *display, int x, int y) { std::vector query_x11_windows_at_pos( Display *display, int x, int y, - std::function predicate) { + std::function predicate, bool eager) { std::vector result; Window root = DefaultVRootWindow(display); XWindowAttributes attr; - for (Window current : query_x11_windows(display)) { + for (Window current : query_x11_windows(display, eager)) { int pos_x, pos_y; Window _ignore; // Doesn't account for decorations. There's no sane way to do that. diff --git a/src/x11.h b/src/x11.h index 15c562f1..7f983ae5 100644 --- a/src/x11.h +++ b/src/x11.h @@ -132,12 +132,13 @@ std::vector x11_atom_window_list(Display *display, Window window, /// /// If neither of the atoms are provided, this function tries traversing the /// window graph in order to collect windows. In this case, map state of windows -/// is ignored. This also produces a lot of noise for some WM/DEs due to -/// inserted window decorations. +/// is ignored. /// -/// @param display which display to query for windows @return a (likely) ordered -/// list of windows -std::vector query_x11_windows(Display *display); +/// @param display which display to query for windows +/// @param eager fallback to very slow tree traversal to ensure a list of +/// windows is returned even if window list atoms aren't defined +/// @return a (likely) ordered list of windows +std::vector query_x11_windows(Display *display, bool eager = false); /// @brief Finds the last ascendant of a window (trunk) before root. /// @@ -171,7 +172,8 @@ Window query_x11_window_at_pos(Display *display, int x, int y); std::vector query_x11_windows_at_pos( Display *display, int x, int y, std::function predicate = - [](XWindowAttributes &a) { return true; }); + [](XWindowAttributes &a) { return true; }, + bool eager = false); #ifdef BUILD_XDBE void xdbe_swap_buffers(void);