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