Merge branch 'master' of git.martlubbers.net:dotfiles
[dotfiles.git] / config.h / dwm / dwm-systray-6.4.diff
1 diff --git a/config.def.h b/config.def.h
2 index 9efa774..750529d 100644
3 --- a/config.def.h
4 +++ b/config.def.h
5 @@ -3,6 +3,11 @@
6 /* appearance */
7 static const unsigned int borderpx = 1; /* border pixel of windows */
8 static const unsigned int snap = 32; /* snap pixel */
9 +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
10 +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */
11 +static const unsigned int systrayspacing = 2; /* systray spacing */
12 +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
13 +static const int showsystray = 1; /* 0 means no systray */
14 static const int showbar = 1; /* 0 means no bar */
15 static const int topbar = 1; /* 0 means bottom bar */
16 static const char *fonts[] = { "monospace:size=10" };
17 @@ -101,8 +106,8 @@ static const Key keys[] = {
18 /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
19 static const Button buttons[] = {
20 /* click event mask button function argument */
21 - { ClkLtSymbol, 0, Button1, setlayout, {0} },
22 - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
23 + { ClkTagBar, MODKEY, Button1, tag, {0} },
24 + { ClkTagBar, MODKEY, Button3, toggletag, {0} },
25 { ClkWinTitle, 0, Button2, zoom, {0} },
26 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
27 { ClkClientWin, MODKEY, Button1, movemouse, {0} },
28 diff --git a/dwm.c b/dwm.c
29 index 03baf42..4611a03 100644
30 --- a/dwm.c
31 +++ b/dwm.c
32 @@ -57,12 +57,27 @@
33 #define TAGMASK ((1 << LENGTH(tags)) - 1)
34 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
35
36 +#define SYSTEM_TRAY_REQUEST_DOCK 0
37 +/* XEMBED messages */
38 +#define XEMBED_EMBEDDED_NOTIFY 0
39 +#define XEMBED_WINDOW_ACTIVATE 1
40 +#define XEMBED_FOCUS_IN 4
41 +#define XEMBED_MODALITY_ON 10
42 +#define XEMBED_MAPPED (1 << 0)
43 +#define XEMBED_WINDOW_ACTIVATE 1
44 +#define XEMBED_WINDOW_DEACTIVATE 2
45 +#define VERSION_MAJOR 0
46 +#define VERSION_MINOR 0
47 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
48 +
49 /* enums */
50 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
51 enum { SchemeNorm, SchemeSel }; /* color schemes */
52 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
53 + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
54 NetWMFullscreen, NetActiveWindow, NetWMWindowType,
55 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
56 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
57 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
58 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
59 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
60 @@ -141,6 +156,12 @@ typedef struct {
61 int monitor;
62 } Rule;
63
64 +typedef struct Systray Systray;
65 +struct Systray {
66 + Window win;
67 + Client *icons;
68 +};
69 +
70 /* function declarations */
71 static void applyrules(Client *c);
72 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
73 @@ -172,6 +193,7 @@ static void focusstack(const Arg *arg);
74 static Atom getatomprop(Client *c, Atom prop);
75 static int getrootptr(int *x, int *y);
76 static long getstate(Window w);
77 +static unsigned int getsystraywidth();
78 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
79 static void grabbuttons(Client *c, int focused);
80 static void grabkeys(void);
81 @@ -189,13 +211,16 @@ static void pop(Client *c);
82 static void propertynotify(XEvent *e);
83 static void quit(const Arg *arg);
84 static Monitor *recttomon(int x, int y, int w, int h);
85 +static void removesystrayicon(Client *i);
86 static void resize(Client *c, int x, int y, int w, int h, int interact);
87 +static void resizebarwin(Monitor *m);
88 static void resizeclient(Client *c, int x, int y, int w, int h);
89 static void resizemouse(const Arg *arg);
90 +static void resizerequest(XEvent *e);
91 static void restack(Monitor *m);
92 static void run(void);
93 static void scan(void);
94 -static int sendevent(Client *c, Atom proto);
95 +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
96 static void sendmon(Client *c, Monitor *m);
97 static void setclientstate(Client *c, long state);
98 static void setfocus(Client *c);
99 @@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg);
100 static void showhide(Client *c);
101 static void sigchld(int unused);
102 static void spawn(const Arg *arg);
103 +static Monitor *systraytomon(Monitor *m);
104 static void tag(const Arg *arg);
105 static void tagmon(const Arg *arg);
106 static void tile(Monitor *m);
107 @@ -224,18 +250,23 @@ static int updategeom(void);
108 static void updatenumlockmask(void);
109 static void updatesizehints(Client *c);
110 static void updatestatus(void);
111 +static void updatesystray(void);
112 +static void updatesystrayicongeom(Client *i, int w, int h);
113 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
114 static void updatetitle(Client *c);
115 static void updatewindowtype(Client *c);
116 static void updatewmhints(Client *c);
117 static void view(const Arg *arg);
118 static Client *wintoclient(Window w);
119 static Monitor *wintomon(Window w);
120 +static Client *wintosystrayicon(Window w);
121 static int xerror(Display *dpy, XErrorEvent *ee);
122 static int xerrordummy(Display *dpy, XErrorEvent *ee);
123 static int xerrorstart(Display *dpy, XErrorEvent *ee);
124 static void zoom(const Arg *arg);
125
126 /* variables */
127 +static Systray *systray = NULL;
128 static const char broken[] = "broken";
129 static char stext[256];
130 static int screen;
131 @@ -258,9 +289,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
132 [MapRequest] = maprequest,
133 [MotionNotify] = motionnotify,
134 [PropertyNotify] = propertynotify,
135 + [ResizeRequest] = resizerequest,
136 [UnmapNotify] = unmapnotify
137 };
138 -static Atom wmatom[WMLast], netatom[NetLast];
139 +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
140 static int running = 1;
141 static Cur *cursor[CurLast];
142 static Clr **scheme;
143 @@ -442,7 +474,7 @@ buttonpress(XEvent *e)
144 arg.ui = 1 << i;
145 } else if (ev->x < x + TEXTW(selmon->ltsymbol))
146 click = ClkLtSymbol;
147 - else if (ev->x > selmon->ww - (int)TEXTW(stext))
148 + else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
149 click = ClkStatusText;
150 else
151 click = ClkWinTitle;
152 @@ -485,6 +517,13 @@ cleanup(void)
153 XUngrabKey(dpy, AnyKey, AnyModifier, root);
154 while (mons)
155 cleanupmon(mons);
156 +
157 + if (showsystray) {
158 + XUnmapWindow(dpy, systray->win);
159 + XDestroyWindow(dpy, systray->win);
160 + free(systray);
161 + }
162 +
163 for (i = 0; i < CurLast; i++)
164 drw_cur_free(drw, cursor[i]);
165 for (i = 0; i < LENGTH(colors); i++)
166 @@ -516,9 +555,58 @@ cleanupmon(Monitor *mon)
167 void
168 clientmessage(XEvent *e)
169 {
170 + XWindowAttributes wa;
171 + XSetWindowAttributes swa;
172 XClientMessageEvent *cme = &e->xclient;
173 Client *c = wintoclient(cme->window);
174
175 + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
176 + /* add systray icons */
177 + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
178 + if (!(c = (Client *)calloc(1, sizeof(Client))))
179 + die("fatal: could not malloc() %u bytes\n", sizeof(Client));
180 + if (!(c->win = cme->data.l[2])) {
181 + free(c);
182 + return;
183 + }
184 + c->mon = selmon;
185 + c->next = systray->icons;
186 + systray->icons = c;
187 + if (!XGetWindowAttributes(dpy, c->win, &wa)) {
188 + /* use sane defaults */
189 + wa.width = bh;
190 + wa.height = bh;
191 + wa.border_width = 0;
192 + }
193 + c->x = c->oldx = c->y = c->oldy = 0;
194 + c->w = c->oldw = wa.width;
195 + c->h = c->oldh = wa.height;
196 + c->oldbw = wa.border_width;
197 + c->bw = 0;
198 + c->isfloating = True;
199 + /* reuse tags field as mapped status */
200 + c->tags = 1;
201 + updatesizehints(c);
202 + updatesystrayicongeom(c, wa.width, wa.height);
203 + XAddToSaveSet(dpy, c->win);
204 + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
205 + XReparentWindow(dpy, c->win, systray->win, 0, 0);
206 + /* use parents background color */
207 + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
208 + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
209 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
210 + /* FIXME not sure if I have to send these events, too */
211 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
212 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
213 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
214 + XSync(dpy, False);
215 + resizebarwin(selmon);
216 + updatesystray();
217 + setclientstate(c, NormalState);
218 + }
219 + return;
220 + }
221 +
222 if (!c)
223 return;
224 if (cme->message_type == netatom[NetWMState]) {
225 @@ -571,7 +659,7 @@ configurenotify(XEvent *e)
226 for (c = m->clients; c; c = c->next)
227 if (c->isfullscreen)
228 resizeclient(c, m->mx, m->my, m->mw, m->mh);
229 - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
230 + resizebarwin(m);
231 }
232 focus(NULL);
233 arrange(NULL);
234 @@ -656,6 +744,11 @@ destroynotify(XEvent *e)
235
236 if ((c = wintoclient(ev->window)))
237 unmanage(c, 1);
238 + else if ((c = wintosystrayicon(ev->window))) {
239 + removesystrayicon(c);
240 + resizebarwin(selmon);
241 + updatesystray();
242 + }
243 }
244
245 void
246 @@ -699,7 +792,7 @@ dirtomon(int dir)
247 void
248 drawbar(Monitor *m)
249 {
250 - int x, w, tw = 0;
251 + int x, w, tw = 0, stw = 0;
252 int boxs = drw->fonts->h / 9;
253 int boxw = drw->fonts->h / 6 + 2;
254 unsigned int i, occ = 0, urg = 0;
255 @@ -708,13 +801,17 @@ drawbar(Monitor *m)
256 if (!m->showbar)
257 return;
258
259 + if(showsystray && m == systraytomon(m) && !systrayonleft)
260 + stw = getsystraywidth();
261 +
262 /* draw status first so it can be overdrawn by tags later */
263 if (m == selmon) { /* status is only drawn on selected monitor */
264 drw_setscheme(drw, scheme[SchemeNorm]);
265 - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
266 - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
267 + tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */
268 + drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0);
269 }
270
271 + resizebarwin(m);
272 for (c = m->clients; c; c = c->next) {
273 occ |= c->tags;
274 if (c->isurgent)
275 @@ -735,7 +832,7 @@ drawbar(Monitor *m)
276 drw_setscheme(drw, scheme[SchemeNorm]);
277 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
278
279 - if ((w = m->ww - tw - x) > bh) {
280 + if ((w = m->ww - tw - stw - x) > bh) {
281 if (m->sel) {
282 drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
283 drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
284 @@ -746,7 +843,7 @@ drawbar(Monitor *m)
285 drw_rect(drw, x, 0, w, bh, 1, 1);
286 }
287 }
288 - drw_map(drw, m->barwin, 0, 0, m->ww, bh);
289 + drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
290 }
291
292 void
293 @@ -783,8 +880,11 @@ expose(XEvent *e)
294 Monitor *m;
295 XExposeEvent *ev = &e->xexpose;
296
297 - if (ev->count == 0 && (m = wintomon(ev->window)))
298 + if (ev->count == 0 && (m = wintomon(ev->window))) {
299 drawbar(m);
300 + if (m == selmon)
301 + updatesystray();
302 + }
303 }
304
305 void
306 @@ -870,14 +970,32 @@ getatomprop(Client *c, Atom prop)
307 unsigned char *p = NULL;
308 Atom da, atom = None;
309
310 - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
311 + /* FIXME getatomprop should return the number of items and a pointer to
312 + * the stored data instead of this workaround */
313 + Atom req = XA_ATOM;
314 + if (prop == xatom[XembedInfo])
315 + req = xatom[XembedInfo];
316 +
317 + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
318 &da, &di, &dl, &dl, &p) == Success && p) {
319 atom = *(Atom *)p;
320 + if (da == xatom[XembedInfo] && dl == 2)
321 + atom = ((Atom *)p)[1];
322 XFree(p);
323 }
324 return atom;
325 }
326
327 +unsigned int
328 +getsystraywidth()
329 +{
330 + unsigned int w = 0;
331 + Client *i;
332 + if(showsystray)
333 + for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
334 + return w ? w + systrayspacing : 1;
335 +}
336 +
337 int
338 getrootptr(int *x, int *y)
339 {
340 @@ -1018,7 +1136,8 @@ killclient(const Arg *arg)
341 {
342 if (!selmon->sel)
343 return;
344 - if (!sendevent(selmon->sel, wmatom[WMDelete])) {
345 +
346 + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
347 XGrabServer(dpy);
348 XSetErrorHandler(xerrordummy);
349 XSetCloseDownMode(dpy, DestroyAll);
350 @@ -1105,6 +1224,13 @@ maprequest(XEvent *e)
351 static XWindowAttributes wa;
352 XMapRequestEvent *ev = &e->xmaprequest;
353
354 + Client *i;
355 + if ((i = wintosystrayicon(ev->window))) {
356 + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
357 + resizebarwin(selmon);
358 + updatesystray();
359 + }
360 +
361 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
362 return;
363 if (!wintoclient(ev->window))
364 @@ -1226,6 +1352,17 @@ propertynotify(XEvent *e)
365 Window trans;
366 XPropertyEvent *ev = &e->xproperty;
367
368 + if ((c = wintosystrayicon(ev->window))) {
369 + if (ev->atom == XA_WM_NORMAL_HINTS) {
370 + updatesizehints(c);
371 + updatesystrayicongeom(c, c->w, c->h);
372 + }
373 + else
374 + updatesystrayiconstate(c, ev);
375 + resizebarwin(selmon);
376 + updatesystray();
377 + }
378 +
379 if ((ev->window == root) && (ev->atom == XA_WM_NAME))
380 updatestatus();
381 else if (ev->state == PropertyDelete)
382 @@ -1276,6 +1413,19 @@ recttomon(int x, int y, int w, int h)
383 return r;
384 }
385
386 +void
387 +removesystrayicon(Client *i)
388 +{
389 + Client **ii;
390 +
391 + if (!showsystray || !i)
392 + return;
393 + for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
394 + if (ii)
395 + *ii = i->next;
396 + free(i);
397 +}
398 +
399 void
400 resize(Client *c, int x, int y, int w, int h, int interact)
401 {
402 @@ -1283,6 +1433,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
403 resizeclient(c, x, y, w, h);
404 }
405
406 +void
407 +resizebarwin(Monitor *m) {
408 + unsigned int w = m->ww;
409 + if (showsystray && m == systraytomon(m) && !systrayonleft)
410 + w -= getsystraywidth();
411 + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
412 +}
413 +
414 void
415 resizeclient(Client *c, int x, int y, int w, int h)
416 {
417 @@ -1298,6 +1456,19 @@ resizeclient(Client *c, int x, int y, int w, int h)
418 XSync(dpy, False);
419 }
420
421 +void
422 +resizerequest(XEvent *e)
423 +{
424 + XResizeRequestEvent *ev = &e->xresizerequest;
425 + Client *i;
426 +
427 + if ((i = wintosystrayicon(ev->window))) {
428 + updatesystrayicongeom(i, ev->width, ev->height);
429 + resizebarwin(selmon);
430 + updatesystray();
431 + }
432 +}
433 +
434 void
435 resizemouse(const Arg *arg)
436 {
437 @@ -1444,26 +1615,37 @@ setclientstate(Client *c, long state)
438 }
439
440 int
441 -sendevent(Client *c, Atom proto)
442 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
443 {
444 int n;
445 - Atom *protocols;
446 + Atom *protocols, mt;
447 int exists = 0;
448 XEvent ev;
449
450 - if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
451 - while (!exists && n--)
452 - exists = protocols[n] == proto;
453 - XFree(protocols);
454 + if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
455 + mt = wmatom[WMProtocols];
456 + if (XGetWMProtocols(dpy, w, &protocols, &n)) {
457 + while (!exists && n--)
458 + exists = protocols[n] == proto;
459 + XFree(protocols);
460 + }
461 + }
462 + else {
463 + exists = True;
464 + mt = proto;
465 }
466 +
467 if (exists) {
468 ev.type = ClientMessage;
469 - ev.xclient.window = c->win;
470 - ev.xclient.message_type = wmatom[WMProtocols];
471 + ev.xclient.window = w;
472 + ev.xclient.message_type = mt;
473 ev.xclient.format = 32;
474 - ev.xclient.data.l[0] = proto;
475 - ev.xclient.data.l[1] = CurrentTime;
476 - XSendEvent(dpy, c->win, False, NoEventMask, &ev);
477 + ev.xclient.data.l[0] = d0;
478 + ev.xclient.data.l[1] = d1;
479 + ev.xclient.data.l[2] = d2;
480 + ev.xclient.data.l[3] = d3;
481 + ev.xclient.data.l[4] = d4;
482 + XSendEvent(dpy, w, False, mask, &ev);
483 }
484 return exists;
485 }
486 @@ -1477,7 +1659,7 @@ setfocus(Client *c)
487 XA_WINDOW, 32, PropModeReplace,
488 (unsigned char *) &(c->win), 1);
489 }
490 - sendevent(c, wmatom[WMTakeFocus]);
491 + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
492 }
493
494 void
495 @@ -1566,6 +1748,10 @@ setup(void)
496 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
497 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
498 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
499 + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
500 + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
501 + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
502 + netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
503 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
504 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
505 netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
506 @@ -1573,6 +1759,9 @@ setup(void)
507 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
508 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
509 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
510 + xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
511 + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
512 + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
513 /* init cursors */
514 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
515 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
516 @@ -1581,6 +1770,8 @@ setup(void)
517 scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
518 for (i = 0; i < LENGTH(colors); i++)
519 scheme[i] = drw_scm_create(drw, colors[i], 3);
520 + /* init system tray */
521 + updatesystray();
522 /* init bars */
523 updatebars();
524 updatestatus();
525 @@ -1711,7 +1902,18 @@ togglebar(const Arg *arg)
526 {
527 selmon->showbar = !selmon->showbar;
528 updatebarpos(selmon);
529 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
530 + resizebarwin(selmon);
531 + if (showsystray) {
532 + XWindowChanges wc;
533 + if (!selmon->showbar)
534 + wc.y = -bh;
535 + else if (selmon->showbar) {
536 + wc.y = 0;
537 + if (!selmon->topbar)
538 + wc.y = selmon->mh - bh;
539 + }
540 + XConfigureWindow(dpy, systray->win, CWY, &wc);
541 + }
542 arrange(selmon);
543 }
544
545 @@ -1807,11 +2009,18 @@ unmapnotify(XEvent *e)
546 else
547 unmanage(c, 0);
548 }
549 + else if ((c = wintosystrayicon(ev->window))) {
550 + /* KLUDGE! sometimes icons occasionally unmap their windows, but do
551 + * _not_ destroy them. We map those windows back */
552 + XMapRaised(dpy, c->win);
553 + updatesystray();
554 + }
555 }
556
557 void
558 updatebars(void)
559 {
560 + unsigned int w;
561 Monitor *m;
562 XSetWindowAttributes wa = {
563 .override_redirect = True,
564 @@ -1822,10 +2031,15 @@ updatebars(void)
565 for (m = mons; m; m = m->next) {
566 if (m->barwin)
567 continue;
568 - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
569 + w = m->ww;
570 + if (showsystray && m == systraytomon(m))
571 + w -= getsystraywidth();
572 + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
573 CopyFromParent, DefaultVisual(dpy, screen),
574 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
575 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
576 + if (showsystray && m == systraytomon(m))
577 + XMapRaised(dpy, systray->win);
578 XMapRaised(dpy, m->barwin);
579 XSetClassHint(dpy, m->barwin, &ch);
580 }
581 @@ -2002,6 +2216,125 @@ updatestatus(void)
582 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
583 strcpy(stext, "dwm-"VERSION);
584 drawbar(selmon);
585 + updatesystray();
586 +}
587 +
588 +
589 +void
590 +updatesystrayicongeom(Client *i, int w, int h)
591 +{
592 + if (i) {
593 + i->h = bh;
594 + if (w == h)
595 + i->w = bh;
596 + else if (h == bh)
597 + i->w = w;
598 + else
599 + i->w = (int) ((float)bh * ((float)w / (float)h));
600 + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
601 + /* force icons into the systray dimensions if they don't want to */
602 + if (i->h > bh) {
603 + if (i->w == i->h)
604 + i->w = bh;
605 + else
606 + i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
607 + i->h = bh;
608 + }
609 + }
610 +}
611 +
612 +void
613 +updatesystrayiconstate(Client *i, XPropertyEvent *ev)
614 +{
615 + long flags;
616 + int code = 0;
617 +
618 + if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
619 + !(flags = getatomprop(i, xatom[XembedInfo])))
620 + return;
621 +
622 + if (flags & XEMBED_MAPPED && !i->tags) {
623 + i->tags = 1;
624 + code = XEMBED_WINDOW_ACTIVATE;
625 + XMapRaised(dpy, i->win);
626 + setclientstate(i, NormalState);
627 + }
628 + else if (!(flags & XEMBED_MAPPED) && i->tags) {
629 + i->tags = 0;
630 + code = XEMBED_WINDOW_DEACTIVATE;
631 + XUnmapWindow(dpy, i->win);
632 + setclientstate(i, WithdrawnState);
633 + }
634 + else
635 + return;
636 + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
637 + systray->win, XEMBED_EMBEDDED_VERSION);
638 +}
639 +
640 +void
641 +updatesystray(void)
642 +{
643 + XSetWindowAttributes wa;
644 + XWindowChanges wc;
645 + Client *i;
646 + Monitor *m = systraytomon(NULL);
647 + unsigned int x = m->mx + m->mw;
648 + unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
649 + unsigned int w = 1;
650 +
651 + if (!showsystray)
652 + return;
653 + if (systrayonleft)
654 + x -= sw + lrpad / 2;
655 + if (!systray) {
656 + /* init systray */
657 + if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
658 + die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
659 + systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
660 + wa.event_mask = ButtonPressMask | ExposureMask;
661 + wa.override_redirect = True;
662 + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
663 + XSelectInput(dpy, systray->win, SubstructureNotifyMask);
664 + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
665 + PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
666 + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
667 + XMapRaised(dpy, systray->win);
668 + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
669 + if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
670 + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
671 + XSync(dpy, False);
672 + }
673 + else {
674 + fprintf(stderr, "dwm: unable to obtain system tray.\n");
675 + free(systray);
676 + systray = NULL;
677 + return;
678 + }
679 + }
680 + for (w = 0, i = systray->icons; i; i = i->next) {
681 + /* make sure the background color stays the same */
682 + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
683 + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
684 + XMapRaised(dpy, i->win);
685 + w += systrayspacing;
686 + i->x = w;
687 + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
688 + w += i->w;
689 + if (i->mon != m)
690 + i->mon = m;
691 + }
692 + w = w ? w + systrayspacing : 1;
693 + x -= w;
694 + XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
695 + wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
696 + wc.stack_mode = Above; wc.sibling = m->barwin;
697 + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
698 + XMapWindow(dpy, systray->win);
699 + XMapSubwindows(dpy, systray->win);
700 + /* redraw background */
701 + XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
702 + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
703 + XSync(dpy, False);
704 }
705
706 void
707 @@ -2069,6 +2402,16 @@ wintoclient(Window w)
708 return NULL;
709 }
710
711 +Client *
712 +wintosystrayicon(Window w) {
713 + Client *i = NULL;
714 +
715 + if (!showsystray || !w)
716 + return i;
717 + for (i = systray->icons; i && i->win != w; i = i->next) ;
718 + return i;
719 +}
720 +
721 Monitor *
722 wintomon(Window w)
723 {
724 @@ -2122,6 +2465,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
725 return -1;
726 }
727
728 +Monitor *
729 +systraytomon(Monitor *m) {
730 + Monitor *t;
731 + int i, n;
732 + if(!systraypinning) {
733 + if(!m)
734 + return selmon;
735 + return m == selmon ? m : NULL;
736 + }
737 + for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
738 + for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
739 + if(systraypinningfailfirst && n < systraypinning)
740 + return mons;
741 + return t;
742 +}
743 +
744 void
745 zoom(const Arg *arg)
746 {