dwm-git-20130119-systray.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-git-20130119-systray.diff (20248B) | |
--- | |
1 Author: Jan Christoph Ebersbach <[email protected]>, inspired by http://code.… | |
2 URL: http://dwm.suckless.org/patches/systray | |
3 Implements a system tray for dwm. | |
4 | |
5 diff -r c794a9f5ae5e config.def.h | |
6 --- a/config.def.h Sun Jul 08 09:45:53 2012 +0200 | |
7 +++ b/config.def.h Sat Aug 18 13:28:31 2012 +0200 | |
8 @@ -10,6 +10,8 @@ | |
9 static const char selfgcolor[] = "#eeeeee"; | |
10 static const unsigned int borderpx = 1; /* border pixel of wind… | |
11 static const unsigned int snap = 32; /* snap pixel */ | |
12 +static const unsigned int systrayspacing = 2; /* systray spacing */ | |
13 +static const Bool showsystray = True; /* False means no systr… | |
14 static const Bool showbar = True; /* False means no bar */ | |
15 static const Bool topbar = True; /* False means bottom b… | |
16 | |
17 diff -r c794a9f5ae5e dwm.c | |
18 --- a/dwm.c Sun Jul 08 09:45:53 2012 +0200 | |
19 +++ b/dwm.c Sat Aug 18 13:28:31 2012 +0200 | |
20 @@ -56,12 +56,30 @@ | |
21 #define TAGMASK ((1 << LENGTH(tags)) - 1) | |
22 #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height) | |
23 | |
24 +#define SYSTEM_TRAY_REQUEST_DOCK 0 | |
25 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 | |
26 + | |
27 +/* XEMBED messages */ | |
28 +#define XEMBED_EMBEDDED_NOTIFY 0 | |
29 +#define XEMBED_WINDOW_ACTIVATE 1 | |
30 +#define XEMBED_FOCUS_IN 4 | |
31 +#define XEMBED_MODALITY_ON 10 | |
32 + | |
33 +#define XEMBED_MAPPED (1 << 0) | |
34 +#define XEMBED_WINDOW_ACTIVATE 1 | |
35 +#define XEMBED_WINDOW_DEACTIVATE 2 | |
36 + | |
37 +#define VERSION_MAJOR 0 | |
38 +#define VERSION_MINOR 0 | |
39 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR | |
40 + | |
41 /* enums */ | |
42 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |
43 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ | |
44 -enum { NetSupported, NetWMName, NetWMState, | |
45 - NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
46 - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH ato… | |
47 +enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrien… | |
48 + NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, Net… | |
49 + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH ato… | |
50 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ | |
51 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* defaul… | |
52 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
53 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ | |
54 @@ -155,6 +173,12 @@ | |
55 int monitor; | |
56 } Rule; | |
57 | |
58 +typedef struct Systray Systray; | |
59 +struct Systray { | |
60 + Window win; | |
61 + Client *icons; | |
62 +}; | |
63 + | |
64 /* function declarations */ | |
65 static void applyrules(Client *c); | |
66 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, B… | |
67 @@ -187,9 +211,11 @@ | |
68 static void focusin(XEvent *e); | |
69 static void focusmon(const Arg *arg); | |
70 static void focusstack(const Arg *arg); | |
71 +static Atom getatomprop(Client *c, Atom prop); | |
72 static unsigned long getcolor(const char *colstr); | |
73 static Bool getrootptr(int *x, int *y); | |
74 static long getstate(Window w); | |
75 +static unsigned int getsystraywidth(); | |
76 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int s… | |
77 static void grabbuttons(Client *c, Bool focused); | |
78 static void grabkeys(void); | |
79 @@ -208,13 +234,16 @@ | |
80 static void propertynotify(XEvent *e); | |
81 static void quit(const Arg *arg); | |
82 static Monitor *recttomon(int x, int y, int w, int h); | |
83 +static void removesystrayicon(Client *i); | |
84 static void resize(Client *c, int x, int y, int w, int h, Bool interact… | |
85 +static void resizebarwin(Monitor *m); | |
86 static void resizeclient(Client *c, int x, int y, int w, int h); | |
87 static void resizemouse(const Arg *arg); | |
88 +static void resizerequest(XEvent *e); | |
89 static void restack(Monitor *m); | |
90 static void run(void); | |
91 static void scan(void); | |
92 -static Bool sendevent(Client *c, Atom proto); | |
93 +static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, lo… | |
94 static void sendmon(Client *c, Monitor *m); | |
95 static void setclientstate(Client *c, long state); | |
96 static void setfocus(Client *c); | |
97 @@ -243,18 +272,24 @@ | |
98 static void updatenumlockmask(void); | |
99 static void updatesizehints(Client *c); | |
100 static void updatestatus(void); | |
101 +static void updatesystray(void); | |
102 +static void updatesystrayicongeom(Client *i, int w, int h); | |
103 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); | |
104 static void updatewindowtype(Client *c); | |
105 static void updatetitle(Client *c); | |
106 static void updatewmhints(Client *c); | |
107 static void view(const Arg *arg); | |
108 static Client *wintoclient(Window w); | |
109 static Monitor *wintomon(Window w); | |
110 +static Client *wintosystrayicon(Window w); | |
111 static int xerror(Display *dpy, XErrorEvent *ee); | |
112 static int xerrordummy(Display *dpy, XErrorEvent *ee); | |
113 static int xerrorstart(Display *dpy, XErrorEvent *ee); | |
114 static void zoom(const Arg *arg); | |
115 | |
116 /* variables */ | |
117 +static Systray *systray = NULL; | |
118 +static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_… | |
119 static const char broken[] = "broken"; | |
120 static char stext[256]; | |
121 static int screen; | |
122 @@ -276,9 +311,10 @@ | |
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 Bool running = True; | |
132 static Cursor cursor[CurLast]; | |
133 static Display *dpy; | |
134 @@ -499,6 +535,11 @@ | |
135 XFreeCursor(dpy, cursor[CurMove]); | |
136 while(mons) | |
137 cleanupmon(mons); | |
138 + if(showsystray) { | |
139 + XUnmapWindow(dpy, systray->win); | |
140 + XDestroyWindow(dpy, systray->win); | |
141 + free(systray); | |
142 + } | |
143 XSync(dpy, False); | |
144 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTi… | |
145 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); | |
146 @@ -533,9 +575,49 @@ | |
147 | |
148 void | |
149 clientmessage(XEvent *e) { | |
150 + XWindowAttributes wa; | |
151 + XSetWindowAttributes swa; | |
152 XClientMessageEvent *cme = &e->xclient; | |
153 Client *c = wintoclient(cme->window); | |
154 | |
155 + if(showsystray && cme->window == systray->win && cme->message_t… | |
156 + /* add systray icons */ | |
157 + if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { | |
158 + if(!(c = (Client *)calloc(1, sizeof(Client)))) | |
159 + die("fatal: could not malloc() %u bytes… | |
160 + c->win = cme->data.l[2]; | |
161 + c->mon = selmon; | |
162 + c->next = systray->icons; | |
163 + systray->icons = c; | |
164 + XGetWindowAttributes(dpy, c->win, &wa); | |
165 + c->x = c->oldx = c->y = c->oldy = 0; | |
166 + c->w = c->oldw = wa.width; | |
167 + c->h = c->oldh = wa.height; | |
168 + c->oldbw = wa.border_width; | |
169 + c->bw = 0; | |
170 + c->isfloating = True; | |
171 + /* reuse tags field as mapped status */ | |
172 + c->tags = 1; | |
173 + updatesizehints(c); | |
174 + updatesystrayicongeom(c, wa.width, wa.height); | |
175 + XAddToSaveSet(dpy, c->win); | |
176 + XSelectInput(dpy, c->win, StructureNotifyMask |… | |
177 + XReparentWindow(dpy, c->win, systray->win, 0, 0… | |
178 + /* use parents background pixmap */ | |
179 + swa.background_pixmap = ParentRelative; | |
180 + swa.background_pixel = dc.norm[ColBG]; | |
181 + XChangeWindowAttributes(dpy, c->win, CWBackPixm… | |
182 + sendevent(c->win, netatom[Xembed], StructureNot… | |
183 + /* FIXME not sure if I have to send these event… | |
184 + sendevent(c->win, netatom[Xembed], StructureNot… | |
185 + sendevent(c->win, netatom[Xembed], StructureNot… | |
186 + sendevent(c->win, netatom[Xembed], StructureNot… | |
187 + resizebarwin(selmon); | |
188 + updatesystray(); | |
189 + setclientstate(c, NormalState); | |
190 + } | |
191 + return; | |
192 + } | |
193 if(!c) | |
194 return; | |
195 if(cme->message_type == netatom[NetWMState]) { | |
196 @@ -587,7 +667,7 @@ | |
197 dc.drawable = XCreatePixmap(dpy, root, sw, bh, … | |
198 updatebars(); | |
199 for(m = mons; m; m = m->next) | |
200 - XMoveResizeWindow(dpy, m->barwin, m->wx… | |
201 + resizebarwin(m); | |
202 focus(NULL); | |
203 arrange(NULL); | |
204 } | |
205 @@ -671,6 +751,11 @@ | |
206 | |
207 if((c = wintoclient(ev->window))) | |
208 unmanage(c, True); | |
209 + else if((c = wintosystrayicon(ev->window))) { | |
210 + removesystrayicon(c); | |
211 + resizebarwin(selmon); | |
212 + updatesystray(); | |
213 + } | |
214 } | |
215 | |
216 void | |
217 @@ -726,6 +811,7 @@ | |
218 unsigned long *col; | |
219 Client *c; | |
220 | |
221 + resizebarwin(m); | |
222 for(c = m->clients; c; c = c->next) { | |
223 occ |= c->tags; | |
224 if(c->isurgent) | |
225 @@ -747,6 +833,9 @@ | |
226 if(m == selmon) { /* status is only drawn on selected monitor */ | |
227 dc.w = TEXTW(stext); | |
228 dc.x = m->ww - dc.w; | |
229 + if(showsystray && m == selmon) { | |
230 + dc.x -= getsystraywidth(); | |
231 + } | |
232 if(dc.x < x) { | |
233 dc.x = x; | |
234 dc.w = m->ww - x; | |
235 @@ -775,6 +864,7 @@ | |
236 | |
237 for(m = mons; m; m = m->next) | |
238 drawbar(m); | |
239 + updatesystray(); | |
240 } | |
241 | |
242 void | |
243 @@ -924,10 +1014,17 @@ | |
244 unsigned long dl; | |
245 unsigned char *p = NULL; | |
246 Atom da, atom = None; | |
247 + /* FIXME getatomprop should return the number of items and a po… | |
248 + * the stored data instead of this workaround */ | |
249 + Atom req = XA_ATOM; | |
250 + if(prop == xatom[XembedInfo]) | |
251 + req = xatom[XembedInfo]; | |
252 | |
253 - if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False… | |
254 + if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False… | |
255 &da, &di, &dl, &dl, &p) == Success && p) { | |
256 atom = *(Atom *)p; | |
257 + if(da == xatom[XembedInfo] && dl == 2) | |
258 + atom = ((Atom *)p)[1]; | |
259 XFree(p); | |
260 } | |
261 return atom; | |
262 @@ -969,6 +1066,15 @@ | |
263 return result; | |
264 } | |
265 | |
266 +unsigned int | |
267 +getsystraywidth() { | |
268 + unsigned int w = 0; | |
269 + Client *i; | |
270 + if(showsystray) | |
271 + for(i = systray->icons; i; w += i->w + systrayspacing, … | |
272 + return w ? w + systrayspacing : 1; | |
273 +} | |
274 + | |
275 Bool | |
276 gettextprop(Window w, Atom atom, char *text, unsigned int size) { | |
277 char **list = NULL; | |
278 @@ -1103,7 +1209,7 @@ | |
279 killclient(const Arg *arg) { | |
280 if(!selmon->sel) | |
281 return; | |
282 - if(!sendevent(selmon->sel, wmatom[WMDelete])) { | |
283 + if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, … | |
284 XGrabServer(dpy); | |
285 XSetErrorHandler(xerrordummy); | |
286 XSetCloseDownMode(dpy, DestroyAll); | |
287 @@ -1189,6 +1295,12 @@ | |
288 maprequest(XEvent *e) { | |
289 static XWindowAttributes wa; | |
290 XMapRequestEvent *ev = &e->xmaprequest; | |
291 + Client *i; | |
292 + if((i = wintosystrayicon(ev->window))) { | |
293 + sendevent(i->win, netatom[Xembed], StructureNotifyMask,… | |
294 + resizebarwin(selmon); | |
295 + updatesystray(); | |
296 + } | |
297 | |
298 if(!XGetWindowAttributes(dpy, ev->window, &wa)) | |
299 return; | |
300 @@ -1305,6 +1417,16 @@ | |
301 Window trans; | |
302 XPropertyEvent *ev = &e->xproperty; | |
303 | |
304 + if((c = wintosystrayicon(ev->window))) { | |
305 + if(ev->atom == XA_WM_NORMAL_HINTS) { | |
306 + updatesizehints(c); | |
307 + updatesystrayicongeom(c, c->w, c->h); | |
308 + } | |
309 + else | |
310 + updatesystrayiconstate(c, ev); | |
311 + resizebarwin(selmon); | |
312 + updatesystray(); | |
313 + } | |
314 if((ev->window == root) && (ev->atom == XA_WM_NAME)) | |
315 updatestatus(); | |
316 else if(ev->state == PropertyDelete) | |
317 @@ -1354,12 +1476,33 @@ | |
318 } | |
319 | |
320 void | |
321 +removesystrayicon(Client *i) { | |
322 + Client **ii; | |
323 + | |
324 + if(!showsystray || !i) | |
325 + return; | |
326 + for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); | |
327 + if(ii) | |
328 + *ii = i->next; | |
329 + free(i); | |
330 +} | |
331 + | |
332 + | |
333 +void | |
334 resize(Client *c, int x, int y, int w, int h, Bool interact) { | |
335 if(applysizehints(c, &x, &y, &w, &h, interact)) | |
336 resizeclient(c, x, y, w, h); | |
337 } | |
338 | |
339 void | |
340 +resizebarwin(Monitor *m) { | |
341 + unsigned int w = m->ww; | |
342 + if(showsystray && m == selmon) | |
343 + w -= getsystraywidth(); | |
344 + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); | |
345 +} | |
346 + | |
347 +void | |
348 resizeclient(Client *c, int x, int y, int w, int h) { | |
349 XWindowChanges wc; | |
350 | |
351 @@ -1426,6 +1569,18 @@ | |
352 } | |
353 | |
354 void | |
355 +resizerequest(XEvent *e) { | |
356 + XResizeRequestEvent *ev = &e->xresizerequest; | |
357 + Client *i; | |
358 + | |
359 + if((i = wintosystrayicon(ev->window))) { | |
360 + updatesystrayicongeom(i, ev->width, ev->height); | |
361 + resizebarwin(selmon); | |
362 + updatesystray(); | |
363 + } | |
364 +} | |
365 + | |
366 +void | |
367 restack(Monitor *m) { | |
368 Client *c; | |
369 XEvent ev; | |
370 @@ -1509,25 +1664,35 @@ | |
371 } | |
372 | |
373 Bool | |
374 -sendevent(Client *c, Atom proto) { | |
375 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, lo… | |
376 int n; | |
377 - Atom *protocols; | |
378 + Atom *protocols, mt; | |
379 Bool exists = False; | |
380 XEvent ev; | |
381 | |
382 - if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { | |
383 - while(!exists && n--) | |
384 - exists = protocols[n] == proto; | |
385 - XFree(protocols); | |
386 + if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { | |
387 + mt = wmatom[WMProtocols]; | |
388 + if(XGetWMProtocols(dpy, w, &protocols, &n)) { | |
389 + while(!exists && n--) | |
390 + exists = protocols[n] == proto; | |
391 + XFree(protocols); | |
392 + } | |
393 + } | |
394 + else { | |
395 + exists = True; | |
396 + mt = proto; | |
397 } | |
398 if(exists) { | |
399 ev.type = ClientMessage; | |
400 - ev.xclient.window = c->win; | |
401 - ev.xclient.message_type = wmatom[WMProtocols]; | |
402 + ev.xclient.window = w; | |
403 + ev.xclient.message_type = mt; | |
404 ev.xclient.format = 32; | |
405 - ev.xclient.data.l[0] = proto; | |
406 - ev.xclient.data.l[1] = CurrentTime; | |
407 - XSendEvent(dpy, c->win, False, NoEventMask, &ev); | |
408 + ev.xclient.data.l[0] = d0; | |
409 + ev.xclient.data.l[1] = d1; | |
410 + ev.xclient.data.l[2] = d2; | |
411 + ev.xclient.data.l[3] = d3; | |
412 + ev.xclient.data.l[4] = d4; | |
413 + XSendEvent(dpy, w, False, mask, &ev); | |
414 } | |
415 return exists; | |
416 } | |
417 @@ -1540,7 +1705,7 @@ | |
418 XA_WINDOW, 32, PropModeReplace, | |
419 (unsigned char *) &(c->win), 1); | |
420 } | |
421 - sendevent(c, wmatom[WMTakeFocus]); | |
422 + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTa… | |
423 } | |
424 | |
425 void | |
426 @@ -1620,12 +1785,18 @@ | |
427 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); | |
428 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW… | |
429 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", Fals… | |
430 + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0"… | |
431 + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_O… | |
432 + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYST… | |
433 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | |
434 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); | |
435 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULL… | |
436 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYP… | |
437 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WIND… | |
438 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", F… | |
439 + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); | |
440 + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); | |
441 + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); | |
442 /* init cursors */ | |
443 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); | |
444 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); | |
445 @@ -1642,6 +1813,8 @@ | |
446 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter… | |
447 if(!dc.font.set) | |
448 XSetFont(dpy, dc.gc, dc.font.xfont->fid); | |
449 + /* init system tray */ | |
450 + updatesystray(); | |
451 /* init bars */ | |
452 updatebars(); | |
453 updatestatus(); | |
454 @@ -1751,7 +1924,18 @@ | |
455 togglebar(const Arg *arg) { | |
456 selmon->showbar = !selmon->showbar; | |
457 updatebarpos(selmon); | |
458 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, … | |
459 + resizebarwin(selmon); | |
460 + if(showsystray) { | |
461 + XWindowChanges wc; | |
462 + if(!selmon->showbar) | |
463 + wc.y = -bh; | |
464 + else if(selmon->showbar) { | |
465 + wc.y = 0; | |
466 + if(!selmon->topbar) | |
467 + wc.y = selmon->mh - bh; | |
468 + } | |
469 + XConfigureWindow(dpy, systray->win, CWY, &wc); | |
470 + } | |
471 arrange(selmon); | |
472 } | |
473 | |
474 @@ -1841,11 +2025,18 @@ | |
475 else | |
476 unmanage(c, False); | |
477 } | |
478 + else if((c = wintosystrayicon(ev->window))) { | |
479 + removesystrayicon(c); | |
480 + resizebarwin(selmon); | |
481 + updatesystray(); | |
482 + } | |
483 } | |
484 | |
485 void | |
486 updatebars(void) { | |
487 + unsigned int w; | |
488 Monitor *m; | |
489 + | |
490 XSetWindowAttributes wa = { | |
491 .override_redirect = True, | |
492 .background_pixmap = ParentRelative, | |
493 @@ -1854,10 +2045,15 @@ | |
494 for(m = mons; m; m = m->next) { | |
495 if (m->barwin) | |
496 continue; | |
497 - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->w… | |
498 + w = m->ww; | |
499 + if(showsystray && m == selmon) | |
500 + w -= getsystraywidth(); | |
501 + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, b… | |
502 CopyFromParent, DefaultVisual… | |
503 CWOverrideRedirect|CWBackPixm… | |
504 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); | |
505 + if(showsystray && m == selmon) | |
506 + XMapRaised(dpy, systray->win); | |
507 XMapRaised(dpy, m->barwin); | |
508 } | |
509 } | |
510 @@ -2051,6 +2250,107 @@ | |
511 } | |
512 | |
513 void | |
514 +updatesystrayicongeom(Client *i, int w, int h) { | |
515 + if(i) { | |
516 + i->h = bh; | |
517 + if(w == h) | |
518 + i->w = bh; | |
519 + else if(h == bh) | |
520 + i->w = w; | |
521 + else | |
522 + i->w = (int) ((float)bh * ((float)w / (float)h)… | |
523 + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), F… | |
524 + /* force icons into the systray dimenons if they don't … | |
525 + if(i->h > bh) { | |
526 + if(i->w == i->h) | |
527 + i->w = bh; | |
528 + else | |
529 + i->w = (int) ((float)bh * ((float)i->w … | |
530 + i->h = bh; | |
531 + } | |
532 + } | |
533 +} | |
534 + | |
535 +void | |
536 +updatesystrayiconstate(Client *i, XPropertyEvent *ev) { | |
537 + long flags; | |
538 + int code = 0; | |
539 + | |
540 + if(!showsystray || !i || ev->atom != xatom[XembedInfo] || | |
541 + !(flags = getatomprop(i, xatom[XembedInfo]))) | |
542 + return; | |
543 + | |
544 + if(flags & XEMBED_MAPPED && !i->tags) { | |
545 + i->tags = 1; | |
546 + code = XEMBED_WINDOW_ACTIVATE; | |
547 + XMapRaised(dpy, i->win); | |
548 + setclientstate(i, NormalState); | |
549 + } | |
550 + else if(!(flags & XEMBED_MAPPED) && i->tags) { | |
551 + i->tags = 0; | |
552 + code = XEMBED_WINDOW_DEACTIVATE; | |
553 + XUnmapWindow(dpy, i->win); | |
554 + setclientstate(i, WithdrawnState); | |
555 + } | |
556 + else | |
557 + return; | |
558 + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTi… | |
559 + systray->win, XEMBED_EMBEDDED_VERSION); | |
560 +} | |
561 + | |
562 +void | |
563 +updatesystray(void) { | |
564 + XSetWindowAttributes wa; | |
565 + Client *i; | |
566 + unsigned int x = selmon->mx + selmon->mw; | |
567 + unsigned int w = 1; | |
568 + | |
569 + if(!showsystray) | |
570 + return; | |
571 + if(!systray) { | |
572 + /* init systray */ | |
573 + if(!(systray = (Systray *)calloc(1, sizeof(Systray)))) | |
574 + die("fatal: could not malloc() %u bytes\n", siz… | |
575 + systray->win = XCreateSimpleWindow(dpy, root, x, selmon… | |
576 + wa.event_mask = ButtonPressMask | ExposureMask; | |
577 + wa.override_redirect = True; | |
578 + wa.background_pixmap = ParentRelative; | |
579 + wa.background_pixel = dc.norm[ColBG]; | |
580 + XSelectInput(dpy, systray->win, SubstructureNotifyMask); | |
581 + XChangeProperty(dpy, systray->win, netatom[NetSystemTra… | |
582 + PropModeReplace, (unsigned char *)&syst… | |
583 + XChangeWindowAttributes(dpy, systray->win, CWEventMask|… | |
584 + XMapRaised(dpy, systray->win); | |
585 + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray… | |
586 + if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == s… | |
587 + sendevent(root, xatom[Manager], StructureNotify… | |
588 + XSync(dpy, False); | |
589 + } | |
590 + else { | |
591 + fprintf(stderr, "dwm: unable to obtain system t… | |
592 + free(systray); | |
593 + systray = NULL; | |
594 + return; | |
595 + } | |
596 + } | |
597 + for(w = 0, i = systray->icons; i; i = i->next) { | |
598 + XMapRaised(dpy, i->win); | |
599 + w += systrayspacing; | |
600 + XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->… | |
601 + w += i->w; | |
602 + if(i->mon != selmon) | |
603 + i->mon = selmon; | |
604 + } | |
605 + w = w ? w + systrayspacing : 1; | |
606 + x -= w; | |
607 + XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh); | |
608 + /* redraw background */ | |
609 + XSetForeground(dpy, dc.gc, dc.norm[ColBG]); | |
610 + XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh); | |
611 + XSync(dpy, False); | |
612 +} | |
613 + | |
614 +void | |
615 updatewindowtype(Client *c) { | |
616 Atom state = getatomprop(c, netatom[NetWMState]); | |
617 Atom wtype = getatomprop(c, netatom[NetWMWindowType]); | |
618 @@ -2119,6 +2413,16 @@ | |
619 return selmon; | |
620 } | |
621 | |
622 +Client * | |
623 +wintosystrayicon(Window w) { | |
624 + Client *i = NULL; | |
625 + | |
626 + if(!showsystray || !w) | |
627 + return i; | |
628 + for(i = systray->icons; i && i->win != w; i = i->next) ; | |
629 + return i; | |
630 +} | |
631 + | |
632 /* There's no way to check accesses to destroyed windows, thus those ca… | |
633 * ignored (especially on UnmapNotify's). Other types of errors call X… | |
634 * default error handler, which may call exit. */ |