From 1a0ec2f7044e96b56ec44f0cbc855bade0f9714e Mon Sep 17 00:00:00 2001
From: Ryan Kes <alrayyes@gmail.com>
Date: Wed, 13 Mar 2019 09:49:55 +0100
Subject: [PATCH] added alpha patch

---
 PKGBUILD                          |  12 +-
 config.h                          |  36 +-
 local-alpha-20180613-b69c870.diff | 408 +++++++++++++++++
 tmp/6.1/systray.diff              | 681 ++++++++++++++++++++++++++++
 tmp/6.2/systray.diff              | 715 ++++++++++++++++++++++++++++++
 5 files changed, 1846 insertions(+), 6 deletions(-)
 create mode 100644 local-alpha-20180613-b69c870.diff
 create mode 100644 tmp/6.1/systray.diff
 create mode 100644 tmp/6.2/systray.diff

diff --git a/PKGBUILD b/PKGBUILD
index b9b8650..1169514 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -25,15 +25,16 @@ _patches=(
 #        "local-fancybar-2019018-b69c870.diff"
         "local-scratchpad-20170207-bb3bd6f.diff"
         "local-notitle-6.2.diff"
+        "local-alpha-20180613-b69c870.diff"
         )
 
 source=(http://dl.suckless.org/dwm/dwm-$pkgver.tar.gz
-	config.h
-	dwm.desktop
-	"${_patches[@]}")
+    config.h
+    dwm.desktop
+    "${_patches[@]}")
 
 md5sums=('9929845ccdec4d2cc191f16210dd7f3d'
-         '255e4ca8ee222687c2699873cb742be7'
+         'ac3797b8777cfebac73c48e9efea93a2'
          '939f403a71b6e85261d09fc3412269ee'
          '2c19f1a3db59e158c45483668f4cee24'
          'fbb786263f2d714b18368ff64779d669'
@@ -45,7 +46,8 @@ md5sums=('9929845ccdec4d2cc191f16210dd7f3d'
          'd2781ac29048fc50e42e0f11e6cf7bce'
          'c5469c1457955a8447e05ec5118b3ce6'
          '7381051e12596394791092f0d39a2dd2'
-         'd14e0938455073391cdcd3ccad083150')
+         'd14e0938455073391cdcd3ccad083150'
+         'd53207118f641b49208d4720176f26be')
 
 prepare() {
   cd $srcdir/$pkgname-$pkgver
diff --git a/config.h b/config.h
index 990083f..4105d96 100644
--- a/config.h
+++ b/config.h
@@ -22,6 +22,8 @@ static const char col_yellow[]      = "#ffff00";
 static const char col_white[]       = "#ffffff";
 static const char status_white[]    = "#dddddd";
 static const char status_black[]    = "#000";
+static const unsigned int baralpha = 0xd0;
+static const unsigned int borderalpha = OPAQUE;
 static const char *colors[][3]      = {
 	/*					fg         bg          border   */
 	[SchemeNorm] =	 { col_gray3, col_gray1,  col_gray2 },
@@ -60,7 +62,39 @@ static const char *colors[][3]      = {
 	//{ status_black, "#42717B",  "#42717B" },       /* bar 15 */
 	//{ "#dddddd", "#42717B",  "#42717B" },       /* bar 16 seperator */
 	//{ status_black, "#dddddd",  "#dddddd" },       /* bar 16 */
-
+};
+static const unsigned int alphas[][3]      = {
+	/*               fg      bg        border     */
+	[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
+	[SchemeSel]  = { OPAQUE, baralpha, borderalpha },
+	[SchemeWarn]  = { OPAQUE, baralpha, borderalpha },
+	[SchemeUrgent]  = { OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha }, /* bar 1 seperator */
+	{ OPAQUE, baralpha, borderalpha }, /* bar 1 */
+	{ OPAQUE, baralpha, borderalpha }, /* bar 2 seperator */
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
+	{ OPAQUE, baralpha, borderalpha },
 };
 
 /* tagging */
diff --git a/local-alpha-20180613-b69c870.diff b/local-alpha-20180613-b69c870.diff
new file mode 100644
index 0000000..becc9c3
--- /dev/null
+++ b/local-alpha-20180613-b69c870.diff
@@ -0,0 +1,408 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h
++++ b/config.def.h
+@@ -20,7 +20,8 @@ static const char col_black[]       = "#
+ static const char col_red[]         = "#ff0000";
+ static const char col_yellow[]      = "#ffff00";
+ static const char col_white[]       = "#ffffff";
+-
++static const unsigned int baralpha = 0xd0;
++static const unsigned int borderalpha = OPAQUE;
+ static const char *colors[][3]      = {
+ 	/*					fg         bg          border   */
+ 	[SchemeNorm] =	 { col_gray3, col_gray1,  col_gray2 },
+@@ -28,6 +29,11 @@ static const char *colors[][3]      = {
+ 	[SchemeWarn] =	 { col_black, col_yellow, col_red },
+ 	[SchemeUrgent]=	 { col_white, col_red,    col_red },
+ };
++static const unsigned int alphas[][3]      = {
++	/*               fg      bg        border     */
++	[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
++	[SchemeSel]  = { OPAQUE, baralpha, borderalpha },
++};
+ 
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+diff -up a/config.mk b/config.mk
+--- a/config.mk	2019-02-02 13:55:28.000000000 +0100
++++ b/config.mk	2019-03-12 18:34:52.780703276 +0100
+@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
+ 
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
+ 
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff -up a/drw.c b/drw.c
+--- a/drw.c	2019-02-02 13:55:28.000000000 +0100
++++ b/drw.c	2019-03-12 18:34:52.780703276 +0100
+@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_
+ }
+ 
+ Drw *
+-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
++drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
+ {
+ 	Drw *drw = ecalloc(1, sizeof(Drw));
+ 
+@@ -70,8 +70,14 @@ drw_create(Display *dpy, int screen, Win
+ 	drw->root = root;
+ 	drw->w = w;
+ 	drw->h = h;
+-	drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
+-	drw->gc = XCreateGC(dpy, root, 0, NULL);
++	drw->visual = visual;
++	drw->depth = depth;
++	drw->cmap = cmap;
++	drw->visual = visual;
++	drw->depth = depth;
++	drw->cmap = cmap;
++	drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
++	drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
+ 	XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
+ 
+ 	return drw;
+@@ -87,7 +93,7 @@ drw_resize(Drw *drw, unsigned int w, uns
+ 	drw->h = h;
+ 	if (drw->drawable)
+ 		XFreePixmap(drw->dpy, drw->drawable);
+-	drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
++	drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
+ }
+ 
+ void
+@@ -193,21 +199,22 @@ drw_fontset_free(Fnt *font)
+ }
+ 
+ void
+-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
++drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
+ {
+ 	if (!drw || !dest || !clrname)
+ 		return;
+ 
+-	if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
+-	                       DefaultColormap(drw->dpy, drw->screen),
++	if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
+ 	                       clrname, dest))
+ 		die("error, cannot allocate color '%s'", clrname);
++
++	dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
+ }
+ 
+ /* Wrapper to create color schemes. The caller has to call free(3) on the
+  * returned color scheme when done using it. */
+ Clr *
+-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
++drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
+ {
+ 	size_t i;
+ 	Clr *ret;
+@@ -217,7 +224,7 @@ drw_scm_create(Drw *drw, const char *clr
+ 		return NULL;
+ 
+ 	for (i = 0; i < clrcount; i++)
+-		drw_clr_create(drw, &ret[i], clrnames[i]);
++		drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
+ 	return ret;
+ }
+ 
+@@ -273,9 +280,7 @@ drw_text(Drw *drw, int x, int y, unsigne
+ 	} else {
+ 		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
+ 		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+-		d = XftDrawCreate(drw->dpy, drw->drawable,
+-		                  DefaultVisual(drw->dpy, drw->screen),
+-		                  DefaultColormap(drw->dpy, drw->screen));
++		d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
+ 		x += lpad;
+ 		w -= lpad;
+ 	}
+diff -up a/drw.h b/drw.h
+--- a/drw.h	2019-02-02 13:55:28.000000000 +0100
++++ b/drw.h	2019-03-12 18:34:52.780703276 +0100
+@@ -20,6 +20,9 @@ typedef struct {
+ 	Display *dpy;
+ 	int screen;
+ 	Window root;
++	Visual *visual;
++	unsigned int depth;
++	Colormap cmap;
+ 	Drawable drawable;
+ 	GC gc;
+ 	Clr *scheme;
+@@ -27,7 +30,7 @@ typedef struct {
+ } Drw;
+ 
+ /* Drawable abstraction */
+-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
++Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
+ void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+ void drw_free(Drw *drw);
+ 
+@@ -38,8 +41,8 @@ unsigned int drw_fontset_getwidth(Drw *d
+ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
+ 
+ /* Colorscheme abstraction */
+-void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
+-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
++void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
++Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
+ 
+ /* Cursor abstraction */
+ Cur *drw_cur_create(Drw *drw, int shape);
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c	2019-03-13 09:31:38.313322535 +0100
++++ b/dwm.c	2019-03-12 18:34:52.780703276 +0100
+@@ -58,6 +58,8 @@
+ #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
+ #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
+ 
++#define OPAQUE                  0xffU
++
+ #define SYSTEM_TRAY_REQUEST_DOCK    0
+ 
+ /* XEMBED messages */
+@@ -74,6 +76,8 @@
+ #define VERSION_MINOR               0
+ #define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
+ 
++#define OPAQUE                  0xffU
++
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel, SchemeWarn, SchemeUrgent }; /* color schemes */
+@@ -272,6 +276,7 @@ static Client *wintosystrayicon(Window w
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
++static void xinitvisual();
+ static void zoom(const Arg *arg);
+ 
+ /* variables */
+@@ -310,6 +315,11 @@ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
+ 
++static int useargb = 0;
++static Visual *visual;
++static int depth;
++static Colormap cmap;
++
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+ 
+@@ -1786,7 +1796,8 @@ setup(void)
+ 	sw = DisplayWidth(dpy, screen);
+ 	sh = DisplayHeight(dpy, screen);
+ 	root = RootWindow(dpy, screen);
+-	drw = drw_create(dpy, screen, root, sw, sh);
++	xinitvisual();
++	drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
+ 	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ 		die("no fonts could be loaded.");
+ 	lrpad = drw->fonts->h;
+@@ -1821,7 +1832,7 @@ setup(void)
+ 	/* init appearance */
+ 	scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ 	for (i = 0; i < LENGTH(colors); i++)
+-		scheme[i] = drw_scm_create(drw, colors[i], 3);
++		scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
+ 	/* init system tray */
+ 	updatesystray();
+ 	/* init bars */
+@@ -2098,7 +2109,9 @@ updatebars(void)
+ 	Monitor *m;
+ 	XSetWindowAttributes wa = {
+ 		.override_redirect = True,
+-		.background_pixmap = ParentRelative,
++		.background_pixel = 0,
++		.border_pixel = 0,
++		.colormap = cmap,
+ 		.event_mask = ButtonPressMask|ExposureMask
+ 	};
+ 	XClassHint ch = {"dwm", "dwm"};
+@@ -2108,9 +2121,9 @@ updatebars(void)
+ 		w = m->ww;
+ 		if (showsystray && m == systraytomon(m))
+ 			w -= getsystraywidth();
+-		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
+-				CopyFromParent, DefaultVisual(dpy, screen),
+-				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
++		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
++		                          InputOutput, visual,
++		                          CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ 		if (showsystray && m == systraytomon(m))
+ 			XMapRaised(dpy, systray->win);
+@@ -2403,7 +2416,8 @@ updatesystray(void)
+ 	XMapSubwindows(dpy, systray->win);
+ 	/* redraw background */
+ 	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
+-	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
++//	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
++    XFillRectangle(dpy, systray->win, XCreateGC(dpy, root, 0, NULL), 0, 0, w, bh);
+ 	XSync(dpy, False);
+ }
+ 
+@@ -2552,6 +2566,43 @@ systraytomon(Monitor *m) {
+ }
+ 
+ void
++xinitvisual()
++{
++	XVisualInfo *infos;
++	XRenderPictFormat *fmt;
++	int nitems;
++	int i;
++
++	XVisualInfo tpl = {
++		.screen = screen,
++		.depth = 32,
++		.class = TrueColor
++	};
++	long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
++
++	infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
++	visual = NULL;
++	for(i = 0; i < nitems; i ++) {
++		fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
++		if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
++			visual = infos[i].visual;
++			depth = infos[i].depth;
++			cmap = XCreateColormap(dpy, root, visual, AllocNone);
++			useargb = 1;
++			break;
++		}
++	}
++
++	XFree(infos);
++
++	if (! visual) {
++		visual = DefaultVisual(dpy, screen);
++		depth = DefaultDepth(dpy, screen);
++		cmap = DefaultColormap(dpy, screen);
++	}
++}
++
++void
+ zoom(const Arg *arg)
+ {
+ 	Client *c = selmon->sel;
+diff -up a/dwm.c.orig b/dwm.c.orig
+--- a/dwm.c.orig	2019-03-13 09:31:38.303322786 +0100
++++ b/dwm.c.orig	2019-03-12 18:34:52.780703276 +0100
+@@ -83,8 +83,8 @@ enum { NetSupported, NetWMName, NetWMSta
+        NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+-       ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
++enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkClientWin,
++       ClkRootWin, ClkLast }; /* clicks */
+ 
+ typedef union {
+ 	int i;
+@@ -246,6 +246,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglescratch(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -312,6 +313,8 @@ static Window root, wmcheckwin;
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+ 
++static unsigned int scratchtag = 1 << LENGTH(tags);
++
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+ 
+@@ -496,10 +499,8 @@ buttonpress(XEvent *e)
+ 			arg.ui = 1 << i;
+ 		} else if (ev->x < x + blw)
+ 			click = ClkLtSymbol;
+-		else if (ev->x > selmon->ww - TEXTW(stext))
+-			click = ClkStatusText;
+ 		else
+-			click = ClkWinTitle;
++			click = ClkStatusText;
+ 	} else if ((c = wintoclient(ev->window))) {
+ 		focus(c);
+ 		restack(selmon);
+@@ -872,15 +873,8 @@ drawbar(Monitor *m)
+ 	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+ 
+ 	if ((w = m->ww - sw - stw - x) > bh) {
+-		if (m->sel) {
+-			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+-			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+-			if (m->sel->isfloating)
+-				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+-		} else {
+ 			drw_setscheme(drw, scheme[SchemeNorm]);
+ 			drw_rect(drw, x, 0, w, bh, 1, 1);
+-		}
+ 	}
+ 	drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
+ }
+@@ -1212,6 +1206,13 @@ manage(Window w, XWindowAttributes *wa)
+ 		&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+ 	c->bw = borderpx;
+ 
++	if (!strcmp(c->name, scratchpadname)) {
++		c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag;
++		c->isfloating = True;
++		c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
++		c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
++	}
++
+ 	wc.border_width = c->bw;
+ 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ 	XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+@@ -1424,11 +1425,8 @@ propertynotify(XEvent *e)
+ 			drawbars();
+ 			break;
+ 		}
+-		if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
++		if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName])
+ 			updatetitle(c);
+-			if (c == c->mon->sel)
+-				drawbar(c->mon);
+-		}
+ 		if (ev->atom == netatom[NetWMWindowType])
+ 			updatewindowtype(c);
+ 	}
+@@ -1987,6 +1985,28 @@ togglefloating(const Arg *arg)
+ }
+ 
+ void
++togglescratch(const Arg *arg)
++{
++	Client *c;
++	unsigned int found = 0;
++
++	for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next);
++	if (found) {
++		unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
++		if (newtagset) {
++			selmon->tagset[selmon->seltags] = newtagset;
++			focus(NULL);
++			arrange(selmon);
++		}
++		if (ISVISIBLE(c)) {
++			focus(c);
++			restack(selmon);
++		}
++	} else
++		spawn(arg);
++}
++
++void
+ toggletag(const Arg *arg)
+ {
+ 	unsigned int newtags;
diff --git a/tmp/6.1/systray.diff b/tmp/6.1/systray.diff
new file mode 100644
index 0000000..7ef94a1
--- /dev/null
+++ b/tmp/6.1/systray.diff
@@ -0,0 +1,681 @@
+diff -up a/config.def.h b/config.def.h
+--- ./config.def.h	2019-02-17 18:32:30.909694411 +0100
++++ ../../tmp/6.1/alpha-systray/dwm-6.1/config.def.h	2019-02-17 18:31:39.294322241 +0100
+@@ -15,6 +15,10 @@ static unsigned int baralpha        = 0x
+ static unsigned int borderalpha     = OPAQUE;
+ static const unsigned int borderpx  = 1;        /* border pixel of windows */
+ static const unsigned int snap      = 32;       /* snap pixel */
++static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
++static const unsigned int systrayspacing = 2;   /* systray spacing */
++static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, 0: display systray on the last monitor*/
++static const int showsystray        = 1;        /* 0 means no systray */
+ static const int showbar            = 1;        /* 0 means no bar */
+ static const int topbar             = 1;        /* 0 means bottom bar */
+ 
+diff -up a/dwm.c b/dwm-6.1/dwm.c
+--- ./dwm.c	2019-02-17 18:32:30.909694411 +0100
++++ ../../tmp/6.1/alpha-systray/dwm-6.1/dwm.c	2019-02-17 18:31:39.294322241 +0100
+@@ -59,12 +59,30 @@
+ 
+ #define OPAQUE                  0xffU
+ 
++#define SYSTEM_TRAY_REQUEST_DOCK    0
++#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
++
++/* XEMBED messages */
++#define XEMBED_EMBEDDED_NOTIFY      0
++#define XEMBED_WINDOW_ACTIVATE      1
++#define XEMBED_FOCUS_IN             4
++#define XEMBED_MODALITY_ON         10
++
++#define XEMBED_MAPPED              (1 << 0)
++#define XEMBED_WINDOW_ACTIVATE      1
++#define XEMBED_WINDOW_DEACTIVATE    2
++
++#define VERSION_MAJOR               0
++#define VERSION_MINOR               0
++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
++
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
+-enum { NetSupported, NetWMName, NetWMState,
+-       NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+-       NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
++	   NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType,
++	   NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+@@ -143,6 +161,12 @@ typedef struct {
+ 	int monitor;
+ } Rule;
+ 
++typedef struct Systray   Systray;
++struct Systray {
++	Window win;
++	Client *icons;
++};
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+@@ -172,8 +196,10 @@ static void focus(Client *c);
+ static void focusin(XEvent *e);
+ static void focusmon(const Arg *arg);
+ static void focusstack(const Arg *arg);
++static Atom getatomprop(Client *c, Atom prop);
+ static int getrootptr(int *x, int *y);
+ static long getstate(Window w);
++static unsigned int getsystraywidth();
+ static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
+ static void grabbuttons(Client *c, int focused);
+ static void grabkeys(void);
+@@ -191,13 +217,16 @@ static void pop(Client *);
+ static void propertynotify(XEvent *e);
+ static void quit(const Arg *arg);
+ static Monitor *recttomon(int x, int y, int w, int h);
++static void removesystrayicon(Client *i);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
++static void resizebarwin(Monitor *m);
+ static void resizeclient(Client *c, int x, int y, int w, int h);
+ static void resizemouse(const Arg *arg);
++static void resizerequest(XEvent *e);
+ static void restack(Monitor *m);
+ static void run(void);
+ static void scan(void);
+-static int sendevent(Client *c, Atom proto);
++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
+ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+@@ -208,6 +237,7 @@ static void setup(void);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static Monitor *systraytomon(Monitor *m);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+@@ -225,12 +255,16 @@ static void updateclientlist(void);
+ static void updatenumlockmask(void);
+ static void updatesizehints(Client *c);
+ static void updatestatus(void);
++static void updatesystray(void);
++static void updatesystrayicongeom(Client *i, int w, int h);
++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
+ static void updatewindowtype(Client *c);
+ static void updatetitle(Client *c);
+ static void updatewmhints(Client *c);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
++static Client *wintosystrayicon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+@@ -238,6 +272,8 @@ static void xinitvisual();
+ static void zoom(const Arg *arg);
+ 
+ /* variables */
++static Systray *systray = NULL;
++static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
+ static const char broken[] = "broken";
+ static char stext[256];
+ static int screen;
+@@ -259,9 +295,10 @@ static void (*handler[LASTEvent]) (XEven
+ 	[MapRequest] = maprequest,
+ 	[MotionNotify] = motionnotify,
+ 	[PropertyNotify] = propertynotify,
++	[ResizeRequest] = resizerequest,
+ 	[UnmapNotify] = unmapnotify
+ };
+-static Atom wmatom[WMLast], netatom[NetLast];
++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
+ static int running = 1;
+ static Cur *cursor[CurLast];
+ static ClrScheme scheme[SchemeLast];
+@@ -502,6 +539,11 @@ cleanup(void)
+ 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ 	while (mons)
+ 		cleanupmon(mons);
++	if (showsystray) {
++		XUnmapWindow(dpy, systray->win);
++		XDestroyWindow(dpy, systray->win);
++		free(systray);
++	}
+ 	for (i = 0; i < CurLast; i++)
+ 		drw_cur_free(drw, cursor[i]);
+ 	for (i = 0; i < SchemeLast; i++) {
+@@ -547,9 +589,50 @@ clearurgent(Client *c)
+ void
+ clientmessage(XEvent *e)
+ {
++	XWindowAttributes wa;
++	XSetWindowAttributes swa;
+ 	XClientMessageEvent *cme = &e->xclient;
+ 	Client *c = wintoclient(cme->window);
+ 
++	if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
++		/* add systray icons */
++		if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
++			if (!(c = (Client *)calloc(1, sizeof(Client))))
++				die("fatal: could not malloc() %u bytes\n", sizeof(Client));
++			c->win = cme->data.l[2];
++			c->mon = selmon;
++			c->next = systray->icons;
++			systray->icons = c;
++			XGetWindowAttributes(dpy, c->win, &wa);
++			c->x = c->oldx = c->y = c->oldy = 0;
++			c->w = c->oldw = wa.width;
++			c->h = c->oldh = wa.height;
++			c->oldbw = wa.border_width;
++			c->bw = 0;
++			c->isfloating = True;
++			/* reuse tags field as mapped status */
++			c->tags = 1;
++			updatesizehints(c);
++			updatesystrayicongeom(c, wa.width, wa.height);
++			XAddToSaveSet(dpy, c->win);
++			XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
++			XReparentWindow(dpy, c->win, systray->win, 0, 0);
++			/* use parents background color */
++			swa.background_pixel  = scheme[SchemeNorm].bg->pix;
++			XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			/* FIXME not sure if I have to send these events, too */
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			XSync(dpy, False);
++			resizebarwin(selmon);
++			updatesystray();
++			setclientstate(c, NormalState);
++		}
++		return;
++	}
++
+ 	if (!c)
+ 		return;
+ 	if (cme->message_type == netatom[NetWMState]) {
+@@ -599,8 +682,7 @@ configurenotify(XEvent *e)
+ 		if (updategeom() || dirty) {
+ 			drw_resize(drw, sw, bh);
+ 			updatebars();
+-			for (m = mons; m; m = m->next)
+-				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
++			resizebarwin(m);
+ 			focus(NULL);
+ 			arrange(NULL);
+ 		}
+@@ -684,6 +766,11 @@ destroynotify(XEvent *e)
+ 
+ 	if ((c = wintoclient(ev->window)))
+ 		unmanage(c, 1);
++	else if ((c = wintosystrayicon(ev->window))) {
++		removesystrayicon(c);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ }
+ 
+ void
+@@ -755,6 +842,9 @@ drawbar(Monitor *m)
+ 	if (m == selmon) { /* status is only drawn on selected monitor */
+ 		w = TEXTW(stext);
+ 		x = m->ww - w;
++		if (showsystray && m == systraytomon(m)) {
++			x -= getsystraywidth();
++		}
+ 		if (x < xx) {
+ 			x = xx;
+ 			w = m->ww - xx;
+@@ -783,6 +873,7 @@ drawbars(void)
+ 
+ 	for (m = mons; m; m = m->next)
+ 		drawbar(m);
++	updatesystray();
+ }
+ 
+ void
+@@ -810,8 +901,11 @@ expose(XEvent *e)
+ 	Monitor *m;
+ 	XExposeEvent *ev = &e->xexpose;
+ 
+-	if (ev->count == 0 && (m = wintomon(ev->window)))
+-		drawbar(m);
++	if (ev->count == 0 && (m = wintomon(ev->window))) {
++ 		drawbar(m);
++		if (m == selmon)
++			updatesystray();
++	}
+ }
+ 
+ void
+@@ -898,15 +992,31 @@ getatomprop(Client *c, Atom prop)
+ 	unsigned long dl;
+ 	unsigned char *p = NULL;
+ 	Atom da, atom = None;
++	/* FIXME getatomprop should return the number of items and a pointer to
++	 * the stored data instead of this workaround */
++	Atom req = XA_ATOM;
++	if (prop == xatom[XembedInfo])
++		req = xatom[XembedInfo];
+ 
+-	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
++	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
+ 	                      &da, &di, &dl, &dl, &p) == Success && p) {
+ 		atom = *(Atom *)p;
++		if (da == xatom[XembedInfo] && dl == 2)
++			atom = ((Atom *)p)[1];
+ 		XFree(p);
+ 	}
+ 	return atom;
+ }
+ 
++unsigned int
++getsystraywidth() {
++	unsigned int w = 0;
++	Client *i;
++	if (showsystray)
++		for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
++	return w ? w + systrayspacing : 1;
++}
++
+ int
+ getrootptr(int *x, int *y)
+ {
+@@ -1041,7 +1151,7 @@ killclient(const Arg *arg)
+ {
+ 	if (!selmon->sel)
+ 		return;
+-	if (!sendevent(selmon->sel, wmatom[WMDelete])) {
++	if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
+ 		XGrabServer(dpy);
+ 		XSetErrorHandler(xerrordummy);
+ 		XSetCloseDownMode(dpy, DestroyAll);
+@@ -1128,7 +1238,12 @@ maprequest(XEvent *e)
+ {
+ 	static XWindowAttributes wa;
+ 	XMapRequestEvent *ev = &e->xmaprequest;
+-
++	Client *i;
++	if ((i = wintosystrayicon(ev->window))) {
++		sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ 	if (!XGetWindowAttributes(dpy, ev->window, &wa))
+ 		return;
+ 	if (wa.override_redirect)
+@@ -1264,6 +1379,16 @@ propertynotify(XEvent *e)
+ 	Window trans;
+ 	XPropertyEvent *ev = &e->xproperty;
+ 
++	if ((c = wintosystrayicon(ev->window))) {
++		if (ev->atom == XA_WM_NORMAL_HINTS) {
++			updatesizehints(c);
++			updatesystrayicongeom(c, c->w, c->h);
++		}
++		else
++			updatesystrayiconstate(c, ev);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ 	if ((ev->window == root) && (ev->atom == XA_WM_NAME))
+ 		updatestatus();
+ 	else if (ev->state == PropertyDelete)
+@@ -1294,6 +1419,18 @@ propertynotify(XEvent *e)
+ 	}
+ }
+ 
++ void
++removesystrayicon(Client *i) {
++	Client **ii;
++
++	if (!showsystray || !i)
++		return;
++	for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
++	if (ii)
++		*ii = i->next;
++	free(i);
++}
++
+ void
+ quit(const Arg *arg)
+ {
+@@ -1322,6 +1459,14 @@ resize(Client *c, int x, int y, int w, i
+ }
+ 
+ void
++resizebarwin(Monitor *m) {
++	unsigned int w = m->ww;
++	if (showsystray && m == systraytomon(m))
++		w -= getsystraywidth();
++	XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
++}
++
++void
+ resizeclient(Client *c, int x, int y, int w, int h)
+ {
+ 	XWindowChanges wc;
+@@ -1337,6 +1482,18 @@ resizeclient(Client *c, int x, int y, in
+ }
+ 
+ void
++resizerequest(XEvent *e) {
++	XResizeRequestEvent *ev = &e->xresizerequest;
++	Client *i;
++
++	if ((i = wintosystrayicon(ev->window))) {
++		updatesystrayicongeom(i, ev->width, ev->height);
++		resizebarwin(selmon);
++		updatesystray();
++	}
++}
++
++void
+ resizemouse(const Arg *arg)
+ {
+ 	int ocx, ocy, nw, nh;
+@@ -1482,26 +1639,36 @@ setclientstate(Client *c, long state)
+ }
+ 
+ int
+-sendevent(Client *c, Atom proto)
++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
+ {
+ 	int n;
+-	Atom *protocols;
++	Atom *protocols, mt;
+ 	int exists = 0;
+ 	XEvent ev;
+ 
+-	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+-		while (!exists && n--)
+-			exists = protocols[n] == proto;
+-		XFree(protocols);
++	if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
++		mt = wmatom[WMProtocols];
++		if (XGetWMProtocols(dpy, w, &protocols, &n)) {
++			while(!exists && n--)
++				exists = protocols[n] == proto;
++			XFree(protocols);
++		}
++	}
++	else {
++		exists = True;
++		mt = proto;
+ 	}
+ 	if (exists) {
+ 		ev.type = ClientMessage;
+-		ev.xclient.window = c->win;
+-		ev.xclient.message_type = wmatom[WMProtocols];
++		ev.xclient.window = w;
++		ev.xclient.message_type = mt;
+ 		ev.xclient.format = 32;
+-		ev.xclient.data.l[0] = proto;
+-		ev.xclient.data.l[1] = CurrentTime;
+-		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
++		ev.xclient.data.l[0] = d0;
++		ev.xclient.data.l[1] = d1;
++		ev.xclient.data.l[2] = d2;
++		ev.xclient.data.l[3] = d3;
++		ev.xclient.data.l[4] = d4;
++		XSendEvent(dpy, w, False, mask, &ev);
+ 	}
+ 	return exists;
+ }
+@@ -1515,7 +1682,7 @@ setfocus(Client *c)
+ 		                XA_WINDOW, 32, PropModeReplace,
+ 		                (unsigned char *) &(c->win), 1);
+ 	}
+-	sendevent(c, wmatom[WMTakeFocus]);
++	sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
+ }
+ 
+ void
+@@ -1602,12 +1769,18 @@ setup(void)
+ 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
+ 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
++	netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
++	netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
++	netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
+ 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+ 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ 	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ 	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
++	xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
++	xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
++	xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
+ 	/* init cursors */
+ 	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ 	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+@@ -1619,6 +1792,8 @@ setup(void)
+ 	scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor, borderalpha);
+ 	scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor, baralpha);
+ 	scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor, OPAQUE);
++	/* init system tray */
++	updatesystray();
+ 	/* init bars */
+ 	updatebars();
+ 	updatestatus();
+@@ -1678,6 +1853,22 @@ spawn(const Arg *arg)
+ 	}
+ }
+ 
++Monitor *
++systraytomon(Monitor *m) {
++	Monitor *t;
++	int i, n;
++	if (!systraypinning) {
++		if (!m)
++			return selmon;
++		return m == selmon ? m : NULL;
++	}
++	for (n = 1, t = mons; t && t->next; n++, t = t->next);
++	for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next);
++	if (systraypinningfailfirst && n < systraypinning)
++		return mons;
++	return t;
++}
++
+ void
+ tag(const Arg *arg)
+ {
+@@ -1727,7 +1918,18 @@ togglebar(const Arg *arg)
+ {
+ 	selmon->showbar = !selmon->showbar;
+ 	updatebarpos(selmon);
+-	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
++	resizebarwin(selmon);
++	if (showsystray) {
++		XWindowChanges wc;
++		if (!selmon->showbar)
++			wc.y = -bh;
++		else if (selmon->showbar) {
++			wc.y = 0;
++			if (!selmon->topbar)
++				wc.y = selmon->mh - bh;
++		}
++		XConfigureWindow(dpy, systray->win, CWY, &wc);
++	}
+ 	arrange(selmon);
+ }
+ 
+@@ -1828,11 +2030,17 @@ unmapnotify(XEvent *e)
+ 		else
+ 			unmanage(c, 0);
+ 	}
++	else if ((c = wintosystrayicon(ev->window))) {
++		removesystrayicon(c);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ }
+ 
+ void
+ updatebars(void)
+ {
++	unsigned int w;
+ 	Monitor *m;
+ 	XSetWindowAttributes wa = {
+ 		.override_redirect = True,
+@@ -1844,10 +2052,15 @@ updatebars(void)
+ 	for (m = mons; m; m = m->next) {
+ 		if (m->barwin)
+ 			continue;
+-		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
++		w = m->ww;
++		if (showsystray && m == systraytomon(m))
++			w -= getsystraywidth();
++		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
+ 		                          InputOutput, visual,
+ 		                          CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
++		if (showsystray && m == systraytomon(m))
++			XMapRaised(dpy, systray->win);
+ 		XMapRaised(dpy, m->barwin);
+ 	}
+ }
+@@ -2037,6 +2250,118 @@ updatestatus(void)
+ 	drawbar(selmon);
+ }
+ 
++
++void
++updatesystrayicongeom(Client *i, int w, int h) {
++	if (i) {
++		i->h = bh;
++		if (w == h)
++			i->w = bh;
++		else if (h == bh)
++			i->w = w;
++		else
++			i->w = (int) ((float)bh * ((float)w / (float)h));
++		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
++		/* force icons into the systray dimenons if they don't want to */
++		if (i->h > bh) {
++			if (i->w == i->h)
++				i->w = bh;
++			else
++				i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
++			i->h = bh;
++		}
++	}
++}
++
++void
++updatesystrayiconstate(Client *i, XPropertyEvent *ev) {
++	long flags;
++	int code = 0;
++
++	if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
++			!(flags = getatomprop(i, xatom[XembedInfo])))
++		return;
++
++	if (flags & XEMBED_MAPPED && !i->tags) {
++		i->tags = 1;
++		code = XEMBED_WINDOW_ACTIVATE;
++		XMapRaised(dpy, i->win);
++		setclientstate(i, NormalState);
++	}
++	else if (!(flags & XEMBED_MAPPED) && i->tags) {
++		i->tags = 0;
++		code = XEMBED_WINDOW_DEACTIVATE;
++		XUnmapWindow(dpy, i->win);
++		setclientstate(i, WithdrawnState);
++	}
++	else
++		return;
++	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
++			systray->win, XEMBED_EMBEDDED_VERSION);
++}
++
++void
++updatesystray(void) {
++	XSetWindowAttributes wa;
++	XWindowChanges wc;
++	Client *i;
++	Monitor *m = systraytomon(NULL);
++	unsigned int x = m->mx + m->mw;
++	unsigned int w = 1;
++
++	if (!showsystray)
++		return;
++	if (!systray) {
++		/* init systray */
++		if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
++			die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
++		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->pix);
++		wa.event_mask        = ButtonPressMask | ExposureMask;
++		wa.override_redirect = True;
++		wa.background_pixel  = scheme[SchemeNorm].bg->pix;
++		XSelectInput(dpy, systray->win, SubstructureNotifyMask);
++		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
++				PropModeReplace, (unsigned char *)&systrayorientation, 1);
++		XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
++		XMapRaised(dpy, systray->win);
++		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
++		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
++			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
++			XSync(dpy, False);
++		}
++		else {
++			fprintf(stderr, "dwm: unable to obtain system tray.\n");
++			free(systray);
++			systray = NULL;
++			return;
++		}
++	}
++	for (w = 0, i = systray->icons; i; i = i->next) {
++		/* make sure the background color stays the same */
++		wa.background_pixel  = scheme[SchemeNorm].bg->pix;
++		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
++		XMapRaised(dpy, i->win);
++		w += systrayspacing;
++		i->x = w;
++		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
++		w += i->w;
++		if (i->mon != m)
++			i->mon = m;
++	}
++	w = w ? w + systrayspacing : 1;
++	x -= w;
++	XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
++	wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
++	wc.stack_mode = Above; wc.sibling = m->barwin;
++	XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
++	XMapWindow(dpy, systray->win);
++	XMapSubwindows(dpy, systray->win);
++	/* redraw background */
++	XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->pix);
++	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
++	XSync(dpy, False);
++}
++
+ void
+ updatewindowtype(Client *c)
+ {
+@@ -2049,6 +2374,16 @@ updatewindowtype(Client *c)
+ 		c->isfloating = 1;
+ }
+ 
++Client *
++wintosystrayicon(Window w) {
++	Client *i = NULL;
++
++	if (!showsystray || !w)
++		return i;
++	for (i = systray->icons; i && i->win != w; i = i->next);
++	return i;
++}
++
+ void
+ updatewmhints(Client *c)
+ {
diff --git a/tmp/6.2/systray.diff b/tmp/6.2/systray.diff
new file mode 100644
index 0000000..df6f3d6
--- /dev/null
+++ b/tmp/6.2/systray.diff
@@ -0,0 +1,715 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h	2019-02-14 17:19:07.650096523 +0100
++++ b/config.def.h	2019-02-15 14:23:33.763240723 +0100
+@@ -3,6 +3,10 @@
+ /* appearance */
+ static const unsigned int borderpx  = 1;        /* border pixel of windows */
+ static const unsigned int snap      = 32;       /* snap pixel */
++static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
++static const unsigned int systrayspacing = 2;   /* systray spacing */
++static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
++static const int showsystray        = 1;     /* 0 means no systray */
+ static const int showbar            = 1;        /* 0 means no bar */
+ static const int topbar             = 1;        /* 0 means bottom bar */
+ static const char *fonts[]          = { "monospace:size=10" };
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c	2019-02-14 17:19:07.653429773 +0100
++++ b/dwm.c	2019-02-15 14:23:33.763240723 +0100
+@@ -59,12 +59,30 @@
+ 
+ #define OPAQUE                  0xffU
+ 
++#define SYSTEM_TRAY_REQUEST_DOCK    0
++
++/* XEMBED messages */
++#define XEMBED_EMBEDDED_NOTIFY      0
++#define XEMBED_WINDOW_ACTIVATE      1
++#define XEMBED_FOCUS_IN             4
++#define XEMBED_MODALITY_ON         10
++
++#define XEMBED_MAPPED              (1 << 0)
++#define XEMBED_WINDOW_ACTIVATE      1
++#define XEMBED_WINDOW_DEACTIVATE    2
++
++#define VERSION_MAJOR               0
++#define VERSION_MINOR               0
++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
++
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
++       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
+        NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+        NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+@@ -143,6 +161,12 @@ typedef struct {
+ 	int monitor;
+ } Rule;
+ 
++typedef struct Systray   Systray;
++struct Systray {
++	Window win;
++	Client *icons;
++};
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+@@ -171,8 +195,10 @@ static void focus(Client *c);
+ static void focusin(XEvent *e);
+ static void focusmon(const Arg *arg);
+ static void focusstack(const Arg *arg);
++static Atom getatomprop(Client *c, Atom prop);
+ static int getrootptr(int *x, int *y);
+ static long getstate(Window w);
++static unsigned int getsystraywidth();
+ static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
+ static void grabbuttons(Client *c, int focused);
+ static void grabkeys(void);
+@@ -190,13 +216,16 @@ static void pop(Client *);
+ static void propertynotify(XEvent *e);
+ static void quit(const Arg *arg);
+ static Monitor *recttomon(int x, int y, int w, int h);
++static void removesystrayicon(Client *i);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
++static void resizebarwin(Monitor *m);
+ static void resizeclient(Client *c, int x, int y, int w, int h);
+ static void resizemouse(const Arg *arg);
++static void resizerequest(XEvent *e);
+ static void restack(Monitor *m);
+ static void run(void);
+ static void scan(void);
+-static int sendevent(Client *c, Atom proto);
++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
+ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+@@ -208,6 +237,7 @@ static void seturgent(Client *c, int urg
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static Monitor *systraytomon(Monitor *m);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+@@ -225,12 +255,16 @@ static int updategeom(void);
+ static void updatenumlockmask(void);
+ static void updatesizehints(Client *c);
+ static void updatestatus(void);
++static void updatesystray(void);
++static void updatesystrayicongeom(Client *i, int w, int h);
++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
+ static void updatetitle(Client *c);
+ static void updatewindowtype(Client *c);
+ static void updatewmhints(Client *c);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
++static Client *wintosystrayicon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+@@ -238,6 +272,7 @@ static void xinitvisual();
+ static void zoom(const Arg *arg);
+ 
+ /* variables */
++static Systray *systray =  NULL;
+ static const char broken[] = "broken";
+ static char stext[256];
+ static int screen;
+@@ -260,9 +295,10 @@ static void (*handler[LASTEvent]) (XEven
+ 	[MapRequest] = maprequest,
+ 	[MotionNotify] = motionnotify,
+ 	[PropertyNotify] = propertynotify,
++	[ResizeRequest] = resizerequest,
+ 	[UnmapNotify] = unmapnotify
+ };
+-static Atom wmatom[WMLast], netatom[NetLast];
++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
+ static int running = 1;
+ static Cur *cursor[CurLast];
+ static Clr **scheme;
+@@ -490,6 +526,11 @@ cleanup(void)
+ 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ 	while (mons)
+ 		cleanupmon(mons);
++	if (showsystray) {
++		XUnmapWindow(dpy, systray->win);
++		XDestroyWindow(dpy, systray->win);
++		free(systray);
++	}
+ 	for (i = 0; i < CurLast; i++)
+ 		drw_cur_free(drw, cursor[i]);
+ 	for (i = 0; i < LENGTH(colors); i++)
+@@ -520,9 +561,53 @@ cleanupmon(Monitor *mon)
+ void
+ clientmessage(XEvent *e)
+ {
++	XWindowAttributes wa;
++	XSetWindowAttributes swa;
+ 	XClientMessageEvent *cme = &e->xclient;
+ 	Client *c = wintoclient(cme->window);
+ 
++	if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
++		/* add systray icons */
++		if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
++			if (!(c = (Client *)calloc(1, sizeof(Client))))
++				die("fatal: could not malloc() %u bytes\n", sizeof(Client));
++			if (!(c->win = cme->data.l[2])) {
++				free(c);
++				return;
++			}
++			c->mon = selmon;
++			c->next = systray->icons;
++			systray->icons = c;
++			XGetWindowAttributes(dpy, c->win, &wa);
++			c->x = c->oldx = c->y = c->oldy = 0;
++			c->w = c->oldw = wa.width;
++			c->h = c->oldh = wa.height;
++			c->oldbw = wa.border_width;
++			c->bw = 0;
++			c->isfloating = True;
++			/* reuse tags field as mapped status */
++			c->tags = 1;
++			updatesizehints(c);
++			updatesystrayicongeom(c, wa.width, wa.height);
++			XAddToSaveSet(dpy, c->win);
++			XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
++			XReparentWindow(dpy, c->win, systray->win, 0, 0);
++			/* use parents background color */
++			swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
++			XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			/* FIXME not sure if I have to send these events, too */
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
++			XSync(dpy, False);
++			resizebarwin(selmon);
++			updatesystray();
++			setclientstate(c, NormalState);
++		}
++		return;
++	}
++
+ 	if (!c)
+ 		return;
+ 	if (cme->message_type == netatom[NetWMState]) {
+@@ -575,7 +660,7 @@ configurenotify(XEvent *e)
+ 				for (c = m->clients; c; c = c->next)
+ 					if (c->isfullscreen)
+ 						resizeclient(c, m->mx, m->my, m->mw, m->mh);
+-				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
++				resizebarwin(m);
+ 			}
+ 			focus(NULL);
+ 			arrange(NULL);
+@@ -660,6 +745,11 @@ destroynotify(XEvent *e)
+ 
+ 	if ((c = wintoclient(ev->window)))
+ 		unmanage(c, 1);
++	else if ((c = wintosystrayicon(ev->window))) {
++		removesystrayicon(c);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ }
+ 
+ void
+@@ -703,19 +793,23 @@ dirtomon(int dir)
+ void
+ drawbar(Monitor *m)
+ {
+-	int x, w, sw = 0;
++	int x, w, sw = 0, stw = 0;
+ 	int boxs = drw->fonts->h / 9;
+ 	int boxw = drw->fonts->h / 6 + 2;
+ 	unsigned int i, occ = 0, urg = 0;
+ 	Client *c;
+ 
+-	/* draw status first so it can be overdrawn by tags later */
++	if(showsystray && m == systraytomon(m))
++		stw = getsystraywidth();
++
++    /* draw status first so it can be overdrawn by tags later */
+ 	if (m == selmon) { /* status is only drawn on selected monitor */
+ 		drw_setscheme(drw, scheme[SchemeNorm]);
+-		sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+-		drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0);
++		sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
++		drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
+ 	}
+ 
++	resizebarwin(m);
+ 	for (c = m->clients; c; c = c->next) {
+ 		occ |= c->tags;
+ 		if (c->isurgent)
+@@ -736,7 +830,7 @@ drawbar(Monitor *m)
+ 	drw_setscheme(drw, scheme[SchemeNorm]);
+ 	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+ 
+-	if ((w = m->ww - sw - x) > bh) {
++	if ((w = m->ww - sw - stw - x) > bh) {
+ 		if (m->sel) {
+ 			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+ 			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+@@ -747,7 +841,7 @@ drawbar(Monitor *m)
+ 			drw_rect(drw, x, 0, w, bh, 1, 1);
+ 		}
+ 	}
+-	drw_map(drw, m->barwin, 0, 0, m->ww, bh);
++	drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
+ }
+ 
+ void
+@@ -784,8 +878,11 @@ expose(XEvent *e)
+ 	Monitor *m;
+ 	XExposeEvent *ev = &e->xexpose;
+ 
+-	if (ev->count == 0 && (m = wintomon(ev->window)))
++	if (ev->count == 0 && (m = wintomon(ev->window))) {
+ 		drawbar(m);
++		if (m == selmon)
++			updatesystray();
++	}
+ }
+ 
+ void
+@@ -870,10 +967,17 @@ getatomprop(Client *c, Atom prop)
+ 	unsigned long dl;
+ 	unsigned char *p = NULL;
+ 	Atom da, atom = None;
++	/* FIXME getatomprop should return the number of items and a pointer to
++	 * the stored data instead of this workaround */
++	Atom req = XA_ATOM;
++	if (prop == xatom[XembedInfo])
++		req = xatom[XembedInfo];
+ 
+ 	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
+ 		&da, &di, &dl, &dl, &p) == Success && p) {
+ 		atom = *(Atom *)p;
++		if (da == xatom[XembedInfo] && dl == 2)
++			atom = ((Atom *)p)[1];
+ 		XFree(p);
+ 	}
+ 	return atom;
+@@ -907,6 +1011,16 @@ getstate(Window w)
+ 	return result;
+ }
+ 
++unsigned int
++getsystraywidth()
++{
++	unsigned int w = 0;
++	Client *i;
++	if(showsystray)
++		for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
++	return w ? w + systrayspacing : 1;
++}
++
+ int
+ gettextprop(Window w, Atom atom, char *text, unsigned int size)
+ {
+@@ -1011,7 +1125,7 @@ killclient(const Arg *arg)
+ {
+ 	if (!selmon->sel)
+ 		return;
+-	if (!sendevent(selmon->sel, wmatom[WMDelete])) {
++	if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
+ 		XGrabServer(dpy);
+ 		XSetErrorHandler(xerrordummy);
+ 		XSetCloseDownMode(dpy, DestroyAll);
+@@ -1099,6 +1213,12 @@ maprequest(XEvent *e)
+ {
+ 	static XWindowAttributes wa;
+ 	XMapRequestEvent *ev = &e->xmaprequest;
++	Client *i;
++	if ((i = wintosystrayicon(ev->window))) {
++		sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ 
+ 	if (!XGetWindowAttributes(dpy, ev->window, &wa))
+ 		return;
+@@ -1223,6 +1343,16 @@ propertynotify(XEvent *e)
+ 	Window trans;
+ 	XPropertyEvent *ev = &e->xproperty;
+ 
++	if ((c = wintosystrayicon(ev->window))) {
++		if (ev->atom == XA_WM_NORMAL_HINTS) {
++			updatesizehints(c);
++			updatesystrayicongeom(c, c->w, c->h);
++		}
++		else
++			updatesystrayiconstate(c, ev);
++		resizebarwin(selmon);
++		updatesystray();
++	}
+ 	if ((ev->window == root) && (ev->atom == XA_WM_NAME))
+ 		updatestatus();
+ 	else if (ev->state == PropertyDelete)
+@@ -1254,6 +1384,19 @@ propertynotify(XEvent *e)
+ }
+ 
+ void
++removesystrayicon(Client *i)
++{
++	Client **ii;
++
++	if (!showsystray || !i)
++		return;
++	for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
++	if (ii)
++		*ii = i->next;
++	free(i);
++}
++
++void
+ quit(const Arg *arg)
+ {
+ 	running = 0;
+@@ -1281,6 +1424,14 @@ resize(Client *c, int x, int y, int w, i
+ }
+ 
+ void
++resizebarwin(Monitor *m) {
++	unsigned int w = m->ww;
++	if (showsystray && m == systraytomon(m))
++		w -= getsystraywidth();
++	XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
++}
++
++void
+ resizeclient(Client *c, int x, int y, int w, int h)
+ {
+ 	XWindowChanges wc;
+@@ -1303,6 +1454,19 @@ resizeclient(Client *c, int x, int y, in
+ }
+ 
+ void
++resizerequest(XEvent *e)
++{
++	XResizeRequestEvent *ev = &e->xresizerequest;
++	Client *i;
++
++	if ((i = wintosystrayicon(ev->window))) {
++		updatesystrayicongeom(i, ev->width, ev->height);
++		resizebarwin(selmon);
++		updatesystray();
++	}
++}
++
++void
+ resizemouse(const Arg *arg)
+ {
+ 	int ocx, ocy, nw, nh;
+@@ -1448,26 +1612,36 @@ setclientstate(Client *c, long state)
+ }
+ 
+ int
+-sendevent(Client *c, Atom proto)
++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
+ {
+ 	int n;
+-	Atom *protocols;
++	Atom *protocols, mt;
+ 	int exists = 0;
+ 	XEvent ev;
+ 
+-	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+-		while (!exists && n--)
+-			exists = protocols[n] == proto;
+-		XFree(protocols);
++	if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
++		mt = wmatom[WMProtocols];
++		if (XGetWMProtocols(dpy, w, &protocols, &n)) {
++			while (!exists && n--)
++				exists = protocols[n] == proto;
++			XFree(protocols);
++		}
++	}
++	else {
++		exists = True;
++		mt = proto;
+ 	}
+ 	if (exists) {
+ 		ev.type = ClientMessage;
+-		ev.xclient.window = c->win;
+-		ev.xclient.message_type = wmatom[WMProtocols];
++		ev.xclient.window = w;
++		ev.xclient.message_type = mt;
+ 		ev.xclient.format = 32;
+-		ev.xclient.data.l[0] = proto;
+-		ev.xclient.data.l[1] = CurrentTime;
+-		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
++		ev.xclient.data.l[0] = d0;
++		ev.xclient.data.l[1] = d1;
++		ev.xclient.data.l[2] = d2;
++		ev.xclient.data.l[3] = d3;
++		ev.xclient.data.l[4] = d4;
++		XSendEvent(dpy, w, False, mask, &ev);
+ 	}
+ 	return exists;
+ }
+@@ -1481,7 +1655,7 @@ setfocus(Client *c)
+ 			XA_WINDOW, 32, PropModeReplace,
+ 			(unsigned char *) &(c->win), 1);
+ 	}
+-	sendevent(c, wmatom[WMTakeFocus]);
++	sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
+ }
+ 
+ void
+@@ -1571,6 +1745,10 @@ setup(void)
+ 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
+ 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
++	netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
++	netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
++	netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
++	netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
+ 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+ 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ 	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+@@ -1578,6 +1756,9 @@ setup(void)
+ 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ 	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
++	xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
++	xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
++	xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
+ 	/* init cursors */
+ 	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ 	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+@@ -1586,6 +1767,8 @@ setup(void)
+ 	scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ 	for (i = 0; i < LENGTH(colors); i++)
+ 		scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
++	/* init system tray */
++	updatesystray();
+ 	/* init bars */
+ 	updatebars();
+ 	updatestatus();
+@@ -1717,7 +1900,18 @@ togglebar(const Arg *arg)
+ {
+ 	selmon->showbar = !selmon->showbar;
+ 	updatebarpos(selmon);
+-	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
++	resizebarwin(selmon);
++	if (showsystray) {
++		XWindowChanges wc;
++		if (!selmon->showbar)
++			wc.y = -bh;
++		else if (selmon->showbar) {
++			wc.y = 0;
++			if (!selmon->topbar)
++				wc.y = selmon->mh - bh;
++		}
++		XConfigureWindow(dpy, systray->win, CWY, &wc);
++	}
+ 	arrange(selmon);
+ }
+ 
+@@ -1812,11 +2006,18 @@ unmapnotify(XEvent *e)
+ 		else
+ 			unmanage(c, 0);
+ 	}
++	else if ((c = wintosystrayicon(ev->window))) {
++		/* KLUDGE! sometimes icons occasionally unmap their windows, but do
++		 * _not_ destroy them. We map those windows back */
++		XMapRaised(dpy, c->win);
++		updatesystray();
++	}
+ }
+ 
+ void
+ updatebars(void)
+ {
++	unsigned int w;
+ 	Monitor *m;
+ 	XSetWindowAttributes wa = {
+ 		.override_redirect = True,
+@@ -1829,10 +2030,15 @@ updatebars(void)
+ 	for (m = mons; m; m = m->next) {
+ 		if (m->barwin)
+ 			continue;
+-		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
++		w = m->ww;
++		if (showsystray && m == systraytomon(m))
++			w -= getsystraywidth();
++		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
+ 		                          InputOutput, visual,
+ 		                          CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
++		if (showsystray && m == systraytomon(m))
++			XMapRaised(dpy, systray->win);
+ 		XMapRaised(dpy, m->barwin);
+ 		XSetClassHint(dpy, m->barwin, &ch);
+ 	}
+@@ -2008,6 +2214,121 @@ updatestatus(void)
+ 	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+ 		strcpy(stext, "dwm-"VERSION);
+ 	drawbar(selmon);
++	updatesystray();
++}
++
++void
++updatesystrayicongeom(Client *i, int w, int h)
++{
++	if (i) {
++		i->h = bh;
++		if (w == h)
++			i->w = bh;
++		else if (h == bh)
++			i->w = w;
++		else
++			i->w = (int) ((float)bh * ((float)w / (float)h));
++		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
++		/* force icons into the systray dimenons if they don't want to */
++		if (i->h > bh) {
++			if (i->w == i->h)
++				i->w = bh;
++			else
++				i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
++			i->h = bh;
++		}
++	}
++}
++
++void
++updatesystrayiconstate(Client *i, XPropertyEvent *ev)
++{
++	long flags;
++	int code = 0;
++
++	if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
++			!(flags = getatomprop(i, xatom[XembedInfo])))
++		return;
++
++	if (flags & XEMBED_MAPPED && !i->tags) {
++		i->tags = 1;
++		code = XEMBED_WINDOW_ACTIVATE;
++		XMapRaised(dpy, i->win);
++		setclientstate(i, NormalState);
++	}
++	else if (!(flags & XEMBED_MAPPED) && i->tags) {
++		i->tags = 0;
++		code = XEMBED_WINDOW_DEACTIVATE;
++		XUnmapWindow(dpy, i->win);
++		setclientstate(i, WithdrawnState);
++	}
++	else
++		return;
++	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
++			systray->win, XEMBED_EMBEDDED_VERSION);
++}
++
++void
++updatesystray(void)
++{
++	XSetWindowAttributes wa;
++	XWindowChanges wc;
++	Client *i;
++	Monitor *m = systraytomon(NULL);
++	unsigned int x = m->mx + m->mw;
++	unsigned int w = 1;
++
++	if (!showsystray)
++		return;
++	if (!systray) {
++		/* init systray */
++		if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
++			die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
++		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
++		wa.event_mask        = ButtonPressMask | ExposureMask;
++		wa.override_redirect = True;
++		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
++		XSelectInput(dpy, systray->win, SubstructureNotifyMask);
++		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
++				PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
++		XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
++		XMapRaised(dpy, systray->win);
++		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
++		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
++			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
++			XSync(dpy, False);
++		}
++		else {
++			fprintf(stderr, "dwm: unable to obtain system tray.\n");
++			free(systray);
++			systray = NULL;
++			return;
++		}
++	}
++	for (w = 0, i = systray->icons; i; i = i->next) {
++		/* make sure the background color stays the same */
++		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
++		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
++		XMapRaised(dpy, i->win);
++		w += systrayspacing;
++		i->x = w;
++		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
++		w += i->w;
++		if (i->mon != m)
++			i->mon = m;
++	}
++	w = w ? w + systrayspacing : 1;
++	x -= w;
++	XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
++	wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
++	wc.stack_mode = Above; wc.sibling = m->barwin;
++	XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
++	XMapWindow(dpy, systray->win);
++	XMapSubwindows(dpy, systray->win);
++	/* redraw background */
++	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
++	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
++	XSync(dpy, False);
+ }
+ 
+ void
+@@ -2075,6 +2396,16 @@ wintoclient(Window w)
+ 	return NULL;
+ }
+ 
++Client *
++wintosystrayicon(Window w) {
++	Client *i = NULL;
++
++	if (!showsystray || !w)
++		return i;
++	for (i = systray->icons; i && i->win != w; i = i->next) ;
++	return i;
++}
++
+ Monitor *
+ wintomon(Window w)
+ {
+@@ -2092,6 +2423,22 @@ wintomon(Window w)
+ 	return selmon;
+ }
+ 
++Monitor *
++systraytomon(Monitor *m) {
++	Monitor *t;
++	int i, n;
++	if(!systraypinning) {
++		if(!m)
++			return selmon;
++		return m == selmon ? m : NULL;
++	}
++	for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
++	for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
++	if(systraypinningfailfirst && n < systraypinning)
++		return mons;
++	return t;
++}
++
+ /* There's no way to check accesses to destroyed windows, thus those cases are
+  * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
+  * default error handler, which may call exit. */