问题
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;
}
回答1:
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:
FocusIn FocusOut
[...]
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.
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;
}
来源:https://stackoverflow.com/questions/57896007/detect-window-focus-changes-with-xcb