XCB - Do not receive event notifications in all windows

I am trying to get notification of any pointer movement. Since I do not want to start as a window manager, I need to set XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION for all windows that I execute both at startup and when I receive a creation notification event.

In general, this works fine, and I receive notifications of movement events in all windows. However, this is not the case for Google Chrome windows. I checked the event mask, after which I explicitly requested it and installed it correctly. I also do not see anything unusual in the spread mask.

What can cause Google Chrome to not report event notifications? AFAIK, the X protocol does not allow this, except for active invaders, which Chrome certainly does not have.

This is how I register myself in all existing windows. I call register_events in the root window and whenever I get a creation notification event:

 static void register_events(xcb_window_t window) { xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(connection, window, XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_LEAVE_WINDOW }); xcb_generic_error_t *error = xcb_request_check(connection, cookie); if (error != NULL) { xcb_disconnect(connection); errx(EXIT_FAILURE, "could not subscribe to events on a window, bailing out"); } } static void register_existing_windows(void) { xcb_query_tree_reply_t *reply; if ((reply = xcb_query_tree_reply(connection, xcb_query_tree(connection, root), 0)) == NULL) { return; } int len = xcb_query_tree_children_length(reply); xcb_window_t *children = xcb_query_tree_children(reply); for (int i = 0; i < len; i++) { register_events(children[i]); } xcb_flush(connection); free(reply); } 
+5
source share
2 answers

Although @Jay Kominek's answer was useful and valid, I realized that using the Xinput extension provides a much better approach, as it will not interfere with applications at all.

Simple selection throughout the tree causes all kinds of problems, for example, freezing no longer works in Chrome.

+2
source

Chrome windows are made up of a pretty tree of nested child windows. It seems you will need to walk through the window tree and control them all. This code captures cursor move events in all Chrome windows:

 #include <stdio.h> #include <stdlib.h> #include <xcb/xcb.h> #include <X11/Xlib.h> static void register_events(xcb_connection_t *conn, xcb_window_t window) { xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn, window, XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_POINTER_MOTION }); xcb_generic_error_t *error = xcb_request_check(conn, cookie); if (error != NULL) { xcb_disconnect(conn); exit(-1); } } static void register_existing_windows(xcb_connection_t *conn, xcb_window_t root) { int i, len; xcb_window_t *children; xcb_query_tree_reply_t *reply; if ((reply = xcb_query_tree_reply(conn, xcb_query_tree(conn, root), 0)) == NULL) { return; } len = xcb_query_tree_children_length(reply); children = xcb_query_tree_children(reply); for (i = 0; i < len; i++) { register_events(conn, children[i]); register_existing_windows(conn, children[i]); } xcb_flush(conn); } void main(void) { int i=0; /* Open the connection to the X server */ xcb_connection_t *conn = xcb_connect (NULL, NULL); /* Get the first screen */ xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (conn)).data; register_existing_windows(conn, screen->root); while(1) { xcb_generic_event_t *evt; evt = xcb_wait_for_event(conn); printf("%i\n", i++); } } 

(This is just intended as proof of concept, and not very nice.)

+5
source

All Articles