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