From 2046e4112f551db819e471b9553dee22f957eb20 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 15 Aug 2011 15:57:52 +0200 Subject: [PATCH] i3bar: Correctly handle removal of tray clients --- i3bar/include/common.h | 1 + i3bar/include/outputs.h | 3 +- i3bar/include/trayclients.h | 24 +++++++++++++++ i3bar/src/outputs.c | 4 ++- i3bar/src/xcb.c | 60 +++++++++++++++++++++++++++++++++---- 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 i3bar/include/trayclients.h diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 644b777c..9737d22f 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -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" diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 680261b1..c6402a5b 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -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 index 00000000..3218578a --- /dev/null +++ b/i3bar/include/trayclients.h @@ -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 diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 39bad192..53544d17 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -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; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 29b31aef..3da23a81 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -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) { -- 2.39.5