XCB - 未在所有窗口上接收动作通知事件

Ing*_*ürk 5 c x11 google-chrome xcb

我正在尝试通知任何指针运动.因为我不想作为窗口管理器运行,所以我需要XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION在启动时和创建通知事件时设置所有窗口.

这似乎一般工作正常,我在所有窗口上收到动作通知事件.但是,不知何故,谷歌Chrome窗口不是这样.我之后通过显式查询它来检查事件掩码,并且它已正确设置.我也没有在传播掩模中看到任何异常.

什么可能导致谷歌浏览器不报告动作通知事件?AFAIK,X协议不允许除了Chrome肯定没有的活动指针抓取.

这是我在所有现有窗口上注册的方式.我打电话register_events给根窗口,每当我收到一个创建通知事件时:

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);
}
Run Code Online (Sandbox Code Playgroud)

Jay*_*nek 5

Chrome窗口似乎由嵌套的子窗口树组成.你似乎需要走在窗户的树上并监控它们.此代码会在整个Chrome窗口中捕获指针运动事件:

#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++);
  }
}
Run Code Online (Sandbox Code Playgroud)

(这只是作为概念的证明,并不是很好.)


Ing*_*ürk 2

虽然 @Jay Kominek 的答案很有帮助且有效,但我现在开始意识到使用 Xinput 扩展提供了更好的方法,因为它不会干扰任何应用程序。

简单地选择整个树会导致各种问题,例如,悬停在 Chrome 中不再起作用。