Skip to content

Commit

Permalink
Fix bad query_x11_windows early returns (#1864)
Browse files Browse the repository at this point in the history
* Fix bad early returns
* Prevent fallback tree traversal from propagation code

Signed-off-by: Tin Švagelj <tin.svagelj@live.com>
  • Loading branch information
Caellian authored Apr 26, 2024
1 parent 0821c25 commit 71c4e6e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 35 deletions.
66 changes: 37 additions & 29 deletions src/x11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1429,39 +1429,47 @@ std::vector<Window> x11_atom_window_list(Display *display, Window window,
return std::vector<Window>{};
}

std::vector<Window> query_x11_windows(Display *display) {
std::vector<Window> query_x11_windows(Display *display, bool eager) {
Window root = DefaultRootWindow(display);

Atom clients_atom = ATOM(_NET_CLIENT_LIST_STACKING);
std::vector<Window> result =
x11_atom_window_list(display, root, clients_atom);
if (result.empty()) { return result; }
std::vector<Window> 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 = ATOM(_NET_CLIENT_LIST);
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<Window> queue = {DefaultVRootWindow(display)};

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

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);
if (eager) {
std::vector<Window> queue = {DefaultVRootWindow(display)};

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

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

Expand All @@ -1486,13 +1494,13 @@ Window query_x11_window_at_pos(Display *display, int x, int y) {

std::vector<Window> query_x11_windows_at_pos(
Display *display, int x, int y,
std::function<bool(XWindowAttributes &)> predicate) {
std::function<bool(XWindowAttributes &)> predicate, bool eager) {
std::vector<Window> 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.
Expand Down
14 changes: 8 additions & 6 deletions src/x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,13 @@ std::vector<Window> 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<Window> 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<Window> query_x11_windows(Display *display, bool eager = false);

/// @brief Finds the last ascendant of a window (trunk) before root.
///
Expand Down Expand Up @@ -171,7 +172,8 @@ Window query_x11_window_at_pos(Display *display, int x, int y);
std::vector<Window> query_x11_windows_at_pos(
Display *display, int x, int y,
std::function<bool(XWindowAttributes &)> predicate =
[](XWindowAttributes &a) { return true; });
[](XWindowAttributes &a) { return true; },
bool eager = false);

#ifdef BUILD_XDBE
void xdbe_swap_buffers(void);
Expand Down

0 comments on commit 71c4e6e

Please sign in to comment.