void-packages

Void Source Packages
git clone git://ezup.dev/void-packages.git
Log | Files | Refs | README | LICENSE

01_dwm-systray-6.2.diff (23966B)


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