dwm-systray-6.4.diff 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. diff --git a/config.def.h b/config.def.h
  2. index 9efa774..750529d 100644
  3. --- a/config.def.h
  4. +++ b/config.def.h
  5. @@ -3,6 +3,11 @@
  6. /* appearance */
  7. static const unsigned int borderpx = 1; /* border pixel of windows */
  8. static const unsigned int snap = 32; /* snap pixel */
  9. +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
  10. +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */
  11. +static const unsigned int systrayspacing = 2; /* systray spacing */
  12. +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
  13. +static const int showsystray = 1; /* 0 means no systray */
  14. static const int showbar = 1; /* 0 means no bar */
  15. static const int topbar = 1; /* 0 means bottom bar */
  16. static const char *fonts[] = { "monospace:size=10" };
  17. @@ -101,8 +106,8 @@ static const Key keys[] = {
  18. /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
  19. static const Button buttons[] = {
  20. /* click event mask button function argument */
  21. - { ClkLtSymbol, 0, Button1, setlayout, {0} },
  22. - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
  23. + { ClkTagBar, MODKEY, Button1, tag, {0} },
  24. + { ClkTagBar, MODKEY, Button3, toggletag, {0} },
  25. { ClkWinTitle, 0, Button2, zoom, {0} },
  26. { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
  27. { ClkClientWin, MODKEY, Button1, movemouse, {0} },
  28. diff --git a/dwm.c b/dwm.c
  29. index 03baf42..4611a03 100644
  30. --- a/dwm.c
  31. +++ b/dwm.c
  32. @@ -57,12 +57,27 @@
  33. #define TAGMASK ((1 << LENGTH(tags)) - 1)
  34. #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
  35. +#define SYSTEM_TRAY_REQUEST_DOCK 0
  36. +/* XEMBED messages */
  37. +#define XEMBED_EMBEDDED_NOTIFY 0
  38. +#define XEMBED_WINDOW_ACTIVATE 1
  39. +#define XEMBED_FOCUS_IN 4
  40. +#define XEMBED_MODALITY_ON 10
  41. +#define XEMBED_MAPPED (1 << 0)
  42. +#define XEMBED_WINDOW_ACTIVATE 1
  43. +#define XEMBED_WINDOW_DEACTIVATE 2
  44. +#define VERSION_MAJOR 0
  45. +#define VERSION_MINOR 0
  46. +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
  47. +
  48. /* enums */
  49. enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
  50. enum { SchemeNorm, SchemeSel }; /* color schemes */
  51. enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
  52. + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
  53. NetWMFullscreen, NetActiveWindow, NetWMWindowType,
  54. NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
  55. +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
  56. enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
  57. enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
  58. ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
  59. @@ -141,6 +156,12 @@ typedef struct {
  60. int monitor;
  61. } Rule;
  62. +typedef struct Systray Systray;
  63. +struct Systray {
  64. + Window win;
  65. + Client *icons;
  66. +};
  67. +
  68. /* function declarations */
  69. static void applyrules(Client *c);
  70. static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
  71. @@ -172,6 +193,7 @@ static void focusstack(const Arg *arg);
  72. static Atom getatomprop(Client *c, Atom prop);
  73. static int getrootptr(int *x, int *y);
  74. static long getstate(Window w);
  75. +static unsigned int getsystraywidth();
  76. static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
  77. static void grabbuttons(Client *c, int focused);
  78. static void grabkeys(void);
  79. @@ -189,13 +211,16 @@ static void pop(Client *c);
  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, int 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 int sendevent(Client *c, Atom proto);
  93. +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
  94. static void sendmon(Client *c, Monitor *m);
  95. static void setclientstate(Client *c, long state);
  96. static void setfocus(Client *c);
  97. @@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg);
  98. static void showhide(Client *c);
  99. static void sigchld(int unused);
  100. static void spawn(const Arg *arg);
  101. +static Monitor *systraytomon(Monitor *m);
  102. static void tag(const Arg *arg);
  103. static void tagmon(const Arg *arg);
  104. static void tile(Monitor *m);
  105. @@ -224,18 +250,23 @@ static int updategeom(void);
  106. static void updatenumlockmask(void);
  107. static void updatesizehints(Client *c);
  108. static void updatestatus(void);
  109. +static void updatesystray(void);
  110. +static void updatesystrayicongeom(Client *i, int w, int h);
  111. +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
  112. static void updatetitle(Client *c);
  113. static void updatewindowtype(Client *c);
  114. static void updatewmhints(Client *c);
  115. static void view(const Arg *arg);
  116. static Client *wintoclient(Window w);
  117. static Monitor *wintomon(Window w);
  118. +static Client *wintosystrayicon(Window w);
  119. static int xerror(Display *dpy, XErrorEvent *ee);
  120. static int xerrordummy(Display *dpy, XErrorEvent *ee);
  121. static int xerrorstart(Display *dpy, XErrorEvent *ee);
  122. static void zoom(const Arg *arg);
  123. /* variables */
  124. +static Systray *systray = NULL;
  125. static const char broken[] = "broken";
  126. static char stext[256];
  127. static int screen;
  128. @@ -258,9 +289,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
  129. [MapRequest] = maprequest,
  130. [MotionNotify] = motionnotify,
  131. [PropertyNotify] = propertynotify,
  132. + [ResizeRequest] = resizerequest,
  133. [UnmapNotify] = unmapnotify
  134. };
  135. -static Atom wmatom[WMLast], netatom[NetLast];
  136. +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
  137. static int running = 1;
  138. static Cur *cursor[CurLast];
  139. static Clr **scheme;
  140. @@ -442,7 +474,7 @@ buttonpress(XEvent *e)
  141. arg.ui = 1 << i;
  142. } else if (ev->x < x + TEXTW(selmon->ltsymbol))
  143. click = ClkLtSymbol;
  144. - else if (ev->x > selmon->ww - (int)TEXTW(stext))
  145. + else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
  146. click = ClkStatusText;
  147. else
  148. click = ClkWinTitle;
  149. @@ -485,6 +517,13 @@ cleanup(void)
  150. XUngrabKey(dpy, AnyKey, AnyModifier, root);
  151. while (mons)
  152. cleanupmon(mons);
  153. +
  154. + if (showsystray) {
  155. + XUnmapWindow(dpy, systray->win);
  156. + XDestroyWindow(dpy, systray->win);
  157. + free(systray);
  158. + }
  159. +
  160. for (i = 0; i < CurLast; i++)
  161. drw_cur_free(drw, cursor[i]);
  162. for (i = 0; i < LENGTH(colors); i++)
  163. @@ -516,9 +555,58 @@ cleanupmon(Monitor *mon)
  164. void
  165. clientmessage(XEvent *e)
  166. {
  167. + XWindowAttributes wa;
  168. + XSetWindowAttributes swa;
  169. XClientMessageEvent *cme = &e->xclient;
  170. Client *c = wintoclient(cme->window);
  171. + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
  172. + /* add systray icons */
  173. + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
  174. + if (!(c = (Client *)calloc(1, sizeof(Client))))
  175. + die("fatal: could not malloc() %u bytes\n", sizeof(Client));
  176. + if (!(c->win = cme->data.l[2])) {
  177. + free(c);
  178. + return;
  179. + }
  180. + c->mon = selmon;
  181. + c->next = systray->icons;
  182. + systray->icons = c;
  183. + if (!XGetWindowAttributes(dpy, c->win, &wa)) {
  184. + /* use sane defaults */
  185. + wa.width = bh;
  186. + wa.height = bh;
  187. + wa.border_width = 0;
  188. + }
  189. + c->x = c->oldx = c->y = c->oldy = 0;
  190. + c->w = c->oldw = wa.width;
  191. + c->h = c->oldh = wa.height;
  192. + c->oldbw = wa.border_width;
  193. + c->bw = 0;
  194. + c->isfloating = True;
  195. + /* reuse tags field as mapped status */
  196. + c->tags = 1;
  197. + updatesizehints(c);
  198. + updatesystrayicongeom(c, wa.width, wa.height);
  199. + XAddToSaveSet(dpy, c->win);
  200. + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
  201. + XReparentWindow(dpy, c->win, systray->win, 0, 0);
  202. + /* use parents background color */
  203. + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
  204. + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
  205. + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
  206. + /* FIXME not sure if I have to send these events, too */
  207. + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
  208. + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
  209. + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
  210. + XSync(dpy, False);
  211. + resizebarwin(selmon);
  212. + updatesystray();
  213. + setclientstate(c, NormalState);
  214. + }
  215. + return;
  216. + }
  217. +
  218. if (!c)
  219. return;
  220. if (cme->message_type == netatom[NetWMState]) {
  221. @@ -571,7 +659,7 @@ configurenotify(XEvent *e)
  222. for (c = m->clients; c; c = c->next)
  223. if (c->isfullscreen)
  224. resizeclient(c, m->mx, m->my, m->mw, m->mh);
  225. - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
  226. + resizebarwin(m);
  227. }
  228. focus(NULL);
  229. arrange(NULL);
  230. @@ -656,6 +744,11 @@ destroynotify(XEvent *e)
  231. if ((c = wintoclient(ev->window)))
  232. unmanage(c, 1);
  233. + else if ((c = wintosystrayicon(ev->window))) {
  234. + removesystrayicon(c);
  235. + resizebarwin(selmon);
  236. + updatesystray();
  237. + }
  238. }
  239. void
  240. @@ -699,7 +792,7 @@ dirtomon(int dir)
  241. void
  242. drawbar(Monitor *m)
  243. {
  244. - int x, w, tw = 0;
  245. + int x, w, tw = 0, stw = 0;
  246. int boxs = drw->fonts->h / 9;
  247. int boxw = drw->fonts->h / 6 + 2;
  248. unsigned int i, occ = 0, urg = 0;
  249. @@ -708,13 +801,17 @@ drawbar(Monitor *m)
  250. if (!m->showbar)
  251. return;
  252. + if(showsystray && m == systraytomon(m) && !systrayonleft)
  253. + stw = getsystraywidth();
  254. +
  255. /* draw status first so it can be overdrawn by tags later */
  256. if (m == selmon) { /* status is only drawn on selected monitor */
  257. drw_setscheme(drw, scheme[SchemeNorm]);
  258. - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
  259. - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
  260. + tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */
  261. + drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0);
  262. }
  263. + resizebarwin(m);
  264. for (c = m->clients; c; c = c->next) {
  265. occ |= c->tags;
  266. if (c->isurgent)
  267. @@ -735,7 +832,7 @@ drawbar(Monitor *m)
  268. drw_setscheme(drw, scheme[SchemeNorm]);
  269. x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
  270. - if ((w = m->ww - tw - x) > bh) {
  271. + if ((w = m->ww - tw - stw - x) > bh) {
  272. if (m->sel) {
  273. drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
  274. drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
  275. @@ -746,7 +843,7 @@ drawbar(Monitor *m)
  276. drw_rect(drw, x, 0, w, bh, 1, 1);
  277. }
  278. }
  279. - drw_map(drw, m->barwin, 0, 0, m->ww, bh);
  280. + drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
  281. }
  282. void
  283. @@ -783,8 +880,11 @@ expose(XEvent *e)
  284. Monitor *m;
  285. XExposeEvent *ev = &e->xexpose;
  286. - if (ev->count == 0 && (m = wintomon(ev->window)))
  287. + if (ev->count == 0 && (m = wintomon(ev->window))) {
  288. drawbar(m);
  289. + if (m == selmon)
  290. + updatesystray();
  291. + }
  292. }
  293. void
  294. @@ -870,14 +970,32 @@ getatomprop(Client *c, Atom prop)
  295. unsigned char *p = NULL;
  296. Atom da, atom = None;
  297. - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
  298. + /* FIXME getatomprop should return the number of items and a pointer to
  299. + * the stored data instead of this workaround */
  300. + Atom req = XA_ATOM;
  301. + if (prop == xatom[XembedInfo])
  302. + req = xatom[XembedInfo];
  303. +
  304. + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
  305. &da, &di, &dl, &dl, &p) == Success && p) {
  306. atom = *(Atom *)p;
  307. + if (da == xatom[XembedInfo] && dl == 2)
  308. + atom = ((Atom *)p)[1];
  309. XFree(p);
  310. }
  311. return atom;
  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, i = i->next) ;
  320. + return w ? w + systrayspacing : 1;
  321. +}
  322. +
  323. int
  324. getrootptr(int *x, int *y)
  325. {
  326. @@ -1018,7 +1136,8 @@ killclient(const Arg *arg)
  327. {
  328. if (!selmon->sel)
  329. return;
  330. - if (!sendevent(selmon->sel, wmatom[WMDelete])) {
  331. +
  332. + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
  333. XGrabServer(dpy);
  334. XSetErrorHandler(xerrordummy);
  335. XSetCloseDownMode(dpy, DestroyAll);
  336. @@ -1105,6 +1224,13 @@ maprequest(XEvent *e)
  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, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
  342. + resizebarwin(selmon);
  343. + updatesystray();
  344. + }
  345. +
  346. if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
  347. return;
  348. if (!wintoclient(ev->window))
  349. @@ -1226,6 +1352,17 @@ propertynotify(XEvent *e)
  350. Window trans;
  351. XPropertyEvent *ev = &e->xproperty;
  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. +
  363. if ((ev->window == root) && (ev->atom == XA_WM_NAME))
  364. updatestatus();
  365. else if (ev->state == PropertyDelete)
  366. @@ -1276,6 +1413,19 @@ recttomon(int x, int y, int w, int h)
  367. return r;
  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. void
  383. resize(Client *c, int x, int y, int w, int h, int interact)
  384. {
  385. @@ -1283,6 +1433,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
  386. resizeclient(c, x, y, w, h);
  387. }
  388. +void
  389. +resizebarwin(Monitor *m) {
  390. + unsigned int w = m->ww;
  391. + if (showsystray && m == systraytomon(m) && !systrayonleft)
  392. + w -= getsystraywidth();
  393. + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
  394. +}
  395. +
  396. void
  397. resizeclient(Client *c, int x, int y, int w, int h)
  398. {
  399. @@ -1298,6 +1456,19 @@ resizeclient(Client *c, int x, int y, int w, int h)
  400. XSync(dpy, False);
  401. }
  402. +void
  403. +resizerequest(XEvent *e)
  404. +{
  405. + XResizeRequestEvent *ev = &e->xresizerequest;
  406. + Client *i;
  407. +
  408. + if ((i = wintosystrayicon(ev->window))) {
  409. + updatesystrayicongeom(i, ev->width, ev->height);
  410. + resizebarwin(selmon);
  411. + updatesystray();
  412. + }
  413. +}
  414. +
  415. void
  416. resizemouse(const Arg *arg)
  417. {
  418. @@ -1444,26 +1615,37 @@ setclientstate(Client *c, long state)
  419. }
  420. int
  421. -sendevent(Client *c, Atom proto)
  422. +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
  423. {
  424. int n;
  425. - Atom *protocols;
  426. + Atom *protocols, mt;
  427. int exists = 0;
  428. XEvent ev;
  429. - if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
  430. - while (!exists && n--)
  431. - exists = protocols[n] == proto;
  432. - XFree(protocols);
  433. + if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
  434. + mt = wmatom[WMProtocols];
  435. + if (XGetWMProtocols(dpy, w, &protocols, &n)) {
  436. + while (!exists && n--)
  437. + exists = protocols[n] == proto;
  438. + XFree(protocols);
  439. + }
  440. + }
  441. + else {
  442. + exists = True;
  443. + mt = proto;
  444. }
  445. +
  446. if (exists) {
  447. ev.type = ClientMessage;
  448. - ev.xclient.window = c->win;
  449. - ev.xclient.message_type = wmatom[WMProtocols];
  450. + ev.xclient.window = w;
  451. + ev.xclient.message_type = mt;
  452. ev.xclient.format = 32;
  453. - ev.xclient.data.l[0] = proto;
  454. - ev.xclient.data.l[1] = CurrentTime;
  455. - XSendEvent(dpy, c->win, False, NoEventMask, &ev);
  456. + ev.xclient.data.l[0] = d0;
  457. + ev.xclient.data.l[1] = d1;
  458. + ev.xclient.data.l[2] = d2;
  459. + ev.xclient.data.l[3] = d3;
  460. + ev.xclient.data.l[4] = d4;
  461. + XSendEvent(dpy, w, False, mask, &ev);
  462. }
  463. return exists;
  464. }
  465. @@ -1477,7 +1659,7 @@ setfocus(Client *c)
  466. XA_WINDOW, 32, PropModeReplace,
  467. (unsigned char *) &(c->win), 1);
  468. }
  469. - sendevent(c, wmatom[WMTakeFocus]);
  470. + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
  471. }
  472. void
  473. @@ -1566,6 +1748,10 @@ setup(void)
  474. wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
  475. netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
  476. netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  477. + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
  478. + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
  479. + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
  480. + netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
  481. netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  482. netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  483. netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
  484. @@ -1573,6 +1759,9 @@ setup(void)
  485. netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
  486. netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
  487. netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
  488. + xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
  489. + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
  490. + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
  491. /* init cursors */
  492. cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
  493. cursor[CurResize] = drw_cur_create(drw, XC_sizing);
  494. @@ -1581,6 +1770,8 @@ setup(void)
  495. scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
  496. for (i = 0; i < LENGTH(colors); i++)
  497. scheme[i] = drw_scm_create(drw, colors[i], 3);
  498. + /* init system tray */
  499. + updatesystray();
  500. /* init bars */
  501. updatebars();
  502. updatestatus();
  503. @@ -1711,7 +1902,18 @@ togglebar(const Arg *arg)
  504. {
  505. selmon->showbar = !selmon->showbar;
  506. updatebarpos(selmon);
  507. - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
  508. + resizebarwin(selmon);
  509. + if (showsystray) {
  510. + XWindowChanges wc;
  511. + if (!selmon->showbar)
  512. + wc.y = -bh;
  513. + else if (selmon->showbar) {
  514. + wc.y = 0;
  515. + if (!selmon->topbar)
  516. + wc.y = selmon->mh - bh;
  517. + }
  518. + XConfigureWindow(dpy, systray->win, CWY, &wc);
  519. + }
  520. arrange(selmon);
  521. }
  522. @@ -1807,11 +2009,18 @@ unmapnotify(XEvent *e)
  523. else
  524. unmanage(c, 0);
  525. }
  526. + else if ((c = wintosystrayicon(ev->window))) {
  527. + /* KLUDGE! sometimes icons occasionally unmap their windows, but do
  528. + * _not_ destroy them. We map those windows back */
  529. + XMapRaised(dpy, c->win);
  530. + updatesystray();
  531. + }
  532. }
  533. void
  534. updatebars(void)
  535. {
  536. + unsigned int w;
  537. Monitor *m;
  538. XSetWindowAttributes wa = {
  539. .override_redirect = True,
  540. @@ -1822,10 +2031,15 @@ updatebars(void)
  541. for (m = mons; m; m = m->next) {
  542. if (m->barwin)
  543. continue;
  544. - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
  545. + w = m->ww;
  546. + if (showsystray && m == systraytomon(m))
  547. + w -= getsystraywidth();
  548. + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
  549. CopyFromParent, DefaultVisual(dpy, screen),
  550. CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  551. XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
  552. + if (showsystray && m == systraytomon(m))
  553. + XMapRaised(dpy, systray->win);
  554. XMapRaised(dpy, m->barwin);
  555. XSetClassHint(dpy, m->barwin, &ch);
  556. }
  557. @@ -2002,6 +2216,125 @@ updatestatus(void)
  558. if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
  559. strcpy(stext, "dwm-"VERSION);
  560. drawbar(selmon);
  561. + updatesystray();
  562. +}
  563. +
  564. +
  565. +void
  566. +updatesystrayicongeom(Client *i, int w, int h)
  567. +{
  568. + if (i) {
  569. + i->h = bh;
  570. + if (w == h)
  571. + i->w = bh;
  572. + else if (h == bh)
  573. + i->w = w;
  574. + else
  575. + i->w = (int) ((float)bh * ((float)w / (float)h));
  576. + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
  577. + /* force icons into the systray dimensions if they don't want to */
  578. + if (i->h > bh) {
  579. + if (i->w == i->h)
  580. + i->w = bh;
  581. + else
  582. + i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
  583. + i->h = bh;
  584. + }
  585. + }
  586. +}
  587. +
  588. +void
  589. +updatesystrayiconstate(Client *i, XPropertyEvent *ev)
  590. +{
  591. + long flags;
  592. + int code = 0;
  593. +
  594. + if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
  595. + !(flags = getatomprop(i, xatom[XembedInfo])))
  596. + return;
  597. +
  598. + if (flags & XEMBED_MAPPED && !i->tags) {
  599. + i->tags = 1;
  600. + code = XEMBED_WINDOW_ACTIVATE;
  601. + XMapRaised(dpy, i->win);
  602. + setclientstate(i, NormalState);
  603. + }
  604. + else if (!(flags & XEMBED_MAPPED) && i->tags) {
  605. + i->tags = 0;
  606. + code = XEMBED_WINDOW_DEACTIVATE;
  607. + XUnmapWindow(dpy, i->win);
  608. + setclientstate(i, WithdrawnState);
  609. + }
  610. + else
  611. + return;
  612. + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
  613. + systray->win, XEMBED_EMBEDDED_VERSION);
  614. +}
  615. +
  616. +void
  617. +updatesystray(void)
  618. +{
  619. + XSetWindowAttributes wa;
  620. + XWindowChanges wc;
  621. + Client *i;
  622. + Monitor *m = systraytomon(NULL);
  623. + unsigned int x = m->mx + m->mw;
  624. + unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
  625. + unsigned int w = 1;
  626. +
  627. + if (!showsystray)
  628. + return;
  629. + if (systrayonleft)
  630. + x -= sw + lrpad / 2;
  631. + if (!systray) {
  632. + /* init systray */
  633. + if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
  634. + die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
  635. + systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
  636. + wa.event_mask = ButtonPressMask | ExposureMask;
  637. + wa.override_redirect = True;
  638. + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
  639. + XSelectInput(dpy, systray->win, SubstructureNotifyMask);
  640. + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
  641. + PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
  642. + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
  643. + XMapRaised(dpy, systray->win);
  644. + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
  645. + if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
  646. + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
  647. + XSync(dpy, False);
  648. + }
  649. + else {
  650. + fprintf(stderr, "dwm: unable to obtain system tray.\n");
  651. + free(systray);
  652. + systray = NULL;
  653. + return;
  654. + }
  655. + }
  656. + for (w = 0, i = systray->icons; i; i = i->next) {
  657. + /* make sure the background color stays the same */
  658. + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
  659. + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
  660. + XMapRaised(dpy, i->win);
  661. + w += systrayspacing;
  662. + i->x = w;
  663. + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
  664. + w += i->w;
  665. + if (i->mon != m)
  666. + i->mon = m;
  667. + }
  668. + w = w ? w + systrayspacing : 1;
  669. + x -= w;
  670. + XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
  671. + wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
  672. + wc.stack_mode = Above; wc.sibling = m->barwin;
  673. + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
  674. + XMapWindow(dpy, systray->win);
  675. + XMapSubwindows(dpy, systray->win);
  676. + /* redraw background */
  677. + XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
  678. + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
  679. + XSync(dpy, False);
  680. }
  681. void
  682. @@ -2069,6 +2402,16 @@ wintoclient(Window w)
  683. return NULL;
  684. }
  685. +Client *
  686. +wintosystrayicon(Window w) {
  687. + Client *i = NULL;
  688. +
  689. + if (!showsystray || !w)
  690. + return i;
  691. + for (i = systray->icons; i && i->win != w; i = i->next) ;
  692. + return i;
  693. +}
  694. +
  695. Monitor *
  696. wintomon(Window w)
  697. {
  698. @@ -2122,6 +2465,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
  699. return -1;
  700. }
  701. +Monitor *
  702. +systraytomon(Monitor *m) {
  703. + Monitor *t;
  704. + int i, n;
  705. + if(!systraypinning) {
  706. + if(!m)
  707. + return selmon;
  708. + return m == selmon ? m : NULL;
  709. + }
  710. + for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
  711. + for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
  712. + if(systraypinningfailfirst && n < systraypinning)
  713. + return mons;
  714. + return t;
  715. +}
  716. +
  717. void
  718. zoom(const Arg *arg)
  719. {