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