1

What would be the proper way to get the active window (the one with input focus) with XCB?

reply = xcb_get_input_focus_reply(connection, xcb_get_input_focus(connection), nullptr);
std::cout << "WId: " << reply->focus;

This seems to be work sometimes and sometimes not.

I also saw someone mentioned querying _NET_ACTIVE_WINDOW root window property but I can't figure out how that is done and is it always supported with XCB?

Edit: The approach above with xcb_get_input_focus is only one part, after getting the reply->focus, you need to follow up the parent windows via xcb_query_tree.

Damir Porobic
  • 681
  • 1
  • 8
  • 21

2 Answers2

3

As far as I know, EWMH-compliant window managers are expected to set _NET_ACTIVE_WINDOW attribute of root window to the window ID of the currently active window.

In order to get it,

  1. Use xcb_intern_atom to get the atom value for _NET_ACTIVE_WINDOW
  2. Get the root window ID, e.g. using xcb_setup_roots_iterator(xcb_get_setup(connection)).data->root
  3. Use xcb_get_property, xcb_get_property_reply, and xcb_get_property_value to get the value of the attribute of the root window.

_NET_ACTIVE_WINDOW has type of CARDINAL, which, for XCB purposes, has size of 32 bits.

Or you could use libxcb-ewmh which wraps this task into xcb_ewmh_get_active_window function.

aitap
  • 325
  • 1
  • 9
  • Maybe you could provide an example for this solution? I was not able to implement it. As far as I understand the `xcb_intern_atom` can be used to check the status of the atom `_NET_ACTIVE_WINDOW` but on what window should it be used? – Damir Porobic Apr 27 '17 at 20:02
  • For the sake of completeness, `xcb_intern_atom` only returns you the `xcb_atom_t` value of a given named atom (you should pass it `"_NET_ACTIVE_WINDOW"` and `strlen("_NET_ACTIVE_WINDOW")`). Pass the root window, the resulting atom as the property to get and `XCB_ATOM_CARDINAL` as its type to `xcb_get_property` to get `xcb_get_property_cookie_t`. Pass the cookie to `xcb_get_property_reply` to get the `xcb_get_property_reply_t*`. The WID would be `*(uint32_t*)xcb_get_property_value(...)`; don't forget to free the reply. – aitap Apr 27 '17 at 22:04
  • For the vast majority of cases relying on EWMH is the correct way and what you want. However, the EWMH hint doesn't necessarily have to refer to the window which currently has the input focus (and quite often won't), so it's a question of what @dporobic actually wants to do. – Ingo Bürk May 12 '17 at 08:23
  • @IngoBürk I need the window that currently has input focus, to be more precise, I need the geometry of the window. The approach with `xcb_get_input_focus_reply` and following up the parent windows works fine for me. What does "active window" mean for EWMH if not input focus? Whats the difference between a window that is active and one that has input focus, I thought they should be the same? – Damir Porobic May 12 '17 at 14:35
  • 2
    @dporobic Input focus is a hard X11 property (managed by X11). The EWMH active window is something the window manager maintains. In particular, a window manager will usually not mark any override_redirect window as active even if they have input focus. A window manager could also have a more sophisticated model. The point of the EWMH spec here is to allow the window manager to tell applications what *it* considers the active window rather than X. In particular since any client can just acquire input focus without the window manager having the possibility to intervene. – Ingo Bürk May 13 '17 at 10:14
  • 1
    … and, needless to say, input focus is a property of any window, not necessarily a top-level window (which are the only windows window managers care about, really). Which is why you need to traverse the tree to find the actual top-level window. The EWMH property will always point to the top-level window (but requires an EWMH compliant window manager). – Ingo Bürk May 13 '17 at 10:15
  • By the way, the approach in the answer above is broken. I'll comment on it. – Ingo Bürk May 13 '17 at 10:16
  • Just as further information, there's also _NET_SUPPORTING_WM_CHECK which some window managers mark as active when there is no window they consider active. I posted a link to a bit of code within i3-input that showcases a lot of this. – Ingo Bürk May 13 '17 at 10:20
2

This solution works for me, it's more or less migration from some X11 code to XCB. Basically get the focus window and follow up the the path of the parent window until the window id is equal to parent or root id, this is then the top level window.

WId ImageGrabber::getActiveWindow()
{
    xcb_connection_t* connection = QX11Info::connection();
    xcb_get_input_focus_reply_t* focusReply;
    xcb_query_tree_cookie_t treeCookie;
    xcb_query_tree_reply_t* treeReply;

    focusReply = xcb_get_input_focus_reply(connection, xcb_get_input_focus(connection), nullptr);
    xcb_window_t window = focusReply->focus;
    while (1) {
        treeCookie = xcb_query_tree(connection, window);
        treeReply = xcb_query_tree_reply(connection, treeCookie, nullptr);
        if (!treeReply) {
            window = 0;
            break;
        }
        if (window == treeReply->root || treeReply->parent == treeReply->root) {
            break;
        } else {
            window = treeReply->parent;
        }
        free(treeReply);
    }
    free(treeReply);
    return window;
}
Damir Porobic
  • 681
  • 1
  • 8
  • 21
  • This code is buggy. You should grab the server for all of this as otherwise the input focus could change while you are going through the tree. See XGrabServer / xcb_grab_server. – Ingo Bürk May 13 '17 at 10:17
  • As a reference, one can look at [this](https://github.com/i3/i3/blob/next/i3-input/main.c#L320) where the server is grabbed around an input focus operation. – Ingo Bürk May 13 '17 at 10:18
  • Thanks for pointing this out, indeed a valid point. So basically I need to `xcb_grab_server(conn)` the server at the beginning and `xcb_ungrab_server(conn)` when I'm done and have found the parent? – Damir Porobic May 14 '17 at 11:13
  • Yes, basically. Since you want the geometry you might also wait with ungrabbing until you have the geometry. – Ingo Bürk May 14 '17 at 13:35