dwm-systray-6.3.diff 25 KB

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