dwm-systray-6.0.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-systray-6.0.diff (19982B) | |
--- | |
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 ec4baab78314 config.def.h | |
6 --- a/config.def.h Mon Dec 19 15:38:30 2011 +0100 | |
7 +++ b/config.def.h Fri Apr 06 08:25:40 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 ec4baab78314 dwm.c | |
18 --- a/dwm.c Mon Dec 19 15:38:30 2011 +0100 | |
19 +++ b/dwm.c Fri Apr 06 08:25:40 2012 +0200 | |
20 @@ -55,12 +55,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, NetLast }; /* EWMH atoms */ | |
47 +enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrien… | |
48 + NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, Net… | |
49 + NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ | |
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 @@ -154,6 +172,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 @@ -186,9 +210,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 @@ -207,13 +233,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 @@ -241,18 +270,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 @@ -274,9 +309,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 @@ -497,6 +533,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 } | |
146 @@ -530,9 +572,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 @@ -583,7 +663,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 @@ -667,6 +747,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 @@ -722,6 +807,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 @@ -743,6 +829,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 @@ -771,6 +860,7 @@ | |
236 | |
237 for(m = mons; m; m = m->next) | |
238 drawbar(m); | |
239 + updatesystray(); | |
240 } | |
241 | |
242 void | |
243 @@ -917,10 +1007,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 @@ -962,6 +1059,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 @@ -1096,7 +1202,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 @@ -1180,6 +1286,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 @@ -1293,6 +1405,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 @@ -1342,12 +1464,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 @@ -1412,6 +1555,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 @@ -1495,25 +1650,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 @@ -1522,7 +1687,7 @@ | |
418 setfocus(Client *c) { | |
419 if(!c->neverfocus) | |
420 XSetInputFocus(dpy, c->win, RevertToPointerRoot, Curren… | |
421 - sendevent(c, wmatom[WMTakeFocus]); | |
422 + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTa… | |
423 } | |
424 | |
425 void | |
426 @@ -1602,11 +1767,17 @@ | |
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 + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); | |
439 + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); | |
440 + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); | |
441 /* init cursors */ | |
442 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); | |
443 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); | |
444 @@ -1623,6 +1794,8 @@ | |
445 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter… | |
446 if(!dc.font.set) | |
447 XSetFont(dpy, dc.gc, dc.font.xfont->fid); | |
448 + /* init system tray */ | |
449 + updatesystray(); | |
450 /* init bars */ | |
451 updatebars(); | |
452 updatestatus(); | |
453 @@ -1731,7 +1904,18 @@ | |
454 togglebar(const Arg *arg) { | |
455 selmon->showbar = !selmon->showbar; | |
456 updatebarpos(selmon); | |
457 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, … | |
458 + resizebarwin(selmon); | |
459 + if(showsystray) { | |
460 + XWindowChanges wc; | |
461 + if(!selmon->showbar) | |
462 + wc.y = -bh; | |
463 + else if(selmon->showbar) { | |
464 + wc.y = 0; | |
465 + if(!selmon->topbar) | |
466 + wc.y = selmon->mh - bh; | |
467 + } | |
468 + XConfigureWindow(dpy, systray->win, CWY, &wc); | |
469 + } | |
470 arrange(selmon); | |
471 } | |
472 | |
473 @@ -1816,18 +2000,28 @@ | |
474 else | |
475 unmanage(c, False); | |
476 } | |
477 + else if((c = wintosystrayicon(ev->window))) { | |
478 + removesystrayicon(c); | |
479 + resizebarwin(selmon); | |
480 + updatesystray(); | |
481 + } | |
482 } | |
483 | |
484 void | |
485 updatebars(void) { | |
486 + unsigned int w; | |
487 Monitor *m; | |
488 + | |
489 XSetWindowAttributes wa = { | |
490 .override_redirect = True, | |
491 .background_pixmap = ParentRelative, | |
492 .event_mask = ButtonPressMask|ExposureMask | |
493 }; | |
494 for(m = mons; m; m = m->next) { | |
495 - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->w… | |
496 + w = m->ww; | |
497 + if(showsystray && m == selmon) | |
498 + w -= getsystraywidth(); | |
499 + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, b… | |
500 CopyFromParent, DefaultVisual… | |
501 CWOverrideRedirect|CWBackPixm… | |
502 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); | |
503 @@ -2011,6 +2208,107 @@ | |
504 } | |
505 | |
506 void | |
507 +updatesystrayicongeom(Client *i, int w, int h) { | |
508 + if(i) { | |
509 + i->h = bh; | |
510 + if(w == h) | |
511 + i->w = bh; | |
512 + else if(h == bh) | |
513 + i->w = w; | |
514 + else | |
515 + i->w = (int) ((float)bh * ((float)w / (float)h)… | |
516 + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), F… | |
517 + /* force icons into the systray dimenons if they don't … | |
518 + if(i->h > bh) { | |
519 + if(i->w == i->h) | |
520 + i->w = bh; | |
521 + else | |
522 + i->w = (int) ((float)bh * ((float)i->w … | |
523 + i->h = bh; | |
524 + } | |
525 + } | |
526 +} | |
527 + | |
528 +void | |
529 +updatesystrayiconstate(Client *i, XPropertyEvent *ev) { | |
530 + long flags; | |
531 + int code = 0; | |
532 + | |
533 + if(!showsystray || !i || ev->atom != xatom[XembedInfo] || | |
534 + !(flags = getatomprop(i, xatom[XembedInfo]))) | |
535 + return; | |
536 + | |
537 + if(flags & XEMBED_MAPPED && !i->tags) { | |
538 + i->tags = 1; | |
539 + code = XEMBED_WINDOW_ACTIVATE; | |
540 + XMapRaised(dpy, i->win); | |
541 + setclientstate(i, NormalState); | |
542 + } | |
543 + else if(!(flags & XEMBED_MAPPED) && i->tags) { | |
544 + i->tags = 0; | |
545 + code = XEMBED_WINDOW_DEACTIVATE; | |
546 + XUnmapWindow(dpy, i->win); | |
547 + setclientstate(i, WithdrawnState); | |
548 + } | |
549 + else | |
550 + return; | |
551 + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTi… | |
552 + systray->win, XEMBED_EMBEDDED_VERSION); | |
553 +} | |
554 + | |
555 +void | |
556 +updatesystray(void) { | |
557 + XSetWindowAttributes wa; | |
558 + Client *i; | |
559 + unsigned int x = selmon->mx + selmon->mw; | |
560 + unsigned int w = 1; | |
561 + | |
562 + if(!showsystray) | |
563 + return; | |
564 + if(!systray) { | |
565 + /* init systray */ | |
566 + if(!(systray = (Systray *)calloc(1, sizeof(Systray)))) | |
567 + die("fatal: could not malloc() %u bytes\n", siz… | |
568 + systray->win = XCreateSimpleWindow(dpy, root, x, selmon… | |
569 + wa.event_mask = ButtonPressMask | ExposureMask; | |
570 + wa.override_redirect = True; | |
571 + wa.background_pixmap = ParentRelative; | |
572 + wa.background_pixel = dc.norm[ColBG]; | |
573 + XSelectInput(dpy, systray->win, SubstructureNotifyMask); | |
574 + XChangeProperty(dpy, systray->win, netatom[NetSystemTra… | |
575 + PropModeReplace, (unsigned char *)&syst… | |
576 + XChangeWindowAttributes(dpy, systray->win, CWEventMask|… | |
577 + XMapRaised(dpy, systray->win); | |
578 + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray… | |
579 + if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == s… | |
580 + sendevent(root, xatom[Manager], StructureNotify… | |
581 + XSync(dpy, False); | |
582 + } | |
583 + else { | |
584 + fprintf(stderr, "dwm: unable to obtain system t… | |
585 + free(systray); | |
586 + systray = NULL; | |
587 + return; | |
588 + } | |
589 + } | |
590 + for(w = 0, i = systray->icons; i; i = i->next) { | |
591 + XMapRaised(dpy, i->win); | |
592 + w += systrayspacing; | |
593 + XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->… | |
594 + w += i->w; | |
595 + if(i->mon != selmon) | |
596 + i->mon = selmon; | |
597 + } | |
598 + w = w ? w + systrayspacing : 1; | |
599 + x -= w; | |
600 + XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh); | |
601 + /* redraw background */ | |
602 + XSetForeground(dpy, dc.gc, dc.norm[ColBG]); | |
603 + XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh); | |
604 + XSync(dpy, False); | |
605 +} | |
606 + | |
607 +void | |
608 updatewindowtype(Client *c) { | |
609 Atom state = getatomprop(c, netatom[NetWMState]); | |
610 Atom wtype = getatomprop(c, netatom[NetWMWindowType]); | |
611 @@ -2080,6 +2372,16 @@ | |
612 return selmon; | |
613 } | |
614 | |
615 +Client * | |
616 +wintosystrayicon(Window w) { | |
617 + Client *i = NULL; | |
618 + | |
619 + if(!showsystray || !w) | |
620 + return i; | |
621 + for(i = systray->icons; i && i->win != w; i = i->next) ; | |
622 + return i; | |
623 +} | |
624 + | |
625 /* There's no way to check accesses to destroyed windows, thus those ca… | |
626 * ignored (especially on UnmapNotify's). Other types of errors call X… | |
627 * default error handler, which may call exit. */ |