使用 XCB 检测窗口焦点变化 [英] Detect window focus changes with XCB

查看:49
本文介绍了使用 XCB 检测窗口焦点变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 XCB 编写一个程序,该程序需要在窗口获得或失去焦点时进行检测.到目前为止,我有这个,但它只是挂在 xcb_wait_for_event 调用上,从未进入循环.我在这里缺少什么来获取根事件?或者我只是完全错误地解决了这个问题,还有比听根听更好的方法吗?

I'm writing a program with XCB that needs to detect whenever a window gains or loses focus. So far I have this but it just hangs on the xcb_wait_for_event call, never entering the loop. What am I missing here to grab root events? Or am I just going about this totally wrong and there's a better way than listening to the root?

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

int main (int argc, char **argv)
{
    xcb_connection_t* conn = xcb_connect(NULL, NULL);
    if (xcb_connection_has_error(conn)) {
        printf("Cannot open daemon connection.");
        return 0;
    }

    xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;

    uint32_t values[] = { XCB_EVENT_MASK_FOCUS_CHANGE };
    xcb_change_window_attributes(
        conn,
        screen->root,
        XCB_CW_EVENT_MASK,
        values);

    xcb_generic_event_t *ev;
    while ((ev = xcb_wait_for_event(conn))) {
        printf("IN LOOP\n");
        switch (ev->response_type & 0x7F) {
        case XCB_FOCUS_IN:
        case XCB_FOCUS_OUT:
            printf("IN CASE\n");
            break;
        default:
            printf("IN DEFAULT\n");
            break;
        }
        free(ev);
    }

    return 0;
}

推荐答案

焦点事件仅在您选择这些事件的窗口接收或失去焦点时才会发送,请参阅 https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html:

The focus events are only sent when the window that you selected these events on receives or loses the focus, see https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html:

专注聚焦

[...]

这些事件在输入焦点更改时生成,并报告给在窗口上选择 FocusChange 的客户端.

These events are generated when the input focus changes and are reported to clients selecting FocusChange on the window.

要使用此功能,您必须在所有窗口上选择此事件掩码,还要注意新窗口的创建.

To use this, you would have to select this event mask on all windows and also watch for the creation of new windows.

我建议采用不同的方法:观察根窗口上的 PropertyChangeNotify 事件,以查看 _NET_ACTIVE_WINDOW 属性何时发生变化.根据 EWMH 的说法,WM 应更新此属性.

I would suggest a different approach: Watch for PropertyChangeNotify events on the root window to see when the _NET_ACTIVE_WINDOW property changes. This property should be kept up to date by the WM, according to EWMH.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xcb/xcb.h>

static xcb_atom_t intern_atom(xcb_connection_t *conn, const char *atom)
{
    xcb_atom_t result = XCB_NONE;
    xcb_intern_atom_reply_t *r = xcb_intern_atom_reply(conn,
            xcb_intern_atom(conn, 0, strlen(atom), atom), NULL);
    if (r)
        result = r->atom;
    free(r);
    return result;
}

int main (int argc, char **argv)
{
    xcb_connection_t* conn = xcb_connect(NULL, NULL);
    if (xcb_connection_has_error(conn)) {
        printf("Cannot open daemon connection.");
        return 0;
    }

    xcb_atom_t active_window = intern_atom(conn, "_NET_ACTIVE_WINDOW");
    xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;

    uint32_t values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
    xcb_change_window_attributes(
        conn,
        screen->root,
        XCB_CW_EVENT_MASK,
        values);

    xcb_flush(conn);

    xcb_generic_event_t *ev;
    while ((ev = xcb_wait_for_event(conn))) {
        printf("IN LOOP\n");
        switch (ev->response_type & 0x7F) {
        case XCB_PROPERTY_NOTIFY: {
            xcb_property_notify_event_t *e = (void *) ev;
            if (e->atom == active_window)
                puts("active window changed");
            break;
        }
        default:
            printf("IN DEFAULT\n");
            break;
        }
        free(ev);
    }

    return 0;
}

这篇关于使用 XCB 检测窗口焦点变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆