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