From c130cefa93a048323586963b7ffce928d848fbb0 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 20 Mar 2011 16:26:36 +0100 Subject: [PATCH] Handle FocusIn events generated by clients and update decoration accordingly (Thanks mseed) --- include/handlers.h | 1 + include/x.h | 3 +++ include/xcb.h | 5 +++-- src/handlers.c | 35 +++++++++++++++++++++++++++++++++++ src/x.c | 15 ++++++++++++++- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/include/handlers.h b/include/handlers.h index 1c8aa283..e36d6605 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -215,4 +215,5 @@ int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window, xcb_atom_t name, xcb_get_property_reply_t *prop); +int handle_focus_in(void *data, xcb_connection_t *conn, xcb_focus_in_event_t *event); #endif diff --git a/include/x.h b/include/x.h index 6b0bae0e..15d37420 100644 --- a/include/x.h +++ b/include/x.h @@ -5,6 +5,9 @@ #ifndef _X_H #define _X_H +/** Stores the X11 window ID of the currently focused window */ +extern xcb_window_t focused_id; + /** * Initializes the X11 part for the given container. Called exactly once for * every container from con_new(). diff --git a/include/xcb.h b/include/xcb.h index 673b5b39..13fafb0b 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -3,7 +3,7 @@ * * i3 - an improved dynamic tiling window manager * - * (c) 2009 Michael Stapelberg and contributors + * © 2009-2011 Michael Stapelberg and contributors * * See file LICENSE for license information. * @@ -32,7 +32,8 @@ while rendering the layout) */ /** The XCB_CW_EVENT_MASK for the child (= real window) */ #define CHILD_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY) + XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ + XCB_EVENT_MASK_FOCUS_CHANGE) /** The XCB_CW_EVENT_MASK for its frame */ #define FRAME_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */ \ diff --git a/src/handlers.c b/src/handlers.c index 111d7c24..619b36bb 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -129,6 +129,10 @@ void handle_event(int type, xcb_generic_event_t *event) { handle_mapping_notify(NULL, conn, (xcb_mapping_notify_event_t*)event); break; + case XCB_FOCUS_IN: + handle_focus_in(NULL, conn, (xcb_focus_in_event_t*)event); + break; + case XCB_PROPERTY_NOTIFY: DLOG("Property notify\n"); xcb_property_notify_event_t *e = (xcb_property_notify_event_t*)event; @@ -1023,3 +1027,34 @@ int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state return 1; } + +/* + * Handles FocusIn events which are generated by clients (i3’s focus changes + * don’t generate FocusIn events due to a different EventMask) and updates the + * decorations accordingly. + * + */ +int handle_focus_in(void *data, xcb_connection_t *conn, xcb_focus_in_event_t *event) { + DLOG("focus change in, for window 0x%08x\n", event->event); + Con *con; + if ((con = con_by_window_id(event->event)) == NULL || con->window == NULL) + return 1; + DLOG("That is con %p / %s\n", con, con->name); + + if (event->detail == XCB_NOTIFY_DETAIL_POINTER) { + DLOG("notify detail is pointer, ignoring this event\n"); + return 1; + } + + if (focused_id == event->event) { + DLOG("focus matches the currently focused window, not doing anything\n"); + return 1; + } + + DLOG("focus is different, updating decorations\n"); + con_focus(con); + /* We update focused_id because we don’t need to set focus again */ + focused_id = event->event; + x_push_changes(croot); + return 1; +} diff --git a/src/x.c b/src/x.c index 22912b9d..0c8a7ead 100644 --- a/src/x.c +++ b/src/x.c @@ -5,7 +5,7 @@ #include "all.h" /* Stores the X11 window ID of the currently focused window */ -static xcb_window_t focused_id = XCB_NONE; +xcb_window_t focused_id = XCB_NONE; /* * Describes the X11 state we may modify (map state, position, window stack). @@ -693,7 +693,18 @@ void x_push_changes(Con *con) { focused_id = XCB_NONE; } else { DLOG("Updating focus (focused: %p / %s)\n", focused, focused->name); + /* We remove XCB_EVENT_MASK_FOCUS_CHANGE from the event mask to get + * no focus change events for our own focus changes. We only want + * these generated by the clients. */ + if (focused->window != NULL) { + values[0] = CHILD_EVENT_MASK & ~(XCB_EVENT_MASK_FOCUS_CHANGE); + xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values); + } xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, to_focus, XCB_CURRENT_TIME); + if (focused->window != NULL) { + values[0] = CHILD_EVENT_MASK; + xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values); + } if (focused->window != NULL && focused->window->needs_take_focus) { @@ -724,6 +735,8 @@ void x_push_changes(Con *con) { CIRCLEQ_FOREACH(state, &old_state_head, old_state) { DLOG("old stack: 0x%08x\n", state->id); } + + xcb_flush(conn); } /*