]> git.sur5r.net Git - i3/i3/commitdiff
Bugfix: Correctly set the _NET_CLIENT_LIST_STACKING hint (fixes chromium tabbar)
authorMichael Stapelberg <michael@stapelberg.de>
Wed, 3 Aug 2011 18:07:03 +0000 (20:07 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Wed, 3 Aug 2011 18:07:03 +0000 (20:07 +0200)
Fixes #287

include/atoms.xmacro
include/ewmh.h
src/ewmh.c
src/main.c
src/x.c

index 5d2ffb1b00024fd084d14f52b899d7406cdea9c3..9b5a132cbdc77f075da126d0a8d2846fbbb0656f 100644 (file)
@@ -11,6 +11,7 @@ xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
 xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
 xmacro(_NET_WM_DESKTOP)
 xmacro(_NET_WM_STRUT_PARTIAL)
+xmacro(_NET_CLIENT_LIST_STACKING)
 xmacro(_NET_CURRENT_DESKTOP)
 xmacro(_NET_ACTIVE_WINDOW)
 xmacro(_NET_WORKAREA)
index 2f2bf431dacdc98961fd35e2c273dc970431518c..54c83f400fa97755e83c0d84fe4a00dbb27eb434 100644 (file)
@@ -39,4 +39,16 @@ void ewmh_update_active_window(xcb_window_t window);
  */
 void ewmh_update_workarea();
 
+/**
+ * Updates the _NET_CLIENT_LIST_STACKING hint. Necessary to move tabs in
+ * Chromium correctly.
+ *
+ * EWMH: These arrays contain all X Windows managed by the Window Manager.
+ * _NET_CLIENT_LIST has initial mapping order, starting with the oldest window.
+ * _NET_CLIENT_LIST_STACKING has bottom-to-top stacking order. These properties
+ * SHOULD be set and updated by the Window Manager.
+ *
+ */
+void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows);
+
 #endif
index 7b2cc3e458fe03d754acae891d0ca48a61a72a20..1736523d7a176a6efe8fd709bec576e5086170dc 100644 (file)
@@ -110,3 +110,20 @@ void ewmh_update_workarea() {
     free(workarea);
     xcb_flush(conn);
 }
+
+/*
+ * Updates the _NET_CLIENT_LIST_STACKING hint.
+ *
+ */
+void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows) {
+    DLOG("Updating _NET_CLIENT_LIST_STACKING\n");
+    xcb_change_property(
+        conn,
+        XCB_PROP_MODE_REPLACE,
+        root,
+        A__NET_CLIENT_LIST_STACKING,
+        A_WINDOW,
+        32,
+        num_windows,
+        stack);
+}
index d7a5aedb99240036808c652564423e4ca5a23eeb..5306774462f3a302ae07e6fd9b10d27ecfd96131 100644 (file)
@@ -397,7 +397,7 @@ int main(int argc, char *argv[]) {
 #include "atoms.xmacro"
 #undef xmacro
     };
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 15, supported_atoms);
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 16, supported_atoms);
     /* Set up the window manager’s name */
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, A_WINDOW, 32, 1, &root);
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
diff --git a/src/x.c b/src/x.c
index e93e90e7687836b280e7be48e15695b6f725d563..f231d7fbb4a3e31ac50a76fd509434031278e436 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -7,6 +7,11 @@
 /* Stores the X11 window ID of the currently focused window */
 xcb_window_t focused_id = XCB_NONE;
 
+/* The bottom-to-top window stack of all windows which are managed by i3.
+ * Used for x_get_window_stack(). */
+static xcb_window_t *btt_stack;
+static int btt_stack_num;
+
 /*
  * Describes the X11 state we may modify (map state, position, window stack).
  * There is one entry per container. The state represents the current situation
@@ -21,6 +26,9 @@ typedef struct con_state {
     bool unmap_now;
     bool child_mapped;
 
+    /** The con for which this state is. */
+    Con *con;
+
     /* For reparenting, we have a flag (need_reparent) and the X ID of the old
      * frame this window was in. The latter is necessary because we need to
      * ignore UnmapNotify events (by changing the window event mask). */
@@ -112,6 +120,7 @@ void x_reinit(Con *con) {
     DLOG("resetting state %p to initial\n", state);
     state->initial = true;
     state->child_mapped = false;
+    state->con = con;
     memset(&(state->window_rect), 0, sizeof(Rect));
 }
 
@@ -148,6 +157,9 @@ void x_move_win(Con *src, Con *dest) {
         return;
     }
 
+    state_dest->con = state_src->con;
+    state_src->con = NULL;
+
     Rect zero = { 0, 0, 0, 0 };
     if (memcmp(&(state_dest->window_rect), &(zero), sizeof(Rect)) == 0) {
         memcpy(&(state_dest->window_rect), &(state_src->window_rect), sizeof(Rect));
@@ -753,14 +765,31 @@ void x_push_changes(Con *con) {
     }
     //DLOG("Done, EnterNotify disabled\n");
     bool order_changed = false;
+
+    /* count first, necessary to (re)allocate memory for the bottom-to-top
+     * stack afterwards */
+    int cnt = 0;
+    CIRCLEQ_FOREACH_REVERSE(state, &state_head, state)
+        if (state->con && state->con->window)
+            cnt++;
+
+    if (cnt != btt_stack_num) {
+        btt_stack = srealloc(btt_stack, sizeof(xcb_window_t) * cnt);
+        btt_stack_num = cnt;
+    }
+
+    xcb_window_t *walk = btt_stack;
+
     /* X11 correctly represents the stack if we push it from bottom to top */
     CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
+        if (state->con && state->con->window)
+            memcpy(walk++, &(state->con->window->id), sizeof(xcb_window_t));
+
         //DLOG("stack: 0x%08x\n", state->id);
         con_state *prev = CIRCLEQ_PREV(state, state);
         con_state *old_prev = CIRCLEQ_PREV(state, old_state);
-        if (prev != old_prev)
+        if ((prev != old_prev || state->initial) && prev != CIRCLEQ_END(&state_head)) {
             order_changed = true;
-        if ((state->initial || order_changed) && prev != CIRCLEQ_END(&state_head)) {
             DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
             uint32_t mask = 0;
             mask |= XCB_CONFIG_WINDOW_SIBLING;
@@ -771,6 +800,12 @@ void x_push_changes(Con *con) {
         }
         state->initial = false;
     }
+
+    /* If we re-stacked something (or a new window appeared), we need to update
+     * the _NET_CLIENT_LIST_STACKING hint */
+    if (order_changed)
+        ewmh_update_client_list_stacking(btt_stack, btt_stack_num);
+
     //DLOG("Re-enabling EnterNotify\n");
     values[0] = FRAME_EVENT_MASK;
     CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {