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) {
* 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
}
}
+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)
/* 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);
}
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. */