]> git.sur5r.net Git - i3/i3/commitdiff
i3bar: Correctly handle removal of tray clients
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 15 Aug 2011 13:57:52 +0000 (15:57 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Tue, 23 Aug 2011 23:18:27 +0000 (01:18 +0200)
i3bar/include/common.h
i3bar/include/outputs.h
i3bar/include/trayclients.h [new file with mode: 0644]
i3bar/src/outputs.c
i3bar/src/xcb.c

index 644b777c738c3fd3a0014448970ddded34ed1c0e..9737d22ff68fc5a266280fa074b91162b757374d 100644 (file)
@@ -29,6 +29,7 @@ struct rect_t {
 #include "outputs.h"
 #include "util.h"
 #include "workspaces.h"
+#include "trayclients.h"
 #include "xcb.h"
 #include "ucs2_to_utf8.h"
 #include "config.h"
index 680261b116107608a15df15272103a2f66833d12..c6402a5b620b987569769862e2d5b02890bb9cba 100644 (file)
@@ -46,9 +46,8 @@ struct i3_output {
     xcb_pixmap_t   buffer;        /* An extra pixmap for double-buffering */
     xcb_gcontext_t bargc;         /* The graphical context of the bar */
 
-    int            traypx;        /* Amount of pixels reserved for tray icons */
-
     struct ws_head *workspaces;   /* The workspaces on this output */
+    struct tc_head *trayclients;  /* The tray clients on this output */
 
     SLIST_ENTRY(i3_output) slist; /* Pointer for the SLIST-Macro */
 };
diff --git a/i3bar/include/trayclients.h b/i3bar/include/trayclients.h
new file mode 100644 (file)
index 0000000..3218578
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * i3bar - an xcb-based status- and ws-bar for i3
+ *
+ * © 2010-2011 Axel Wagner and contributors
+ *
+ * See file LICNSE for license information
+ *
+ */
+#ifndef TRAYCLIENT_H_
+#define TRAYCLIENT_H_
+
+#include "common.h"
+
+typedef struct trayclient trayclient;
+
+TAILQ_HEAD(tc_head, trayclient);
+
+struct trayclient {
+    xcb_window_t       win;         /* The window ID of the tray client */
+
+    TAILQ_ENTRY(trayclient) tailq;  /* Pointer for the TAILQ-Macro */
+};
+
+#endif
index 39bad1924ef2430dce10d4abcc1d13c6587182c1..53544d178c312f77969734cd021808d2634404b8 100644 (file)
@@ -157,11 +157,13 @@ static int outputs_start_map_cb(void *params_) {
         new_output->ws = 0,
         memset(&new_output->rect, 0, sizeof(rect));
         new_output->bar = XCB_NONE;
-        new_output->traypx = 0;
 
         new_output->workspaces = malloc(sizeof(struct ws_head));
         TAILQ_INIT(new_output->workspaces);
 
+        new_output->trayclients = malloc(sizeof(struct tc_head));
+        TAILQ_INIT(new_output->trayclients);
+
         params->outputs_walk = new_output;
 
         return 1;
index 29b31aefe56e276463603c8b19b2c4570a56e72c..3da23a81e6809d892c5d26c71f0e8e0b3262b0b1 100644 (file)
@@ -408,16 +408,32 @@ void handle_client_message(xcb_client_message_event_t* event) {
                                 client,
                                 output->bar,
                                 output->rect.w - font_height - 2, /* TODO: why -2? */
-                                0);
+                                2);
+            /* We reconfigure the window to use a reasonable size. The systray
+             * specification explicitly says:
+             *   Tray icons may be assigned any size by the system tray, and
+             *   should do their best to cope with any size effectively
+             */
             uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
             uint32_t values[] = { font_height, font_height };
             xcb_configure_window(xcb_connection,
                                  client,
                                  mask,
                                  values);
+
+            /* Listen for PropertyNotify events to get the most recent value of
+             * the XEMBED_MAPPED atom, also listen for UnmapNotify events */
+            mask = XCB_CW_EVENT_MASK;
+            values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
+                    XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+            xcb_change_window_attributes(xcb_connection,
+                                         client,
+                                         mask,
+                                         values);
             xcb_map_window(xcb_connection, client);
-            /* XXX: We assume that icons are quadratic. Is that so? */
-            output->traypx += font_height;
+            trayclient *tc = malloc(sizeof(trayclient));
+            tc->win = client;
+            TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
 
             /* Trigger an update to copy the statusline text to the appropriate
              * position */
@@ -426,6 +442,29 @@ void handle_client_message(xcb_client_message_event_t* event) {
     }
 }
 
+void handle_unmap_notify(xcb_unmap_notify_event_t* event) {
+    DLOG("UnmapNotify for window = %08x, event = %08x\n", event->window, event->event);
+
+    i3_output *walk;
+    SLIST_FOREACH(walk, outputs, slist) {
+        if (!walk->active)
+            continue;
+        DLOG("checking output %s\n", walk->name);
+        trayclient *trayclient;
+        TAILQ_FOREACH(trayclient, walk->trayclients, tailq) {
+            if (trayclient->win != event->window)
+                continue;
+
+            DLOG("Removing tray client with window ID %08x\n", event->window);
+            TAILQ_REMOVE(walk->trayclients, trayclient, tailq);
+
+            /* Trigger an update, we now have more space for the statusline */
+            draw_bars();
+            return;
+        }
+    }
+}
+
 /*
  * This function is called immediately before the main loop locks. We flush xcb
  * then (and only then)
@@ -461,6 +500,10 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
              * example system tray widgets talk to us directly via client messages. */
             handle_client_message((xcb_client_message_event_t*) event);
             break;
+        case XCB_UNMAP_NOTIFY:
+            /* UnmapNotifies are received when a tray window unmaps itself */
+            handle_unmap_notify((xcb_unmap_notify_event_t*) event);
+            break;
     }
     FREE(event);
 }
@@ -1053,7 +1096,14 @@ void draw_bars() {
             /* Luckily we already prepared a seperate pixmap containing the rendered
              * statusline, we just have to copy the relevant parts to the relevant
              * position */
-            int traypx = outputs_walk->traypx;
+            trayclient *trayclient;
+            int traypx = 0;
+            TAILQ_FOREACH(trayclient, outputs_walk->trayclients, tailq) {
+                /* We assume the tray icons are quadratic (we use the font
+                 * *height* as *width* of the icons) because we configured them
+                 * like this. */
+                traypx += font_height;
+            }
             /* Add 2px of padding if there are any tray icons */
             if (traypx > 0)
                 traypx += 2;
@@ -1063,7 +1113,7 @@ void draw_bars() {
                           outputs_walk->bargc,
                           MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0,
                           MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - traypx - 4)), 3,
-                          MIN(outputs_walk->rect.w - outputs_walk->traypx - 4, statusline_width), font_height);
+                          MIN(outputs_walk->rect.w - traypx - 4, statusline_width), font_height);
         }
 
         if (config.disable_ws) {