Search code examples
cx11xorgxcb

How can I get all events on the root window with XCB?


I'm writing an X client using XCB and I want to listen for all events on the root window. I wrote this code:

#include <stdio.h>
#include <stdlib.h>

#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>

int main(void) {
    xcb_connection_t *connection = xcb_connect(NULL, NULL);
    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
    xcb_generic_event_t *event;

    const uint32_t values[] = {
        XCB_EVENT_MASK_BUTTON_PRESS
    };

    xcb_change_window_attributes(connection, screen->root, XCB_CW_EVENT_MASK, values);
    xcb_aux_sync(connection);
    xcb_flush(connection);

    while ((event = xcb_wait_for_event(connection))) {
        switch (event->response_type & ~0x80) {
            case XCB_EXPOSE: {
                puts("expose");
                break;
            }
            case XCB_BUTTON_PRESS: {
                puts("mouse clicked");
                break;
            }
        }
        free(event);
    }

    xcb_disconnect(connection);

    return 0;
}

But it doesn't work if I try to get button press events on DISPLAY=:0. How can I do this? If I try to check the returned value of xcb_poll_for_event, it returns NULL because another window manager is running - do I need to somehow get access to the running window manager?


Solution

  • According to the Xlib documentation, the button press mask is one of three event masks that can only be registered by a single client at a time on a particular window.

    It may be the case, however, that the window manager has not grabbed the mouse button inputs on the root window (though, you cannot be sure this will always be the case). If the window manager has not grabbed the mouse buttons, your client should be able to grab the buttons with xcb_grab_button, allowing your client to receive the button events instead. If owner_events (a parameter of xcb_grab_button) is set to 1, button events will still be reported on the root window, which would allow both your client and the window manager to receive the button events.

    Obviously, the 'big if' here is whether the window manager will be grabbing the button events on the root window. There is no way to be certain that your client will always be able to receive these button events, not unless your client is running without a window manager.