]> git.sur5r.net Git - i3/i3/commitdiff
Handle FocusIn events generated by clients and update decoration accordingly (Thanks...
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 20 Mar 2011 15:26:36 +0000 (16:26 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 20 Mar 2011 15:26:36 +0000 (16:26 +0100)
include/handlers.h
include/x.h
include/xcb.h
src/handlers.c
src/x.c

index 1c8aa283291fba33a03b9c84763b36efdc782108..e36d6605356e50a51429a72102c740e4edf82460 100644 (file)
@@ -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
index 6b0bae0ec5640d21921b9a4df1aebb56e244c043..15d37420adfb7b1cdcde8822ad201f3432d310d7 100644 (file)
@@ -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().
index 673b5b392a88872450e6bee5cdee00241821cef9..13fafb0b9c72777ce34dd8e941b304c6c07af995 100644 (file)
@@ -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 */ \
index 111d7c24b8cca5b6d3adadb31e7a8c087d8684dd..619b36bb3af6c74f73c5ef0f5eec54fa00e13e7b 100644 (file)
@@ -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 22912b9df49d69ca72aba5179490a090b3da37f7..0c8a7ead1dcd8ca528c98045576134b96132650f 100644 (file)
--- 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);
 }
 
 /*