使用 XCB 检测 window 焦点变化
Detect window focus changes with XCB
我正在用 XCB 编写一个程序,需要在 window 获得或失去焦点时进行检测。到目前为止我有这个但它只是挂在 xcb_wait_for_event
调用上,从未进入循环。我在这里缺少什么来获取根事件?或者我只是在做这件事完全错了,有比听根更好的方法吗?
#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;
}
仅当您 select 编辑这些事件的 window 收到或失去焦点时才会发送焦点事件,请参阅 https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html:
FocusIn
FocusOut
[...]
These events are generated when the input focus changes and are reported to clients selecting FocusChange on the window.
要使用它,您必须 select 在所有 windows 上使用此事件掩码,并注意创建新的 windows。
我会建议一种不同的方法:观察根 window 上的 PropertyChangeNotify 事件以查看 _NET_ACTIVE_WINDOW
属性 何时更改。根据 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 编写一个程序,需要在 window 获得或失去焦点时进行检测。到目前为止我有这个但它只是挂在 xcb_wait_for_event
调用上,从未进入循环。我在这里缺少什么来获取根事件?或者我只是在做这件事完全错了,有比听根更好的方法吗?
#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;
}
仅当您 select 编辑这些事件的 window 收到或失去焦点时才会发送焦点事件,请参阅 https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html:
FocusIn FocusOut
[...]
These events are generated when the input focus changes and are reported to clients selecting FocusChange on the window.
要使用它,您必须 select 在所有 windows 上使用此事件掩码,并注意创建新的 windows。
我会建议一种不同的方法:观察根 window 上的 PropertyChangeNotify 事件以查看 _NET_ACTIVE_WINDOW
属性 何时更改。根据 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;
}