使用XCB检测窗口焦点更改

使用XCB检测窗口焦点更改,c,x11,xlib,xcb,C,X11,Xlib,Xcb,我正在用XCB编写一个程序,需要在窗口获得或失去焦点时进行检测。到目前为止,我已经有了这个,但它只是挂起了xcb\u wait\u for\u事件调用,从未进入循环。我在这里遗漏了什么来获取根事件?还是我完全错了,还有比听根的更好的方法 #include <stdio.h> #include <stdlib.h> #include <xcb/xcb.h> int main (int argc, char **argv) { xcb_connectio

我正在用XCB编写一个程序,需要在窗口获得或失去焦点时进行检测。到目前为止,我已经有了这个,但它只是挂起了
xcb\u wait\u for\u事件
调用,从未进入循环。我在这里遗漏了什么来获取根事件?还是我完全错了,还有比听根的更好的方法

#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;
}
#包括
#包括
#包括
int main(int argc,字符**argv)
{
xcb_connection\u t*conn=xcb_connect(NULL,NULL);
如果(xcb_连接_有错误(连接)){
printf(“无法打开守护程序连接”);
返回0;
}
xcb_screen_t*screen=xcb_setup_root_迭代器(xcb_get_setup(conn))。数据;
uint32_t值[]={XCB_事件_掩码_焦点_改变};
xcb\u更改\u窗口\u属性(
康涅狄格州,
屏幕->根目录,
XCB_CW_事件_掩码,
价值观);
xcb_通用事件_t*ev;
而((ev=xcb_等待_事件(conn))){
printf(“循环中\n”);
开关(ev->响应类型和0x7F){
案例XCB_FOCUS_IN:
案例XCB\U焦点\U OUT:
printf(“在这种情况下”);
打破
违约:
printf(“默认情况下”);
打破
}
免费(ev);
}
返回0;
}

仅当您选择这些事件的窗口接收或失去焦点时,才会发送焦点事件,请参阅:

聚焦蛋白 聚焦输出

[……]

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

要使用此选项,您必须在所有窗口上选择此事件掩码,并观察新窗口的创建


我建议使用另一种方法:观察根窗口上的PropertyChangeNotify事件,以查看
\u NET\u ACTIVE\u窗口
属性何时更改。根据EWMH,WM应保持此属性的最新状态

#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_原子内部原子(xcb_连接连接,常量字符*原子)
{
xcb_原子结果=xcb_无;
xcb_intern_atom_reply_t*r=xcb_intern_atom_reply(conn,
xcb_intern_atom(conn,0,strlen(atom),atom),NULL);
if(r)
结果=r->atom;
自由(r);
返回结果;
}
int main(int argc,字符**argv)
{
xcb_connection\u t*conn=xcb_connect(NULL,NULL);
如果(xcb_连接_有错误(连接)){
printf(“无法打开守护程序连接”);
返回0;
}
xcb_atom_t active_window=intern_atom(conn,“_NET_active_window”);
xcb_screen_t*screen=xcb_setup_root_迭代器(xcb_get_setup(conn))。数据;
uint32_t值[]={XCB_事件_掩码_属性_更改};
xcb\u更改\u窗口\u属性(
康涅狄格州,
屏幕->根目录,
XCB_CW_事件_掩码,
价值观);
xcb_冲洗(连接);
xcb_通用事件_t*ev;
而((ev=xcb_等待_事件(conn))){
printf(“循环中\n”);
开关(ev->响应类型和0x7F){
案例XCB_财产_通知:{
xcb_属性_通知_事件_t*e=(无效*)ev;
如果(e->atom==活动窗口)
puts(“活动窗口已更改”);
打破
}
违约:
printf(“默认情况下”);
打破
}
免费(ev);
}
返回0;
}

谢谢,我会在可能的时候试一试。同时,您是否介意解释一下您的
intern\u atom
函数中发生了什么?作为一名X11/xcb新手,很难解析那里发生的事情。原子基本上是任意字符串,就像这里的
\u NET\u ACTIVE\u WINDOW
。但是,字符串没有固定的长度。因此,您向X11服务器请求
\u NET\u ACTIVE\u窗口
atom,它会返回一个数字。数字具有固定长度,现在您可以始终使用此数字来引用此字符串。其他请求使用此atom的X11客户端返回相同的号码。原子例如用于窗口属性:属性的类型是原子(例如
\u NET\u ACTIVE\u window
\u WM\u CLASS
),属性的类型是原子(例如
window
UTF8\u STRING)
等。