1

使用 XCB 获取活动窗口(具有输入焦点的窗口)的正确方法是什么?

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

这似乎有时有效,有时无效。

我还看到有人提到查询 _NET_ACTIVE_WINDOW 根窗口属性,但我不知道这是如何完成的,XCB 是否总是支持它?

编辑: 上面使用xcb_get_input_focus的方法只是其中的一部分,在得到reply->focus之后,你需要通过xcb_query_tree跟进父窗口。

4

2 回答 2

3

据我所知,符合 EWMH 的窗口管理器应该将_NET_ACTIVE_WINDOW根窗口的属性设置为当前活动窗口的窗口 ID。

为了得到它,

  1. 用于xcb_intern_atom获取原子值_NET_ACTIVE_WINDOW
  2. 获取根窗口 ID,例如使用xcb_setup_roots_iterator(xcb_get_setup(connection)).data->root
  3. 使用xcb_get_propertyxcb_get_property_replyxcb_get_property_value获取根窗口的属性值。

_NET_ACTIVE_WINDOW类型为CARDINAL,对于 XCB 而言,其大小为 32 位。

或者你可以使用libxcb-ewmh将这个任务包装成xcb_ewmh_get_active_window函数。

于 2017-04-26T13:19:13.393 回答
2

这个解决方案对我有用,它或多或少是从一些 X11 代码迁移到 XCB。基本上得到焦点窗口并跟随父窗口的路径,直到窗口id等于父或根id,这就是顶层窗口。

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;
}
于 2017-04-27T20:00:12.227 回答