]> git.sur5r.net Git - i3/i3/commitdiff
i3bar: properly handle the _XEMBED_INFO property
authorMichael Stapelberg <michael@stapelberg.de>
Tue, 16 Aug 2011 22:05:05 +0000 (00:05 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Tue, 23 Aug 2011 23:18:27 +0000 (01:18 +0200)
i3bar/include/common.h
i3bar/include/trayclients.h
i3bar/include/xcb.h
i3bar/include/xcb_atoms.def
i3bar/src/outputs.c
i3bar/src/workspaces.c
i3bar/src/xcb.c

index 9737d22ff68fc5a266280fa074b91162b757374d..74bd21528501d3b4701043ef51691c30e2891a61 100644 (file)
@@ -9,8 +9,9 @@
 #ifndef COMMON_H_
 #define COMMON_H_
 
+#include <stdbool.h>
+
 typedef struct rect_t rect;
-typedef int bool;
 
 struct ev_loop* main_loop;
 char            *statusline;
index 3218578a69e664257f124b8facbf445977239c2a..277cd1cbd298fae9047ce264826eb242475cfc55 100644 (file)
@@ -17,6 +17,7 @@ TAILQ_HEAD(tc_head, trayclient);
 
 struct trayclient {
     xcb_window_t       win;         /* The window ID of the tray client */
+    bool               mapped;      /* Whether this window is mapped */
 
     TAILQ_ENTRY(trayclient) tailq;  /* Pointer for the TAILQ-Macro */
 };
index 531fdfe942c76265e0e5b559528b5ccb5e733604..3fadc4c50cf938cf0c6d9d6bd3ff7794eab2f614 100644 (file)
 #include <stdint.h>
 //#include "outputs.h"
 
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+#define XEMBED_MAPPED                   (1 << 0)
+
 struct xcb_color_strings_t {
     char *bar_fg;
     char *bar_bg;
index 792ef9a9477f8a6ae12585ff50fceff71fb330e1..3f2b9775db4d0904b0f2ef8088e0c38eeadfceec 100644 (file)
@@ -8,4 +8,5 @@ ATOM_DO(_NET_SYSTEM_TRAY_ORIENTATION)
 ATOM_DO(_NET_SYSTEM_TRAY_VISUAL)
 ATOM_DO(CARDINAL)
 ATOM_DO(_NET_SYSTEM_TRAY_OPCODE)
+ATOM_DO(_XEMBED_INFO)
 #undef ATOM_DO
index 53544d178c312f77969734cd021808d2634404b8..464f24a0ea52fa171b5caa1904d6d4708672cd89 100644 (file)
@@ -43,7 +43,7 @@ static int outputs_null_cb(void *params_) {
  * Parse a boolean value (active)
  *
  */
-static int outputs_boolean_cb(void *params_, bool val) {
+static int outputs_boolean_cb(void *params_, int val) {
     struct outputs_json_params *params = (struct outputs_json_params*) params_;
 
     if (strcmp(params->cur_key, "active")) {
index eeb9ca349f459d47a7b0ad9c5eacfa39a5b4c831..a84e152b79e981f2bd71099a27a1a146472716cf 100644 (file)
@@ -29,7 +29,7 @@ struct workspaces_json_params {
  * Parse a boolean value (visible, focused, urgent)
  *
  */
-static int workspaces_boolean_cb(void *params_, bool val) {
+static int workspaces_boolean_cb(void *params_, int val) {
     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
 
     if (!strcmp(params->cur_key, "visible")) {
index eb1ae0abd91b39115df213b8ab94b99eecf07253..c7ddfe88a2c7fd812b2cd11dc7c2d444d69d958f 100644 (file)
@@ -416,11 +416,48 @@ void handle_client_message(xcb_client_message_event_t* event) {
         DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
         /* event->data.data32[0] is the timestamp */
         uint32_t op = event->data.data32[1];
-#define SYSTEM_TRAY_REQUEST_DOCK    0
-#define SYSTEM_TRAY_BEGIN_MESSAGE   1
-#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+        uint32_t mask;
+        uint32_t values[2];
         if (op == SYSTEM_TRAY_REQUEST_DOCK) {
             xcb_window_t client = event->data.data32[2];
+
+            /* 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);
+
+            /* Request the _XEMBED_INFO property. The XEMBED specification
+             * (which is referred by the tray specification) says this *has* to
+             * be set, but VLC does not set it… */
+            bool map_it = true;
+            xcb_get_property_cookie_t xembedc;
+            xembedc = xcb_get_property_unchecked(xcb_connection,
+                                                 0,
+                                                 client,
+                                                 atoms[_XEMBED_INFO],
+                                                 XCB_GET_PROPERTY_TYPE_ANY,
+                                                 0,
+                                                 2 * 32);
+
+            xcb_get_property_reply_t *xembedr = xcb_get_property_reply(xcb_connection,
+                                                                       xembedc,
+                                                                       NULL);
+            if (xembedr != NULL && xembedr->length != 0) {
+                DLOG("xembed format = %d, len = %d\n", xembedr->format, xembedr->length);
+                uint32_t *xembed = xcb_get_property_value(xembedr);
+                DLOG("xembed version = %d\n", xembed[0]);
+                DLOG("xembed flags = %d\n", xembed[1]);
+                map_it = ((xembed[1] & XEMBED_MAPPED) == XEMBED_MAPPED);
+                free(xembedr);
+            } else {
+                ELOG("Window %08x violates the XEMBED protocol, _XEMBED_INFO not set\n", client);
+            }
+
             DLOG("X window %08x requested docking\n", client);
             i3_output *walk, *output;
             SLIST_FOREACH(walk, outputs, slist) {
@@ -439,25 +476,23 @@ void handle_client_message(xcb_client_message_event_t* event) {
              *   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 };
+            mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+            values[0] = font_height;
+            values[1] = 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);
+            if (map_it) {
+                DLOG("Mapping dock client\n");
+                xcb_map_window(xcb_connection, client);
+            } else {
+                DLOG("Not mapping dock client yet\n");
+            }
             trayclient *tc = malloc(sizeof(trayclient));
             tc->win = client;
+            tc->mapped = map_it;
             TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
 
             /* Trigger an update to copy the statusline text to the appropriate
@@ -492,6 +527,68 @@ void handle_unmap_notify(xcb_unmap_notify_event_t* event) {
     }
 }
 
+static void handle_property_notify(xcb_property_notify_event_t *event) {
+    DLOG("PropertyNotify\n");
+    if (event->atom == atoms[_XEMBED_INFO] &&
+        event->state == XCB_PROPERTY_NEW_VALUE) {
+        DLOG("xembed_info updated\n");
+        trayclient *trayclient = NULL, *walk;
+        i3_output *output;
+        SLIST_FOREACH(output, outputs, slist) {
+            if (!output->active)
+                continue;
+
+            TAILQ_FOREACH(walk, output->trayclients, tailq) {
+                if (walk->win != event->window)
+                    continue;
+                trayclient = walk;
+                break;
+            }
+
+            if (trayclient)
+                break;
+        }
+        if (!trayclient) {
+            ELOG("PropertyNotify received for unknown window %08x\n",
+                 event->window);
+            return;
+        }
+        xcb_get_property_cookie_t xembedc;
+        xembedc = xcb_get_property_unchecked(xcb_connection,
+                                             0,
+                                             trayclient->win,
+                                             atoms[_XEMBED_INFO],
+                                             XCB_GET_PROPERTY_TYPE_ANY,
+                                             0,
+                                             2 * 32);
+
+        xcb_get_property_reply_t *xembedr = xcb_get_property_reply(xcb_connection,
+                                                                   xembedc,
+                                                                   NULL);
+        if (xembedr == NULL || xembedr->length == 0)
+            return;
+
+        DLOG("xembed format = %d, len = %d\n", xembedr->format, xembedr->length);
+        uint32_t *xembed = xcb_get_property_value(xembedr);
+        DLOG("xembed version = %d\n", xembed[0]);
+        DLOG("xembed flags = %d\n", xembed[1]);
+        bool map_it = ((xembed[1] & XEMBED_MAPPED) == XEMBED_MAPPED);
+        DLOG("map-state now %d\n", map_it);
+        if (trayclient->mapped && !map_it) {
+            /* need to unmap the window */
+            xcb_unmap_window(xcb_connection, trayclient->win);
+            trayclient->mapped = map_it;
+            draw_bars();
+        } else if (!trayclient->mapped && map_it) {
+            /* need to map the window */
+            xcb_map_window(xcb_connection, trayclient->win);
+            trayclient->mapped = map_it;
+            draw_bars();
+        }
+        free(xembedr);
+    }
+}
+
 /*
  * This function is called immediately before the main loop locks. We flush xcb
  * then (and only then)
@@ -531,6 +628,10 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
             /* UnmapNotifies are received when a tray window unmaps itself */
             handle_unmap_notify((xcb_unmap_notify_event_t*) event);
             break;
+        case XCB_PROPERTY_NOTIFY:
+            /* PropertyNotify */
+            handle_property_notify((xcb_property_notify_event_t*) event);
+            break;
     }
     FREE(event);
 }
@@ -1126,6 +1227,8 @@ void draw_bars() {
             trayclient *trayclient;
             int traypx = 0;
             TAILQ_FOREACH(trayclient, outputs_walk->trayclients, tailq) {
+                if (!trayclient->mapped)
+                    continue;
                 /* We assume the tray icons are quadratic (we use the font
                  * *height* as *width* of the icons) because we configured them
                  * like this. */