dwm-systray-6.0.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
dwm-systray-6.0.diff (19982B)
---
1 Author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus
2 URL: http://dwm.suckless.org/patches/systray
3 Implements a system tray for dwm.
4
5 diff -r ec4baab78314 config.def.h
6 --- a/config.def.h Mon Dec 19 15:38:30 2011 +0100
7 +++ b/config.def.h Fri Apr 06 08:25:40 2012 +0200
8 @@ -10,6 +10,8 @@
9 static const char selfgcolor[] = "#eeeeee";
10 static const unsigned int borderpx = 1; /* border pixel of windows */
11 static const unsigned int snap = 32; /* snap pixel */
12 +static const unsigned int systrayspacing = 2; /* systray spacing */
13 +static const Bool showsystray = True; /* False means no systray */
14 static const Bool showbar = True; /* False means no bar */
15 static const Bool topbar = True; /* False means bottom bar */
16
17 diff -r ec4baab78314 dwm.c
18 --- a/dwm.c Mon Dec 19 15:38:30 2011 +0100
19 +++ b/dwm.c Fri Apr 06 08:25:40 2012 +0200
20 @@ -55,12 +55,30 @@
21 #define TAGMASK ((1 << LENGTH(tags)) - 1)
22 #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height)
23
24 +#define SYSTEM_TRAY_REQUEST_DOCK 0
25 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
26 +
27 +/* XEMBED messages */
28 +#define XEMBED_EMBEDDED_NOTIFY 0
29 +#define XEMBED_WINDOW_ACTIVATE 1
30 +#define XEMBED_FOCUS_IN 4
31 +#define XEMBED_MODALITY_ON 10
32 +
33 +#define XEMBED_MAPPED (1 << 0)
34 +#define XEMBED_WINDOW_ACTIVATE 1
35 +#define XEMBED_WINDOW_DEACTIVATE 2
36 +
37 +#define VERSION_MAJOR 0
38 +#define VERSION_MINOR 0
39 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
40 +
41 /* enums */
42 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
43 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
44 -enum { NetSupported, NetWMName, NetWMState,
45 - NetWMFullscreen, NetActiveWindow, NetWMWindowType,
46 - NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
47 +enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
48 + NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType,
49 + NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
50 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
51 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
52 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
53 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
54 @@ -154,6 +172,12 @@
55 int monitor;
56 } Rule;
57
58 +typedef struct Systray Systray;
59 +struct Systray {
60 + Window win;
61 + Client *icons;
62 +};
63 +
64 /* function declarations */
65 static void applyrules(Client *c);
66 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
67 @@ -186,9 +210,11 @@
68 static void focusin(XEvent *e);
69 static void focusmon(const Arg *arg);
70 static void focusstack(const Arg *arg);
71 +static Atom getatomprop(Client *c, Atom prop);
72 static unsigned long getcolor(const char *colstr);
73 static Bool getrootptr(int *x, int *y);
74 static long getstate(Window w);
75 +static unsigned int getsystraywidth();
76 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
77 static void grabbuttons(Client *c, Bool focused);
78 static void grabkeys(void);
79 @@ -207,13 +233,16 @@
80 static void propertynotify(XEvent *e);
81 static void quit(const Arg *arg);
82 static Monitor *recttomon(int x, int y, int w, int h);
83 +static void removesystrayicon(Client *i);
84 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
85 +static void resizebarwin(Monitor *m);
86 static void resizeclient(Client *c, int x, int y, int w, int h);
87 static void resizemouse(const Arg *arg);
88 +static void resizerequest(XEvent *e);
89 static void restack(Monitor *m);
90 static void run(void);
91 static void scan(void);
92 -static Bool sendevent(Client *c, Atom proto);
93 +static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
94 static void sendmon(Client *c, Monitor *m);
95 static void setclientstate(Client *c, long state);
96 static void setfocus(Client *c);
97 @@ -241,18 +270,24 @@
98 static void updatenumlockmask(void);
99 static void updatesizehints(Client *c);
100 static void updatestatus(void);
101 +static void updatesystray(void);
102 +static void updatesystrayicongeom(Client *i, int w, int h);
103 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
104 static void updatewindowtype(Client *c);
105 static void updatetitle(Client *c);
106 static void updatewmhints(Client *c);
107 static void view(const Arg *arg);
108 static Client *wintoclient(Window w);
109 static Monitor *wintomon(Window w);
110 +static Client *wintosystrayicon(Window w);
111 static int xerror(Display *dpy, XErrorEvent *ee);
112 static int xerrordummy(Display *dpy, XErrorEvent *ee);
113 static int xerrorstart(Display *dpy, XErrorEvent *ee);
114 static void zoom(const Arg *arg);
115
116 /* variables */
117 +static Systray *systray = NULL;
118 +static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
119 static const char broken[] = "broken";
120 static char stext[256];
121 static int screen;
122 @@ -274,9 +309,10 @@
123 [MapRequest] = maprequest,
124 [MotionNotify] = motionnotify,
125 [PropertyNotify] = propertynotify,
126 + [ResizeRequest] = resizerequest,
127 [UnmapNotify] = unmapnotify
128 };
129 -static Atom wmatom[WMLast], netatom[NetLast];
130 +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
131 static Bool running = True;
132 static Cursor cursor[CurLast];
133 static Display *dpy;
134 @@ -497,6 +533,11 @@
135 XFreeCursor(dpy, cursor[CurMove]);
136 while(mons)
137 cleanupmon(mons);
138 + if(showsystray) {
139 + XUnmapWindow(dpy, systray->win);
140 + XDestroyWindow(dpy, systray->win);
141 + free(systray);
142 + }
143 XSync(dpy, False);
144 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
145 }
146 @@ -530,9 +572,49 @@
147
148 void
149 clientmessage(XEvent *e) {
150 + XWindowAttributes wa;
151 + XSetWindowAttributes swa;
152 XClientMessageEvent *cme = &e->xclient;
153 Client *c = wintoclient(cme->window);
154
155 + if(showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
156 + /* add systray icons */
157 + if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
158 + if(!(c = (Client *)calloc(1, sizeof(Client))))
159 + die("fatal: could not malloc() %u bytes\n", sizeof(Client));
160 + c->win = cme->data.l[2];
161 + c->mon = selmon;
162 + c->next = systray->icons;
163 + systray->icons = c;
164 + XGetWindowAttributes(dpy, c->win, &wa);
165 + c->x = c->oldx = c->y = c->oldy = 0;
166 + c->w = c->oldw = wa.width;
167 + c->h = c->oldh = wa.height;
168 + c->oldbw = wa.border_width;
169 + c->bw = 0;
170 + c->isfloating = True;
171 + /* reuse tags field as mapped status */
172 + c->tags = 1;
173 + updatesizehints(c);
174 + updatesystrayicongeom(c, wa.width, wa.height);
175 + XAddToSaveSet(dpy, c->win);
176 + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
177 + XReparentWindow(dpy, c->win, systray->win, 0, 0);
178 + /* use parents background pixmap */
179 + swa.background_pixmap = ParentRelative;
180 + swa.background_pixel = dc.norm[ColBG];
181 + XChangeWindowAttributes(dpy, c->win, CWBackPixmap|CWBackPixel, &swa);
182 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
183 + /* FIXME not sure if I have to send these events, too */
184 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
185 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
186 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
187 + resizebarwin(selmon);
188 + updatesystray();
189 + setclientstate(c, NormalState);
190 + }
191 + return;
192 + }
193 if(!c)
194 return;
195 if(cme->message_type == netatom[NetWMState]) {
196 @@ -583,7 +663,7 @@
197 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
198 updatebars();
199 for(m = mons; m; m = m->next)
200 - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
201 + resizebarwin(m);
202 focus(NULL);
203 arrange(NULL);
204 }
205 @@ -667,6 +747,11 @@
206
207 if((c = wintoclient(ev->window)))
208 unmanage(c, True);
209 + else if((c = wintosystrayicon(ev->window))) {
210 + removesystrayicon(c);
211 + resizebarwin(selmon);
212 + updatesystray();
213 + }
214 }
215
216 void
217 @@ -722,6 +807,7 @@
218 unsigned long *col;
219 Client *c;
220
221 + resizebarwin(m);
222 for(c = m->clients; c; c = c->next) {
223 occ |= c->tags;
224 if(c->isurgent)
225 @@ -743,6 +829,9 @@
226 if(m == selmon) { /* status is only drawn on selected monitor */
227 dc.w = TEXTW(stext);
228 dc.x = m->ww - dc.w;
229 + if(showsystray && m == selmon) {
230 + dc.x -= getsystraywidth();
231 + }
232 if(dc.x < x) {
233 dc.x = x;
234 dc.w = m->ww - x;
235 @@ -771,6 +860,7 @@
236
237 for(m = mons; m; m = m->next)
238 drawbar(m);
239 + updatesystray();
240 }
241
242 void
243 @@ -917,10 +1007,17 @@
244 unsigned long dl;
245 unsigned char *p = NULL;
246 Atom da, atom = None;
247 + /* FIXME getatomprop should return the number of items and a pointer to
248 + * the stored data instead of this workaround */
249 + Atom req = XA_ATOM;
250 + if(prop == xatom[XembedInfo])
251 + req = xatom[XembedInfo];
252
253 - if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
254 + if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
255 &da, &di, &dl, &dl, &p) == Success && p) {
256 atom = *(Atom *)p;
257 + if(da == xatom[XembedInfo] && dl == 2)
258 + atom = ((Atom *)p)[1];
259 XFree(p);
260 }
261 return atom;
262 @@ -962,6 +1059,15 @@
263 return result;
264 }
265
266 +unsigned int
267 +getsystraywidth() {
268 + unsigned int w = 0;
269 + Client *i;
270 + if(showsystray)
271 + for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
272 + return w ? w + systrayspacing : 1;
273 +}
274 +
275 Bool
276 gettextprop(Window w, Atom atom, char *text, unsigned int size) {
277 char **list = NULL;
278 @@ -1096,7 +1202,7 @@
279 killclient(const Arg *arg) {
280 if(!selmon->sel)
281 return;
282 - if(!sendevent(selmon->sel, wmatom[WMDelete])) {
283 + if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
284 XGrabServer(dpy);
285 XSetErrorHandler(xerrordummy);
286 XSetCloseDownMode(dpy, DestroyAll);
287 @@ -1180,6 +1286,12 @@
288 maprequest(XEvent *e) {
289 static XWindowAttributes wa;
290 XMapRequestEvent *ev = &e->xmaprequest;
291 + Client *i;
292 + if((i = wintosystrayicon(ev->window))) {
293 + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
294 + resizebarwin(selmon);
295 + updatesystray();
296 + }
297
298 if(!XGetWindowAttributes(dpy, ev->window, &wa))
299 return;
300 @@ -1293,6 +1405,16 @@
301 Window trans;
302 XPropertyEvent *ev = &e->xproperty;
303
304 + if((c = wintosystrayicon(ev->window))) {
305 + if(ev->atom == XA_WM_NORMAL_HINTS) {
306 + updatesizehints(c);
307 + updatesystrayicongeom(c, c->w, c->h);
308 + }
309 + else
310 + updatesystrayiconstate(c, ev);
311 + resizebarwin(selmon);
312 + updatesystray();
313 + }
314 if((ev->window == root) && (ev->atom == XA_WM_NAME))
315 updatestatus();
316 else if(ev->state == PropertyDelete)
317 @@ -1342,12 +1464,33 @@
318 }
319
320 void
321 +removesystrayicon(Client *i) {
322 + Client **ii;
323 +
324 + if(!showsystray || !i)
325 + return;
326 + for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
327 + if(ii)
328 + *ii = i->next;
329 + free(i);
330 +}
331 +
332 +
333 +void
334 resize(Client *c, int x, int y, int w, int h, Bool interact) {
335 if(applysizehints(c, &x, &y, &w, &h, interact))
336 resizeclient(c, x, y, w, h);
337 }
338
339 void
340 +resizebarwin(Monitor *m) {
341 + unsigned int w = m->ww;
342 + if(showsystray && m == selmon)
343 + w -= getsystraywidth();
344 + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
345 +}
346 +
347 +void
348 resizeclient(Client *c, int x, int y, int w, int h) {
349 XWindowChanges wc;
350
351 @@ -1412,6 +1555,18 @@
352 }
353
354 void
355 +resizerequest(XEvent *e) {
356 + XResizeRequestEvent *ev = &e->xresizerequest;
357 + Client *i;
358 +
359 + if((i = wintosystrayicon(ev->window))) {
360 + updatesystrayicongeom(i, ev->width, ev->height);
361 + resizebarwin(selmon);
362 + updatesystray();
363 + }
364 +}
365 +
366 +void
367 restack(Monitor *m) {
368 Client *c;
369 XEvent ev;
370 @@ -1495,25 +1650,35 @@
371 }
372
373 Bool
374 -sendevent(Client *c, Atom proto) {
375 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) {
376 int n;
377 - Atom *protocols;
378 + Atom *protocols, mt;
379 Bool exists = False;
380 XEvent ev;
381
382 - if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
383 - while(!exists && n--)
384 - exists = protocols[n] == proto;
385 - XFree(protocols);
386 + if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
387 + mt = wmatom[WMProtocols];
388 + if(XGetWMProtocols(dpy, w, &protocols, &n)) {
389 + while(!exists && n--)
390 + exists = protocols[n] == proto;
391 + XFree(protocols);
392 + }
393 + }
394 + else {
395 + exists = True;
396 + mt = proto;
397 }
398 if(exists) {
399 ev.type = ClientMessage;
400 - ev.xclient.window = c->win;
401 - ev.xclient.message_type = wmatom[WMProtocols];
402 + ev.xclient.window = w;
403 + ev.xclient.message_type = mt;
404 ev.xclient.format = 32;
405 - ev.xclient.data.l[0] = proto;
406 - ev.xclient.data.l[1] = CurrentTime;
407 - XSendEvent(dpy, c->win, False, NoEventMask, &ev);
408 + ev.xclient.data.l[0] = d0;
409 + ev.xclient.data.l[1] = d1;
410 + ev.xclient.data.l[2] = d2;
411 + ev.xclient.data.l[3] = d3;
412 + ev.xclient.data.l[4] = d4;
413 + XSendEvent(dpy, w, False, mask, &ev);
414 }
415 return exists;
416 }
417 @@ -1522,7 +1687,7 @@
418 setfocus(Client *c) {
419 if(!c->neverfocus)
420 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
421 - sendevent(c, wmatom[WMTakeFocus]);
422 + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
423 }
424
425 void
426 @@ -1602,11 +1767,17 @@
427 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
428 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
429 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
430 + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
431 + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
432 + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
433 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
434 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
435 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
436 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
437 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
438 + xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
439 + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
440 + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
441 /* init cursors */
442 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
443 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
444 @@ -1623,6 +1794,8 @@
445 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
446 if(!dc.font.set)
447 XSetFont(dpy, dc.gc, dc.font.xfont->fid);
448 + /* init system tray */
449 + updatesystray();
450 /* init bars */
451 updatebars();
452 updatestatus();
453 @@ -1731,7 +1904,18 @@
454 togglebar(const Arg *arg) {
455 selmon->showbar = !selmon->showbar;
456 updatebarpos(selmon);
457 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
458 + resizebarwin(selmon);
459 + if(showsystray) {
460 + XWindowChanges wc;
461 + if(!selmon->showbar)
462 + wc.y = -bh;
463 + else if(selmon->showbar) {
464 + wc.y = 0;
465 + if(!selmon->topbar)
466 + wc.y = selmon->mh - bh;
467 + }
468 + XConfigureWindow(dpy, systray->win, CWY, &wc);
469 + }
470 arrange(selmon);
471 }
472
473 @@ -1816,18 +2000,28 @@
474 else
475 unmanage(c, False);
476 }
477 + else if((c = wintosystrayicon(ev->window))) {
478 + removesystrayicon(c);
479 + resizebarwin(selmon);
480 + updatesystray();
481 + }
482 }
483
484 void
485 updatebars(void) {
486 + unsigned int w;
487 Monitor *m;
488 +
489 XSetWindowAttributes wa = {
490 .override_redirect = True,
491 .background_pixmap = ParentRelative,
492 .event_mask = ButtonPressMask|ExposureMask
493 };
494 for(m = mons; m; m = m->next) {
495 - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
496 + w = m->ww;
497 + if(showsystray && m == selmon)
498 + w -= getsystraywidth();
499 + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
500 CopyFromParent, DefaultVisual(dpy, screen),
501 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
502 XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
503 @@ -2011,6 +2208,107 @@
504 }
505
506 void
507 +updatesystrayicongeom(Client *i, int w, int h) {
508 + if(i) {
509 + i->h = bh;
510 + if(w == h)
511 + i->w = bh;
512 + else if(h == bh)
513 + i->w = w;
514 + else
515 + i->w = (int) ((float)bh * ((float)w / (float)h));
516 + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
517 + /* force icons into the systray dimenons if they don't want to */
518 + if(i->h > bh) {
519 + if(i->w == i->h)
520 + i->w = bh;
521 + else
522 + i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
523 + i->h = bh;
524 + }
525 + }
526 +}
527 +
528 +void
529 +updatesystrayiconstate(Client *i, XPropertyEvent *ev) {
530 + long flags;
531 + int code = 0;
532 +
533 + if(!showsystray || !i || ev->atom != xatom[XembedInfo] ||
534 + !(flags = getatomprop(i, xatom[XembedInfo])))
535 + return;
536 +
537 + if(flags & XEMBED_MAPPED && !i->tags) {
538 + i->tags = 1;
539 + code = XEMBED_WINDOW_ACTIVATE;
540 + XMapRaised(dpy, i->win);
541 + setclientstate(i, NormalState);
542 + }
543 + else if(!(flags & XEMBED_MAPPED) && i->tags) {
544 + i->tags = 0;
545 + code = XEMBED_WINDOW_DEACTIVATE;
546 + XUnmapWindow(dpy, i->win);
547 + setclientstate(i, WithdrawnState);
548 + }
549 + else
550 + return;
551 + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
552 + systray->win, XEMBED_EMBEDDED_VERSION);
553 +}
554 +
555 +void
556 +updatesystray(void) {
557 + XSetWindowAttributes wa;
558 + Client *i;
559 + unsigned int x = selmon->mx + selmon->mw;
560 + unsigned int w = 1;
561 +
562 + if(!showsystray)
563 + return;
564 + if(!systray) {
565 + /* init systray */
566 + if(!(systray = (Systray *)calloc(1, sizeof(Systray))))
567 + die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
568 + systray->win = XCreateSimpleWindow(dpy, root, x, selmon->by, w, bh, 0, 0, dc.sel[ColBG]);
569 + wa.event_mask = ButtonPressMask | ExposureMask;
570 + wa.override_redirect = True;
571 + wa.background_pixmap = ParentRelative;
572 + wa.background_pixel = dc.norm[ColBG];
573 + XSelectInput(dpy, systray->win, SubstructureNotifyMask);
574 + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
575 + PropModeReplace, (unsigned char *)&systrayorientation, 1);
576 + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel|CWBackPixmap, &wa);
577 + XMapRaised(dpy, systray->win);
578 + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
579 + if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
580 + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
581 + XSync(dpy, False);
582 + }
583 + else {
584 + fprintf(stderr, "dwm: unable to obtain system tray.\n");
585 + free(systray);
586 + systray = NULL;
587 + return;
588 + }
589 + }
590 + for(w = 0, i = systray->icons; i; i = i->next) {
591 + XMapRaised(dpy, i->win);
592 + w += systrayspacing;
593 + XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->h);
594 + w += i->w;
595 + if(i->mon != selmon)
596 + i->mon = selmon;
597 + }
598 + w = w ? w + systrayspacing : 1;
599 + x -= w;
600 + XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh);
601 + /* redraw background */
602 + XSetForeground(dpy, dc.gc, dc.norm[ColBG]);
603 + XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh);
604 + XSync(dpy, False);
605 +}
606 +
607 +void
608 updatewindowtype(Client *c) {
609 Atom state = getatomprop(c, netatom[NetWMState]);
610 Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
611 @@ -2080,6 +2372,16 @@
612 return selmon;
613 }
614
615 +Client *
616 +wintosystrayicon(Window w) {
617 + Client *i = NULL;
618 +
619 + if(!showsystray || !w)
620 + return i;
621 + for(i = systray->icons; i && i->win != w; i = i->next) ;
622 + return i;
623 +}
624 +
625 /* There's no way to check accesses to destroyed windows, thus those cases are
626 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
627 * default error handler, which may call exit. */