dwm-status2d-barpadding-systray-20241014-b663875.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
dwm-status2d-barpadding-systray-20241014-b663875.diff (29414B)
---
1 From b663875b9f4ed4357403ae340b312d38ce071f00 Mon Sep 17 00:00:00 2001
2 From: elbachir-one <bachiralfa@gmail.com>
3 Date: Mon, 14 Oct 2024 17:39:18 +0100
4 Subject: [PATCH] (Status2d + Barpadding + Systray) all patched together
5
6 ---
7 config.def.h | 8 +-
8 dwm.c | 561 +++++++++++++++++++++++++++++++++++++++++++++++----
9 2 files changed, 527 insertions(+), 42 deletions(-)
10
11 diff --git a/config.def.h b/config.def.h
12 index 9efa774..b3265b4 100644
13 --- a/config.def.h
14 +++ b/config.def.h
15 @@ -3,6 +3,13 @@
16 /* appearance */
17 static const unsigned int borderpx = 1; /* border pixel of windows */
18 static const unsigned int snap = 32; /* snap pixel */
19 +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
20 +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */
21 +static const unsigned int systrayspacing = 2; /* systray spacing */
22 +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
23 +static const int showsystray = 1; /* 0 means no systray */
24 +static const int vertpad = 10; /* vertical padding of bar */
25 +static const int sidepad = 10; /* horizontal padding of bar */
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 @@ -113,4 +120,3 @@ static const Button buttons[] = {
30 { ClkTagBar, MODKEY, Button1, tag, {0} },
31 { ClkTagBar, MODKEY, Button3, toggletag, {0} },
32 };
33 -
34 diff --git a/dwm.c b/dwm.c
35 index 1443802..8802de0 100644
36 --- a/dwm.c
37 +++ b/dwm.c
38 @@ -56,12 +56,27 @@
39 #define TAGMASK ((1 << LENGTH(tags)) - 1)
40 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
41
42 +#define SYSTEM_TRAY_REQUEST_DOCK 0
43 +/* XEMBED messages */
44 +#define XEMBED_EMBEDDED_NOTIFY 0
45 +#define XEMBED_WINDOW_ACTIVATE 1
46 +#define XEMBED_FOCUS_IN 4
47 +#define XEMBED_MODALITY_ON 10
48 +#define XEMBED_MAPPED (1 << 0)
49 +#define XEMBED_WINDOW_ACTIVATE 1
50 +#define XEMBED_WINDOW_DEACTIVATE 2
51 +#define VERSION_MAJOR 0
52 +#define VERSION_MINOR 0
53 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
54 +
55 /* enums */
56 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
57 enum { SchemeNorm, SchemeSel }; /* color schemes */
58 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
59 + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
60 NetWMFullscreen, NetActiveWindow, NetWMWindowType,
61 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
62 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
63 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
64 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
65 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
66 @@ -140,6 +155,12 @@ typedef struct {
67 int monitor;
68 } Rule;
69
70 +typedef struct Systray Systray;
71 +struct Systray {
72 + Window win;
73 + Client *icons;
74 +};
75 +
76 /* function declarations */
77 static void applyrules(Client *c);
78 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
79 @@ -162,6 +183,7 @@ static void detachstack(Client *c);
80 static Monitor *dirtomon(int dir);
81 static void drawbar(Monitor *m);
82 static void drawbars(void);
83 +static int drawstatusbar(Monitor *m, int bh, char* text);
84 static void enternotify(XEvent *e);
85 static void expose(XEvent *e);
86 static void focus(Client *c);
87 @@ -171,6 +193,7 @@ static void focusstack(const Arg *arg);
88 static Atom getatomprop(Client *c, Atom prop);
89 static int getrootptr(int *x, int *y);
90 static long getstate(Window w);
91 +static unsigned int getsystraywidth();
92 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
93 static void grabbuttons(Client *c, int focused);
94 static void grabkeys(void);
95 @@ -188,13 +211,16 @@ static void pop(Client *c);
96 static void propertynotify(XEvent *e);
97 static void quit(const Arg *arg);
98 static Monitor *recttomon(int x, int y, int w, int h);
99 +static void removesystrayicon(Client *i);
100 static void resize(Client *c, int x, int y, int w, int h, int interact);
101 +static void resizebarwin(Monitor *m);
102 static void resizeclient(Client *c, int x, int y, int w, int h);
103 static void resizemouse(const Arg *arg);
104 +static void resizerequest(XEvent *e);
105 static void restack(Monitor *m);
106 static void run(void);
107 static void scan(void);
108 -static int sendevent(Client *c, Atom proto);
109 +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
110 static void sendmon(Client *c, Monitor *m);
111 static void setclientstate(Client *c, long state);
112 static void setfocus(Client *c);
113 @@ -205,6 +231,7 @@ static void setup(void);
114 static void seturgent(Client *c, int urg);
115 static void showhide(Client *c);
116 static void spawn(const Arg *arg);
117 +static Monitor *systraytomon(Monitor *m);
118 static void tag(const Arg *arg);
119 static void tagmon(const Arg *arg);
120 static void tile(Monitor *m);
121 @@ -222,24 +249,31 @@ static int updategeom(void);
122 static void updatenumlockmask(void);
123 static void updatesizehints(Client *c);
124 static void updatestatus(void);
125 +static void updatesystray(void);
126 +static void updatesystrayicongeom(Client *i, int w, int h);
127 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
128 static void updatetitle(Client *c);
129 static void updatewindowtype(Client *c);
130 static void updatewmhints(Client *c);
131 static void view(const Arg *arg);
132 static Client *wintoclient(Window w);
133 static Monitor *wintomon(Window w);
134 +static Client *wintosystrayicon(Window w);
135 static int xerror(Display *dpy, XErrorEvent *ee);
136 static int xerrordummy(Display *dpy, XErrorEvent *ee);
137 static int xerrorstart(Display *dpy, XErrorEvent *ee);
138 static void zoom(const Arg *arg);
139
140 /* variables */
141 +static Systray *systray = NULL;
142 static const char broken[] = "broken";
143 -static char stext[256];
144 +static char stext[1024];
145 static int screen;
146 static int sw, sh; /* X display screen geometry width, height */
147 static int bh; /* bar height */
148 static int lrpad; /* sum of left and right padding for text */
149 +static int vp; /* vertical padding for bar */
150 +static int sp; /* side padding for bar */
151 static int (*xerrorxlib)(Display *, XErrorEvent *);
152 static unsigned int numlockmask = 0;
153 static void (*handler[LASTEvent]) (XEvent *) = {
154 @@ -256,9 +290,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
155 [MapRequest] = maprequest,
156 [MotionNotify] = motionnotify,
157 [PropertyNotify] = propertynotify,
158 + [ResizeRequest] = resizerequest,
159 [UnmapNotify] = unmapnotify
160 };
161 -static Atom wmatom[WMLast], netatom[NetLast];
162 +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
163 static int running = 1;
164 static Cur *cursor[CurLast];
165 static Clr **scheme;
166 @@ -440,7 +475,7 @@ buttonpress(XEvent *e)
167 arg.ui = 1 << i;
168 } else if (ev->x < x + TEXTW(selmon->ltsymbol))
169 click = ClkLtSymbol;
170 - else if (ev->x > selmon->ww - (int)TEXTW(stext))
171 + else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
172 click = ClkStatusText;
173 else
174 click = ClkWinTitle;
175 @@ -483,9 +518,16 @@ cleanup(void)
176 XUngrabKey(dpy, AnyKey, AnyModifier, root);
177 while (mons)
178 cleanupmon(mons);
179 - for (i = 0; i < CurLast; i++)
180 +
181 + if (showsystray) {
182 + XUnmapWindow(dpy, systray->win);
183 + XDestroyWindow(dpy, systray->win);
184 + free(systray);
185 + }
186 +
187 + for (i = 0; i < CurLast; i++)
188 drw_cur_free(drw, cursor[i]);
189 - for (i = 0; i < LENGTH(colors); i++)
190 + for (i = 0; i < LENGTH(colors) + 1; i++)
191 free(scheme[i]);
192 free(scheme);
193 XDestroyWindow(dpy, wmcheckwin);
194 @@ -514,9 +556,58 @@ cleanupmon(Monitor *mon)
195 void
196 clientmessage(XEvent *e)
197 {
198 + XWindowAttributes wa;
199 + XSetWindowAttributes swa;
200 XClientMessageEvent *cme = &e->xclient;
201 Client *c = wintoclient(cme->window);
202
203 + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
204 + /* add systray icons */
205 + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
206 + if (!(c = (Client *)calloc(1, sizeof(Client))))
207 + die("fatal: could not malloc() %u bytes\n", sizeof(Client));
208 + if (!(c->win = cme->data.l[2])) {
209 + free(c);
210 + return;
211 + }
212 + c->mon = selmon;
213 + c->next = systray->icons;
214 + systray->icons = c;
215 + if (!XGetWindowAttributes(dpy, c->win, &wa)) {
216 + /* use sane defaults */
217 + wa.width = bh;
218 + wa.height = bh;
219 + wa.border_width = 0;
220 + }
221 + c->x = c->oldx = c->y = c->oldy = 0;
222 + c->w = c->oldw = wa.width;
223 + c->h = c->oldh = wa.height;
224 + c->oldbw = wa.border_width;
225 + c->bw = 0;
226 + c->isfloating = True;
227 + /* reuse tags field as mapped status */
228 + c->tags = 1;
229 + updatesizehints(c);
230 + updatesystrayicongeom(c, wa.width, wa.height);
231 + XAddToSaveSet(dpy, c->win);
232 + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
233 + XReparentWindow(dpy, c->win, systray->win, 0, 0);
234 + /* use parents background color */
235 + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
236 + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
237 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
238 + /* FIXME not sure if I have to send these events, too */
239 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
240 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
241 + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
242 + XSync(dpy, False);
243 + resizebarwin(selmon);
244 + updatesystray();
245 + setclientstate(c, NormalState);
246 + }
247 + return;
248 + }
249 +
250 if (!c)
251 return;
252 if (cme->message_type == netatom[NetWMState]) {
253 @@ -569,7 +660,7 @@ configurenotify(XEvent *e)
254 for (c = m->clients; c; c = c->next)
255 if (c->isfullscreen)
256 resizeclient(c, m->mx, m->my, m->mw, m->mh);
257 - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
258 + resizebarwin(m);
259 }
260 focus(NULL);
261 arrange(NULL);
262 @@ -654,6 +745,11 @@ destroynotify(XEvent *e)
263
264 if ((c = wintoclient(ev->window)))
265 unmanage(c, 1);
266 + else if ((c = wintosystrayicon(ev->window))) {
267 + removesystrayicon(c);
268 + resizebarwin(selmon);
269 + updatesystray();
270 + }
271 }
272
273 void
274 @@ -694,10 +790,119 @@ dirtomon(int dir)
275 return m;
276 }
277
278 +int
279 +drawstatusbar(Monitor *m, int bh, char* stext) {
280 + int ret, i, w, x, len;
281 + short isCode = 0;
282 + char *text;
283 + char *p;
284 +
285 + len = strlen(stext) + 1 ;
286 + if (!(text = (char*) malloc(sizeof(char)*len)))
287 + die("malloc");
288 + p = text;
289 + memcpy(text, stext, len);
290 +
291 + /* compute width of the status text */
292 + w = 0;
293 + i = -1;
294 + while (text[++i]) {
295 + if (text[i] == '^') {
296 + if (!isCode) {
297 + isCode = 1;
298 + text[i] = '\0';
299 + w += TEXTW(text) - lrpad;
300 + text[i] = '^';
301 + if (text[++i] == 'f')
302 + w += atoi(text + ++i);
303 + } else {
304 + isCode = 0;
305 + text = text + i + 1;
306 + i = -1;
307 + }
308 + }
309 + }
310 + if (!isCode)
311 + w += TEXTW(text) - lrpad;
312 + else
313 + isCode = 0;
314 + text = p;
315 +
316 + w += lrpad; /* 1px padding on both sides */
317 + ret = m->ww - w;
318 + x = m->ww - w - getsystraywidth();
319 +
320 + drw_setscheme(drw, scheme[LENGTH(colors)]);
321 + drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
322 + drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
323 + drw_rect(drw, x - 2 * sp, 0, w, bh, 1, 1);
324 + x += lrpad / 2;
325 +
326 + /* process status text */
327 + i = -1;
328 + while (text[++i]) {
329 + if (text[i] == '^' && !isCode) {
330 + isCode = 1;
331 +
332 + text[i] = '\0';
333 + w = TEXTW(text) - lrpad;
334 + drw_text(drw, x - 2 * sp, vp / 2, w, bh - vp, 0, text, 0);
335 +
336 + x += w;
337 +
338 + /* process code */
339 + while (text[++i] != '^') {
340 + if (text[i] == 'c') {
341 + char buf[8];
342 + memcpy(buf, (char*)text+i+1, 7);
343 + buf[7] = '\0';
344 + drw_clr_create(drw, &drw->scheme[ColFg], buf);
345 + i += 7;
346 + } else if (text[i] == 'b') {
347 + char buf[8];
348 + memcpy(buf, (char*)text+i+1, 7);
349 + buf[7] = '\0';
350 + drw_clr_create(drw, &drw->scheme[ColBg], buf);
351 + i += 7;
352 + } else if (text[i] == 'd') {
353 + drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
354 + drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
355 + } else if (text[i] == 'r') {
356 + int rx = atoi(text + ++i);
357 + while (text[++i] != ',');
358 + int ry = atoi(text + ++i);
359 + while (text[++i] != ',');
360 + int rw = atoi(text + ++i);
361 + while (text[++i] != ',');
362 + int rh = atoi(text + ++i);
363 +
364 + drw_rect(drw, rx +x - 2 * sp, ry + vp / 2, rw, MIN(rh, bh - vp), 1, 0);
365 + } else if (text[i] == 'f') {
366 + x += atoi(text + ++i);
367 + }
368 + }
369 +
370 + text = text + i + 1;
371 + i=-1;
372 + isCode = 0;
373 + }
374 + }
375 +
376 + if (!isCode) {
377 + w = TEXTW(text) - lrpad;
378 + drw_text(drw, x - 2 * sp, 0, w, bh, 0, text, 0);
379 + }
380 +
381 + drw_setscheme(drw, scheme[SchemeNorm]);
382 + free(p);
383 +
384 + return ret;
385 +}
386 +
387 void
388 drawbar(Monitor *m)
389 {
390 - int x, w, tw = 0;
391 + int x, w, tw = 0, stw = 0;
392 int boxs = drw->fonts->h / 9;
393 int boxw = drw->fonts->h / 6 + 2;
394 unsigned int i, occ = 0, urg = 0;
395 @@ -706,13 +911,15 @@ drawbar(Monitor *m)
396 if (!m->showbar)
397 return;
398
399 + if(showsystray && m == systraytomon(m) && !systrayonleft)
400 + stw = getsystraywidth();
401 +
402 /* draw status first so it can be overdrawn by tags later */
403 if (m == selmon) { /* status is only drawn on selected monitor */
404 - drw_setscheme(drw, scheme[SchemeNorm]);
405 - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
406 - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
407 + tw = m->ww - drawstatusbar(m, bh, stext);
408 }
409
410 + resizebarwin(m);
411 for (c = m->clients; c; c = c->next) {
412 occ |= c->tags;
413 if (c->isurgent)
414 @@ -733,18 +940,18 @@ drawbar(Monitor *m)
415 drw_setscheme(drw, scheme[SchemeNorm]);
416 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
417
418 - if ((w = m->ww - tw - x) > bh) {
419 + if ((w = m->ww - tw - stw - x) > bh) {
420 if (m->sel) {
421 drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
422 - drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
423 + drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
424 if (m->sel->isfloating)
425 drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
426 } else {
427 drw_setscheme(drw, scheme[SchemeNorm]);
428 - drw_rect(drw, x, 0, w, bh, 1, 1);
429 + drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
430 }
431 }
432 - drw_map(drw, m->barwin, 0, 0, m->ww, bh);
433 + drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
434 }
435
436 void
437 @@ -781,8 +988,11 @@ expose(XEvent *e)
438 Monitor *m;
439 XExposeEvent *ev = &e->xexpose;
440
441 - if (ev->count == 0 && (m = wintomon(ev->window)))
442 + if (ev->count == 0 && (m = wintomon(ev->window))) {
443 drawbar(m);
444 + if (m == selmon)
445 + updatesystray();
446 + }
447 }
448
449 void
450 @@ -868,9 +1078,17 @@ getatomprop(Client *c, Atom prop)
451 unsigned char *p = NULL;
452 Atom da, atom = None;
453
454 - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
455 + /* FIXME getatomprop should return the number of items and a pointer to
456 + * the stored data instead of this workaround */
457 + Atom req = XA_ATOM;
458 + if (prop == xatom[XembedInfo])
459 + req = xatom[XembedInfo];
460 +
461 + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
462 &da, &di, &dl, &dl, &p) == Success && p) {
463 atom = *(Atom *)p;
464 + if (da == xatom[XembedInfo] && dl == 2)
465 + atom = ((Atom *)p)[1];
466 XFree(p);
467 }
468 return atom;
469 @@ -904,6 +1122,16 @@ getstate(Window w)
470 return result;
471 }
472
473 +unsigned int
474 +getsystraywidth()
475 +{
476 + unsigned int w = 0;
477 + Client *i;
478 + if(showsystray)
479 + for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
480 + return w ? w + systrayspacing : 1;
481 +}
482 +
483 int
484 gettextprop(Window w, Atom atom, char *text, unsigned int size)
485 {
486 @@ -1016,7 +1244,8 @@ killclient(const Arg *arg)
487 {
488 if (!selmon->sel)
489 return;
490 - if (!sendevent(selmon->sel, wmatom[WMDelete])) {
491 +
492 + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
493 XGrabServer(dpy);
494 XSetErrorHandler(xerrordummy);
495 XSetCloseDownMode(dpy, DestroyAll);
496 @@ -1103,6 +1332,14 @@ maprequest(XEvent *e)
497 static XWindowAttributes wa;
498 XMapRequestEvent *ev = &e->xmaprequest;
499
500 + Client *i;
501 + if ((i = wintosystrayicon(ev->window))) {
502 + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
503 + resizebarwin(selmon);
504 + updatesystray();
505 + }
506 +
507 +
508 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
509 return;
510 if (!wintoclient(ev->window))
511 @@ -1224,7 +1461,18 @@ propertynotify(XEvent *e)
512 Window trans;
513 XPropertyEvent *ev = &e->xproperty;
514
515 - if ((ev->window == root) && (ev->atom == XA_WM_NAME))
516 + if ((c = wintosystrayicon(ev->window))) {
517 + if (ev->atom == XA_WM_NORMAL_HINTS) {
518 + updatesizehints(c);
519 + updatesystrayicongeom(c, c->w, c->h);
520 + }
521 + else
522 + updatesystrayiconstate(c, ev);
523 + resizebarwin(selmon);
524 + updatesystray();
525 + }
526 +
527 + if ((ev->window == root) && (ev->atom == XA_WM_NAME))
528 updatestatus();
529 else if (ev->state == PropertyDelete)
530 return; /* ignore */
531 @@ -1274,6 +1522,19 @@ recttomon(int x, int y, int w, int h)
532 return r;
533 }
534
535 +void
536 +removesystrayicon(Client *i)
537 +{
538 + Client **ii;
539 +
540 + if (!showsystray || !i)
541 + return;
542 + for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
543 + if (ii)
544 + *ii = i->next;
545 + free(i);
546 +}
547 +
548 void
549 resize(Client *c, int x, int y, int w, int h, int interact)
550 {
551 @@ -1281,6 +1542,15 @@ resize(Client *c, int x, int y, int w, int h, int interact)
552 resizeclient(c, x, y, w, h);
553 }
554
555 +void
556 +resizebarwin(Monitor *m) {
557 + unsigned int w = m->ww;
558 + if (showsystray && m == systraytomon(m) && !systrayonleft)
559 + w -= getsystraywidth();
560 + XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
561 +
562 +}
563 +
564 void
565 resizeclient(Client *c, int x, int y, int w, int h)
566 {
567 @@ -1353,6 +1623,19 @@ resizemouse(const Arg *arg)
568 }
569 }
570
571 +void
572 +resizerequest(XEvent *e)
573 +{
574 + XResizeRequestEvent *ev = &e->xresizerequest;
575 + Client *i;
576 +
577 + if ((i = wintosystrayicon(ev->window))) {
578 + updatesystrayicongeom(i, ev->width, ev->height);
579 + resizebarwin(selmon);
580 + updatesystray();
581 + }
582 +}
583 +
584 void
585 restack(Monitor *m)
586 {
587 @@ -1442,26 +1725,37 @@ setclientstate(Client *c, long state)
588 }
589
590 int
591 -sendevent(Client *c, Atom proto)
592 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
593 {
594 int n;
595 - Atom *protocols;
596 + Atom *protocols, mt;
597 int exists = 0;
598 XEvent ev;
599
600 - if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
601 - while (!exists && n--)
602 - exists = protocols[n] == proto;
603 - XFree(protocols);
604 + if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
605 + mt = wmatom[WMProtocols];
606 + if (XGetWMProtocols(dpy, w, &protocols, &n)) {
607 + while (!exists && n--)
608 + exists = protocols[n] == proto;
609 + XFree(protocols);
610 + }
611 }
612 + else {
613 + exists = True;
614 + mt = proto;
615 + }
616 +
617 if (exists) {
618 ev.type = ClientMessage;
619 - ev.xclient.window = c->win;
620 - ev.xclient.message_type = wmatom[WMProtocols];
621 + ev.xclient.window = w;
622 + ev.xclient.message_type = mt;
623 ev.xclient.format = 32;
624 - ev.xclient.data.l[0] = proto;
625 - ev.xclient.data.l[1] = CurrentTime;
626 - XSendEvent(dpy, c->win, False, NoEventMask, &ev);
627 + ev.xclient.data.l[0] = d0;
628 + ev.xclient.data.l[1] = d1;
629 + ev.xclient.data.l[2] = d2;
630 + ev.xclient.data.l[3] = d3;
631 + ev.xclient.data.l[4] = d4;
632 + XSendEvent(dpy, w, False, mask, &ev);
633 }
634 return exists;
635 }
636 @@ -1475,7 +1769,7 @@ setfocus(Client *c)
637 XA_WINDOW, 32, PropModeReplace,
638 (unsigned char *) &(c->win), 1);
639 }
640 - sendevent(c, wmatom[WMTakeFocus]);
641 + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
642 }
643
644 void
645 @@ -1562,7 +1856,10 @@ setup(void)
646 die("no fonts could be loaded.");
647 lrpad = drw->fonts->h;
648 bh = drw->fonts->h + 2;
649 + sp = sidepad;
650 + vp = (topbar == 1) ? vertpad : - vertpad;
651 updategeom();
652 +
653 /* init atoms */
654 utf8string = XInternAtom(dpy, "UTF8_STRING", False);
655 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
656 @@ -1570,22 +1867,32 @@ setup(void)
657 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
658 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
659 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
660 - netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
661 - netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
662 + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
663 + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
664 + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
665 + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
666 + netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
667 + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
668 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
669 netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
670 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
671 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
672 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
673 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
674 - /* init cursors */
675 + xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
676 + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
677 + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
678 + /* init cursors */
679 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
680 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
681 cursor[CurMove] = drw_cur_create(drw, XC_fleur);
682 /* init appearance */
683 - scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
684 + scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
685 + scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
686 for (i = 0; i < LENGTH(colors); i++)
687 scheme[i] = drw_scm_create(drw, colors[i], 3);
688 + /* init system tray */
689 + updatesystray();
690 /* init bars */
691 updatebars();
692 updatestatus();
693 @@ -1716,7 +2023,19 @@ togglebar(const Arg *arg)
694 {
695 selmon->showbar = !selmon->showbar;
696 updatebarpos(selmon);
697 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
698 + resizebarwin(selmon);
699 + if (showsystray) {
700 + XWindowChanges wc;
701 + if (!selmon->showbar)
702 + wc.y = -bh;
703 + else if (selmon->showbar) {
704 + wc.y = 0;
705 + if (!selmon->topbar)
706 + wc.y = selmon->mh - bh;
707 + }
708 + XConfigureWindow(dpy, systray->win, CWY, &wc);
709 + }
710 + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
711 arrange(selmon);
712 }
713
714 @@ -1812,11 +2131,18 @@ unmapnotify(XEvent *e)
715 else
716 unmanage(c, 0);
717 }
718 + else if ((c = wintosystrayicon(ev->window))) {
719 + /* KLUDGE! sometimes icons occasionally unmap their windows, but do
720 + * _not_ destroy them. We map those windows back */
721 + XMapRaised(dpy, c->win);
722 + updatesystray();
723 + }
724 }
725
726 void
727 updatebars(void)
728 {
729 + unsigned int w;
730 Monitor *m;
731 XSetWindowAttributes wa = {
732 .override_redirect = True,
733 @@ -1827,10 +2153,15 @@ updatebars(void)
734 for (m = mons; m; m = m->next) {
735 if (m->barwin)
736 continue;
737 - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
738 + w = m->ww;
739 + if (showsystray && m == systraytomon(m))
740 + w -= getsystraywidth();
741 + m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen),
742 CopyFromParent, DefaultVisual(dpy, screen),
743 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
744 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
745 + if (showsystray && m == systraytomon(m))
746 + XMapRaised(dpy, systray->win);
747 XMapRaised(dpy, m->barwin);
748 XSetClassHint(dpy, m->barwin, &ch);
749 }
750 @@ -1842,11 +2173,11 @@ updatebarpos(Monitor *m)
751 m->wy = m->my;
752 m->wh = m->mh;
753 if (m->showbar) {
754 - m->wh -= bh;
755 - m->by = m->topbar ? m->wy : m->wy + m->wh;
756 - m->wy = m->topbar ? m->wy + bh : m->wy;
757 + m->wh = m->wh - vertpad - bh;
758 + m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
759 + m->wy = m->topbar ? m->wy + bh + vp : m->wy;
760 } else
761 - m->by = -bh;
762 + m->by = -bh - vp;
763 }
764
765 void
766 @@ -2007,6 +2338,128 @@ updatestatus(void)
767 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
768 strcpy(stext, "dwm-"VERSION);
769 drawbar(selmon);
770 + updatesystray();
771 +}
772 +
773 +
774 +void
775 +updatesystrayicongeom(Client *i, int w, int h)
776 +{
777 + if (i) {
778 + i->h = bh;
779 + if (w == h)
780 + i->w = bh;
781 + else if (h == bh)
782 + i->w = w;
783 + else
784 + i->w = (int) ((float)bh * ((float)w / (float)h));
785 + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
786 + /* force icons into the systray dimensions if they don't want to */
787 + if (i->h > bh) {
788 + if (i->w == i->h)
789 + i->w = bh;
790 + else
791 + i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
792 + i->h = bh;
793 + }
794 + }
795 +}
796 +
797 +void
798 +updatesystrayiconstate(Client *i, XPropertyEvent *ev)
799 +{
800 + long flags;
801 + int code = 0;
802 +
803 + if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
804 + !(flags = getatomprop(i, xatom[XembedInfo])))
805 + return;
806 +
807 + if (flags & XEMBED_MAPPED && !i->tags) {
808 + i->tags = 1;
809 + code = XEMBED_WINDOW_ACTIVATE;
810 + XMapRaised(dpy, i->win);
811 + setclientstate(i, NormalState);
812 + }
813 + else if (!(flags & XEMBED_MAPPED) && i->tags) {
814 + i->tags = 0;
815 + code = XEMBED_WINDOW_DEACTIVATE;
816 + XUnmapWindow(dpy, i->win);
817 + setclientstate(i, WithdrawnState);
818 + }
819 + else
820 + return;
821 + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
822 + systray->win, XEMBED_EMBEDDED_VERSION);
823 +}
824 +
825 +void
826 +updatesystray(void)
827 +{
828 + XSetWindowAttributes wa;
829 + XWindowChanges wc;
830 + Client *i;
831 + Monitor *m = systraytomon(NULL);
832 + unsigned int x = m->mx + m->mw;
833 + unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
834 + unsigned int w = 1;
835 +
836 + if (!showsystray)
837 + return;
838 + if (systrayonleft)
839 + x -= sw + lrpad / 2;
840 + if (!systray) {
841 + /* init systray */
842 + if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
843 + die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
844 + systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
845 + wa.event_mask = ButtonPressMask | ExposureMask;
846 + wa.override_redirect = True;
847 + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
848 + XSelectInput(dpy, systray->win, SubstructureNotifyMask);
849 + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
850 + PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
851 + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
852 + XMapRaised(dpy, systray->win);
853 + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
854 + if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
855 + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
856 + XSync(dpy, False);
857 + }
858 + else {
859 + fprintf(stderr, "dwm: unable to obtain system tray.\n");
860 + free(systray);
861 + systray = NULL;
862 + return;
863 + }
864 + }
865 + for (w = 0, i = systray->icons; i; i = i->next) {
866 + /* make sure the background color stays the same */
867 + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
868 + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
869 + XMapRaised(dpy, i->win);
870 + w += systrayspacing;
871 + i->x = w;
872 + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
873 + w += i->w;
874 + if (i->mon != m)
875 + i->mon = m;
876 + }
877 + w = w ? w + systrayspacing : 1;
878 + x -= w;
879 + XMoveResizeWindow(dpy, systray->win, x - sp, m->by + vp, w, bh);
880 + wc.x = x - sp;
881 + wc.y = m->by + vp;
882 + wc.width = w;
883 + wc.height = bh;
884 + wc.stack_mode = Above; wc.sibling = m->barwin;
885 + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
886 + XMapWindow(dpy, systray->win);
887 + XMapSubwindows(dpy, systray->win);
888 + /* redraw background */
889 + XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
890 + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
891 + XSync(dpy, False);
892 }
893
894 void
895 @@ -2074,6 +2527,16 @@ wintoclient(Window w)
896 return NULL;
897 }
898
899 +Client *
900 +wintosystrayicon(Window w) {
901 + Client *i = NULL;
902 +
903 + if (!showsystray || !w)
904 + return i;
905 + for (i = systray->icons; i && i->win != w; i = i->next) ;
906 + return i;
907 +}
908 +
909 Monitor *
910 wintomon(Window w)
911 {
912 @@ -2127,6 +2590,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
913 return -1;
914 }
915
916 +Monitor *
917 +systraytomon(Monitor *m) {
918 + Monitor *t;
919 + int i, n;
920 + if(!systraypinning) {
921 + if(!m)
922 + return selmon;
923 + return m == selmon ? m : NULL;
924 + }
925 + for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
926 + for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
927 + if(systraypinningfailfirst && n < systraypinning)
928 + return mons;
929 + return t;
930 +}
931 +
932 void
933 zoom(const Arg *arg)
934 {
935 --
936 2.46.2
937