@Eon, I'd be happy to integrate parts of the patch into the systray
patch.  Would you mind posting your version as a proper patch file in
the wiki or in this list?

On Fri 23-12-2016 17:21 +0900, Eon S. Jeon wrote:

> 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[]       = "#222222A#dd";
> +static const char col_gray2[]       = "#444444A#ff";
> +static const char col_gray3[]       = "#bbbbbbA#ff";
> +static const char col_gray4[]       = "#eeeeeeA#ff";
> +static const char col_cyan[]        = "#005577A#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 : %lun", 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 bytesn", 
> 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 bytesn", 
> 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)
>  {

-- 
Jan Christoph Ebersbach
I didn’t want some petty, inferior brand of righteousness that comes
from keeping a list of rules when I could get the robust kind that comes
from trusting Christ - God’s righteousness.  Phil 3:9

Attachment: signature.asc
Description: PGP signature

Reply via email to