This patch is a merge b/w systray and alpha.

Additional changes are:
 - create systray->win with apropriate visual and attributes
 - utilize _NET_SYSTEM_TRAY_VISUAL to let tray icon alpha-aware
---
 config.def.h |  14 +-
 config.mk    |   2 +-
 drw.c        |  59 +++++++--
 drw.h        |   3 +
 dwm.c        | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 446 insertions(+), 41 deletions(-)

diff --git a/config.def.h b/config.def.h
index ba9a240..498b5bb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -3,15 +3,19 @@
 /* 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" };
 static const char dmenufont[]       = "monospace:size=10";
-static const char col_gray1[]       = "#222222";
-static const char col_gray2[]       = "#444444";
-static const char col_gray3[]       = "#bbbbbb";
-static const char col_gray4[]       = "#eeeeee";
-static const char col_cyan[]        = "#005577";
+static const char col_gray1[]       = "#222222\0A#dd";
+static const char col_gray2[]       = "#444444\0A#ff";
+static const char col_gray3[]       = "#bbbbbb\0A#ff";
+static const char col_gray4[]       = "#eeeeee\0A#ff";
+static const char col_cyan[]        = "#005577\0A#dd";
 static const char *colors[][3]      = {
        /*               fg         bg         border   */
        [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
diff --git a/config.mk b/config.mk
index 80dc936..2c62e89 100644
--- a/config.mk
+++ b/config.mk
@@ -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 --git a/drw.c b/drw.c
index 319eb6b..833e8d1 100644
--- a/drw.c
+++ b/drw.c
@@ -60,6 +60,39 @@ utf8decode(const char *c, long *u, size_t clen)
        return len;
 }
 
+static void
+drw_initvisual(Drw *drw, Display *dpy, int screen, Window root)
+{
+       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);
+       for(i = 0; i < nitems; i ++) {
+               fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
+               if (fmt->type == PictTypeDirect && fmt->direct.alphaMask)
+                       goto found;
+       }
+
+       drw->visual = DefaultVisual(dpy, screen);
+       drw->depth = DefaultDepth(dpy, screen);
+       drw->cmap = DefaultColormap(dpy, screen);
+       return;
+
+found:
+       drw->visual = infos[i].visual;
+       drw->depth = infos[i].depth;
+       drw->cmap = XCreateColormap(dpy, root, drw->visual, AllocNone);
+}
+
 Drw *
 drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int 
h)
 {
@@ -70,8 +103,9 @@ drw_create(Display *dpy, int screen, Window root, unsigned 
int w, unsigned int h
        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_initvisual(drw, dpy, screen, root);
+       drw->drawable = XCreatePixmap(dpy, root, w, h, drw->depth);
+       drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
        XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
 
        return drw;
@@ -87,7 +121,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
        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
@@ -182,13 +216,24 @@ drw_fontset_free(Fnt *font)
 void
 drw_clr_create(Drw *drw, XftColor *dest, const char *clrname)
 {
+       unsigned long alpha;
+       size_t i;
+
        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);
+
+       i = strlen(clrname) + 1;
+       if (clrname[i] == 'A' && clrname[i+1] == '#') {
+               alpha = strtoul(&clrname[i+2], NULL, 16);
+               printf("alpha : %lu\n", alpha);
+               dest->pixel &= 0x00ffffffUL;
+               dest->pixel |= alpha << 24;
+               dest->color.alpha = alpha << 8;
+       }
 }
 
 /* Wrapper to create color schemes. The caller has to call free(3) on the
@@ -260,9 +305,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
        } 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 --git a/drw.h b/drw.h
index ff4355b..b3b13aa 100644
--- a/drw.h
+++ b/drw.h
@@ -20,6 +20,9 @@ typedef struct {
        Display *dpy;
        int screen;
        Window root;
+       Visual *visual;
+       unsigned int depth;
+       Colormap cmap;
        Drawable drawable;
        GC gc;
        Scm scheme;
diff --git a/dwm.c b/dwm.c
index d27cb67..2fb2f5b 100644
--- a/dwm.c
+++ b/dwm.c
@@ -58,12 +58,30 @@
 #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
 #define ColBorder               2
 
+#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, NetSystemTrayVisual,
        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 */
@@ -142,6 +160,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);
@@ -170,8 +194,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);
@@ -189,13 +215,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);
@@ -207,6 +236,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 *);
@@ -224,18 +254,23 @@ 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);
 static void zoom(const Arg *arg);
 
 /* variables */
+static Systray *systray = NULL;
 static const char broken[] = "broken";
 static char stext[256];
 static int screen;
@@ -258,9 +293,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
        [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 Scm *scheme;
@@ -481,6 +517,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++)
@@ -511,9 +552,52 @@ 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]) {
@@ -565,7 +649,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);
@@ -650,6 +734,11 @@ destroynotify(XEvent *e)
 
        if ((c = wintoclient(ev->window)))
                unmanage(c, 1);
+       else if ((c = wintosystrayicon(ev->window))) {
+               removesystrayicon(c);
+               resizebarwin(selmon);
+               updatesystray();
+       }
 }
 
 void
@@ -693,19 +782,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;
 
+       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);
+               drw_text(drw, m->ww - sw - stw, 0, sw, bh, 0, stext, 0);
        }
 
+       resizebarwin(m);
        for (c = m->clients; c; c = c->next) {
                occ |= c->tags;
                if (c->isurgent)
@@ -726,7 +819,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);
@@ -737,7 +830,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
@@ -774,8 +867,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
@@ -862,10 +958,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,
+       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;
@@ -899,6 +1002,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)
 {
@@ -1005,7 +1118,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);
@@ -1093,6 +1206,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;
@@ -1220,6 +1339,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)
@@ -1271,6 +1400,20 @@ recttomon(int x, int y, int w, int h)
 }
 
 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
 resize(Client *c, int x, int y, int w, int h, int interact)
 {
        if (applysizehints(c, &x, &y, &w, &h, interact))
@@ -1278,6 +1421,14 @@ resize(Client *c, int x, int y, int w, int h, int 
interact)
 }
 
 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;
@@ -1350,6 +1501,19 @@ resizemouse(const Arg *arg)
 }
 
 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
 restack(Monitor *m)
 {
        Client *c;
@@ -1438,26 +1602,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;
 }
@@ -1471,7 +1645,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
@@ -1560,6 +1734,11 @@ 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[NetSystemTrayVisual] = XInternAtom(dpy, 
"_NET_SYSTEM_TRAY_VISUAL", 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);
@@ -1567,6 +1746,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);
@@ -1575,6 +1757,8 @@ setup(void)
        scheme = ecalloc(LENGTH(colors), sizeof(Scm));
        for (i = 0; i < LENGTH(colors); i++)
                scheme[i] = drw_scm_create(drw, colors[i], 3);
+       /* init system tray */
+       updatesystray();
        /* init bars */
        updatebars();
        updatestatus();
@@ -1705,7 +1889,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);
 }
 
@@ -1801,24 +1996,38 @@ 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,
-               .background_pixmap = ParentRelative,
+               .background_pixel = 0,
+               .border_pixel = 0,
+               .colormap = drw->cmap,
                .event_mask = ButtonPressMask|ExposureMask
        };
        for (m = mons; m; m = m->next) {
                if (m->barwin)
                        continue;
-               m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 
0, DefaultDepth(dpy, screen),
-                                         CopyFromParent, DefaultVisual(dpy, 
screen),
-                                         
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+               w = m->ww;
+               if (showsystray && m == systraytomon(m))
+                       w -= getsystraywidth();
+               m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, 
drw->depth,
+                                         CopyFromParent, drw->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);
        }
 }
@@ -2006,6 +2215,126 @@ 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));
+               wa.event_mask        = ButtonPressMask | ExposureMask;
+               wa.override_redirect = True;
+               wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+               wa.border_pixel      = 0;
+               wa.colormap          = drw->cmap;
+               systray->win = XCreateWindow(dpy, root, x, m->by, w, bh, 0, 
drw->depth,
+                                            InputOutput, drw->visual,
+                                            
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+               XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+               XChangeProperty(dpy, systray->win, 
netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+                               PropModeReplace, (unsigned char 
*)&netatom[NetSystemTrayOrientationHorz], 1);
+               XChangeProperty(dpy, systray->win, 
netatom[NetSystemTrayVisual], XA_VISUALID, 32,
+                               PropModeReplace, (unsigned char 
*)&drw->visual->visualid, 1);
+               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
@@ -2064,6 +2393,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)
 {
@@ -2117,6 +2456,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
        return -1;
 }
 
+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
 zoom(const Arg *arg)
 {
-- 
2.10.0.windows.1


Reply via email to