wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 6e288e661158583b83a77a8bdc093787dd2d30c8
parent 0a694fe4ea0ad00398f4d80e20a2ebce73117ad6
Author: Kris Maglione <kris@suckless.org>
Date:   Tue, 20 Sep 2011 02:49:06 -0400

[tray] Add a horrible workaround for broken Qt systray icon implementation. Closes issue #228.

Diffstat:
cmd/tray/selection.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 50 insertions(+), 21 deletions(-)

diff --git a/cmd/tray/selection.c b/cmd/tray/selection.c @@ -7,10 +7,11 @@ static Handlers selection_handlers; static Handlers steal_handlers; -Selection* -selection_create(char *selection, ulong time, +static Selection* +_selection_create(char *selection, ulong time, void (*request)(Selection*, XSelectionRequestEvent*), - void (*cleanup)(Selection*)) { + void (*cleanup)(Selection*), + bool lazy) { Selection *s; if(time == 0) @@ -26,31 +27,49 @@ selection_create(char *selection, ulong time, sethandler(s->owner, &selection_handlers); - XSetSelectionOwner(display, xatom(selection), s->owner->xid, time); - - /* - * There is a race here that ICCCM doesn't mention. It's - * possible that we've gained and lost the selection in this - * time, and a client's sent us a selection request. We're - * required to reply to it, but since we're destroying the - * window, we'll never hear about it. Since ICCCM doesn't - * mention it, we assume that other clients behave likewise, - * and therefore clients must be prepared to deal with such - * behavior regardless. - */ - if(XGetSelectionOwner(display, xatom(selection)) != s->owner->xid) { - destroywindow(s->owner); - free(s); - return nil; + if (!lazy) { + XSetSelectionOwner(display, xatom(selection), s->owner->xid, time); + + /* + * There is a race here that ICCCM doesn't mention. It's + * possible that we've gained and lost the selection in this + * time, and a client's sent us a selection request. We're + * required to reply to it, but since we're destroying the + * window, we'll never hear about it. Since ICCCM doesn't + * mention it, we assume that other clients behave likewise, + * and therefore clients must be prepared to deal with such + * behavior regardless. + */ + if(XGetSelectionOwner(display, xatom(selection)) != s->owner->xid) { + destroywindow(s->owner); + free(s); + return nil; + } } s->selection = estrdup(selection); return s; } +Selection* +selection_create(char *selection, ulong time, + void (*request)(Selection*, XSelectionRequestEvent*), + void (*cleanup)(Selection*)) { + return _selection_create(selection, time, request, cleanup, false); +} + static void _selection_manage(Selection *s) { + if (s->oldowner) { + Dprint("[selection] Grabbing.\n"); + XSetSelectionOwner(display, xatom(s->selection), s->owner->xid, s->time_start); + if(XGetSelectionOwner(display, xatom(s->selection)) != s->owner->xid) { + selection_release(s); + return; + } + } + Dprint("[selection] Notifying.\n"); clientmessage(&scr.root, "MANAGER", SubstructureNotifyMask|StructureNotifyMask, 32, (ClientMessageData){ .l = {s->time_start, xatom(s->selection), s->owner->xid} }); @@ -84,9 +103,18 @@ selection_manage(char *selection, ulong time, w->type = WWindow; w->xid = old; selectinput(w, StructureNotifyMask); + + /* Hack for broken Qt systray implementation. If it + * finds a new system tray running when the old one + * dies, it never selects the StructureNotify mask + * on it, and therefore never disassociates from it, + * and completely ignores any future MANAGER + * messages it receives. + */ + XSetSelectionOwner(display, xatom(selection), 0, time); } - s = selection_create(selection, time, nil, cleanup); + s = _selection_create(selection, time, nil, cleanup, old); if(s) { s->message = message; s->oldowner = old; @@ -189,8 +217,9 @@ destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) { if(s->timer) ixp_unsettimer(&srv, s->timer); s->timer = 0; - s->oldowner = 0; + _selection_manage(s); + s->oldowner = 0; return false; }