dwm-systray-6.0.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-systray-6.0.diff (19982B)
       ---
            1 Author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus
            2 URL: http://dwm.suckless.org/patches/systray
            3 Implements a system tray for dwm.
            4 
            5 diff -r ec4baab78314 config.def.h
            6 --- a/config.def.h        Mon Dec 19 15:38:30 2011 +0100
            7 +++ b/config.def.h        Fri Apr 06 08:25:40 2012 +0200
            8 @@ -10,6 +10,8 @@
            9  static const char selfgcolor[]      = "#eeeeee";
           10  static const unsigned int borderpx  = 1;        /* border pixel of windows */
           11  static const unsigned int snap      = 32;       /* snap pixel */
           12 +static const unsigned int systrayspacing = 2;   /* systray spacing */
           13 +static const Bool showsystray       = True;     /* False means no systray */
           14  static const Bool showbar           = True;     /* False means no bar */
           15  static const Bool topbar            = True;     /* False means bottom bar */
           16  
           17 diff -r ec4baab78314 dwm.c
           18 --- a/dwm.c        Mon Dec 19 15:38:30 2011 +0100
           19 +++ b/dwm.c        Fri Apr 06 08:25:40 2012 +0200
           20 @@ -55,12 +55,30 @@
           21  #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
           22  #define TEXTW(X)                (textnw(X, strlen(X)) + dc.font.height)
           23  
           24 +#define SYSTEM_TRAY_REQUEST_DOCK    0
           25 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
           26 +
           27 +/* XEMBED messages */
           28 +#define XEMBED_EMBEDDED_NOTIFY      0
           29 +#define XEMBED_WINDOW_ACTIVATE      1
           30 +#define XEMBED_FOCUS_IN             4
           31 +#define XEMBED_MODALITY_ON         10
           32 +
           33 +#define XEMBED_MAPPED              (1 << 0)
           34 +#define XEMBED_WINDOW_ACTIVATE      1
           35 +#define XEMBED_WINDOW_DEACTIVATE    2
           36 +
           37 +#define VERSION_MAJOR               0
           38 +#define VERSION_MINOR               0
           39 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
           40 +
           41  /* enums */
           42  enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
           43  enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
           44 -enum { NetSupported, NetWMName, NetWMState,
           45 -       NetWMFullscreen, NetActiveWindow, NetWMWindowType,
           46 -       NetWMWindowTypeDialog, NetLast };     /* EWMH atoms */
           47 +enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
           48 +           NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType,
           49 +           NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
           50 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
           51  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
           52  enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
           53         ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
           54 @@ -154,6 +172,12 @@
           55          int monitor;
           56  } Rule;
           57  
           58 +typedef struct Systray   Systray;
           59 +struct Systray {
           60 +        Window win;
           61 +        Client *icons;
           62 +};
           63 +
           64  /* function declarations */
           65  static void applyrules(Client *c);
           66  static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
           67 @@ -186,9 +210,11 @@
           68  static void focusin(XEvent *e);
           69  static void focusmon(const Arg *arg);
           70  static void focusstack(const Arg *arg);
           71 +static Atom getatomprop(Client *c, Atom prop);
           72  static unsigned long getcolor(const char *colstr);
           73  static Bool getrootptr(int *x, int *y);
           74  static long getstate(Window w);
           75 +static unsigned int getsystraywidth();
           76  static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
           77  static void grabbuttons(Client *c, Bool focused);
           78  static void grabkeys(void);
           79 @@ -207,13 +233,16 @@
           80  static void propertynotify(XEvent *e);
           81  static void quit(const Arg *arg);
           82  static Monitor *recttomon(int x, int y, int w, int h);
           83 +static void removesystrayicon(Client *i);
           84  static void resize(Client *c, int x, int y, int w, int h, Bool interact);
           85 +static void resizebarwin(Monitor *m);
           86  static void resizeclient(Client *c, int x, int y, int w, int h);
           87  static void resizemouse(const Arg *arg);
           88 +static void resizerequest(XEvent *e);
           89  static void restack(Monitor *m);
           90  static void run(void);
           91  static void scan(void);
           92 -static Bool sendevent(Client *c, Atom proto);
           93 +static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
           94  static void sendmon(Client *c, Monitor *m);
           95  static void setclientstate(Client *c, long state);
           96  static void setfocus(Client *c);
           97 @@ -241,18 +270,24 @@
           98  static void updatenumlockmask(void);
           99  static void updatesizehints(Client *c);
          100  static void updatestatus(void);
          101 +static void updatesystray(void);
          102 +static void updatesystrayicongeom(Client *i, int w, int h);
          103 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
          104  static void updatewindowtype(Client *c);
          105  static void updatetitle(Client *c);
          106  static void updatewmhints(Client *c);
          107  static void view(const Arg *arg);
          108  static Client *wintoclient(Window w);
          109  static Monitor *wintomon(Window w);
          110 +static Client *wintosystrayicon(Window w);
          111  static int xerror(Display *dpy, XErrorEvent *ee);
          112  static int xerrordummy(Display *dpy, XErrorEvent *ee);
          113  static int xerrorstart(Display *dpy, XErrorEvent *ee);
          114  static void zoom(const Arg *arg);
          115  
          116  /* variables */
          117 +static Systray *systray = NULL;
          118 +static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
          119  static const char broken[] = "broken";
          120  static char stext[256];
          121  static int screen;
          122 @@ -274,9 +309,10 @@
          123          [MapRequest] = maprequest,
          124          [MotionNotify] = motionnotify,
          125          [PropertyNotify] = propertynotify,
          126 +        [ResizeRequest] = resizerequest,
          127          [UnmapNotify] = unmapnotify
          128  };
          129 -static Atom wmatom[WMLast], netatom[NetLast];
          130 +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
          131  static Bool running = True;
          132  static Cursor cursor[CurLast];
          133  static Display *dpy;
          134 @@ -497,6 +533,11 @@
          135          XFreeCursor(dpy, cursor[CurMove]);
          136          while(mons)
          137                  cleanupmon(mons);
          138 +        if(showsystray) {
          139 +                XUnmapWindow(dpy, systray->win);
          140 +                XDestroyWindow(dpy, systray->win);
          141 +                free(systray);
          142 +        }
          143          XSync(dpy, False);
          144          XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
          145  }
          146 @@ -530,9 +572,49 @@
          147  
          148  void
          149  clientmessage(XEvent *e) {
          150 +        XWindowAttributes wa;
          151 +        XSetWindowAttributes swa;
          152          XClientMessageEvent *cme = &e->xclient;
          153          Client *c = wintoclient(cme->window);
          154  
          155 +        if(showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
          156 +                /* add systray icons */
          157 +                if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
          158 +                        if(!(c = (Client *)calloc(1, sizeof(Client))))
          159 +                                die("fatal: could not malloc() %u bytes\n", sizeof(Client));
          160 +                        c->win = cme->data.l[2];
          161 +                        c->mon = selmon;
          162 +                        c->next = systray->icons;
          163 +                        systray->icons = c;
          164 +                        XGetWindowAttributes(dpy, c->win, &wa);
          165 +                        c->x = c->oldx = c->y = c->oldy = 0;
          166 +                        c->w = c->oldw = wa.width;
          167 +                        c->h = c->oldh = wa.height;
          168 +                        c->oldbw = wa.border_width;
          169 +                        c->bw = 0;
          170 +                        c->isfloating = True;
          171 +                        /* reuse tags field as mapped status */
          172 +                        c->tags = 1;
          173 +                        updatesizehints(c);
          174 +                        updatesystrayicongeom(c, wa.width, wa.height);
          175 +                        XAddToSaveSet(dpy, c->win);
          176 +                        XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
          177 +                        XReparentWindow(dpy, c->win, systray->win, 0, 0);
          178 +                        /* use parents background pixmap */
          179 +                        swa.background_pixmap = ParentRelative;
          180 +                        swa.background_pixel  = dc.norm[ColBG];
          181 +                        XChangeWindowAttributes(dpy, c->win, CWBackPixmap|CWBackPixel, &swa);
          182 +                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          183 +                        /* FIXME not sure if I have to send these events, too */
          184 +                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          185 +                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          186 +                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          187 +                        resizebarwin(selmon);
          188 +                        updatesystray();
          189 +                        setclientstate(c, NormalState);
          190 +                }
          191 +                return;
          192 +        }
          193          if(!c)
          194                  return;
          195          if(cme->message_type == netatom[NetWMState]) {
          196 @@ -583,7 +663,7 @@
          197                          dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
          198                          updatebars();
          199                          for(m = mons; m; m = m->next)
          200 -                                XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
          201 +                                resizebarwin(m);
          202                          focus(NULL);
          203                          arrange(NULL);
          204                  }
          205 @@ -667,6 +747,11 @@
          206  
          207          if((c = wintoclient(ev->window)))
          208                  unmanage(c, True);
          209 +        else if((c = wintosystrayicon(ev->window))) {
          210 +                removesystrayicon(c);
          211 +                resizebarwin(selmon);
          212 +                updatesystray();
          213 +        }
          214  }
          215  
          216  void
          217 @@ -722,6 +807,7 @@
          218          unsigned long *col;
          219          Client *c;
          220  
          221 +        resizebarwin(m);
          222          for(c = m->clients; c; c = c->next) {
          223                  occ |= c->tags;
          224                  if(c->isurgent)
          225 @@ -743,6 +829,9 @@
          226          if(m == selmon) { /* status is only drawn on selected monitor */
          227                  dc.w = TEXTW(stext);
          228                  dc.x = m->ww - dc.w;
          229 +                if(showsystray && m == selmon) {
          230 +                        dc.x -= getsystraywidth();
          231 +                }
          232                  if(dc.x < x) {
          233                          dc.x = x;
          234                          dc.w = m->ww - x;
          235 @@ -771,6 +860,7 @@
          236  
          237          for(m = mons; m; m = m->next)
          238                  drawbar(m);
          239 +        updatesystray();
          240  }
          241  
          242  void
          243 @@ -917,10 +1007,17 @@
          244          unsigned long dl;
          245          unsigned char *p = NULL;
          246          Atom da, atom = None;
          247 +        /* FIXME getatomprop should return the number of items and a pointer to
          248 +         * the stored data instead of this workaround */
          249 +        Atom req = XA_ATOM;
          250 +        if(prop == xatom[XembedInfo])
          251 +                req = xatom[XembedInfo];
          252  
          253 -        if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
          254 +        if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
          255                                &da, &di, &dl, &dl, &p) == Success && p) {
          256                  atom = *(Atom *)p;
          257 +                if(da == xatom[XembedInfo] && dl == 2)
          258 +                        atom = ((Atom *)p)[1];
          259                  XFree(p);
          260          }
          261          return atom;
          262 @@ -962,6 +1059,15 @@
          263          return result;
          264  }
          265  
          266 +unsigned int
          267 +getsystraywidth() {
          268 +        unsigned int w = 0;
          269 +        Client *i;
          270 +        if(showsystray)
          271 +                for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
          272 +        return w ? w + systrayspacing : 1;
          273 +}
          274 +
          275  Bool
          276  gettextprop(Window w, Atom atom, char *text, unsigned int size) {
          277          char **list = NULL;
          278 @@ -1096,7 +1202,7 @@
          279  killclient(const Arg *arg) {
          280          if(!selmon->sel)
          281                  return;
          282 -        if(!sendevent(selmon->sel, wmatom[WMDelete])) {
          283 +        if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
          284                  XGrabServer(dpy);
          285                  XSetErrorHandler(xerrordummy);
          286                  XSetCloseDownMode(dpy, DestroyAll);
          287 @@ -1180,6 +1286,12 @@
          288  maprequest(XEvent *e) {
          289          static XWindowAttributes wa;
          290          XMapRequestEvent *ev = &e->xmaprequest;
          291 +        Client *i;
          292 +        if((i = wintosystrayicon(ev->window))) {
          293 +                sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
          294 +                resizebarwin(selmon);
          295 +                updatesystray();
          296 +        }
          297  
          298          if(!XGetWindowAttributes(dpy, ev->window, &wa))
          299                  return;
          300 @@ -1293,6 +1405,16 @@
          301          Window trans;
          302          XPropertyEvent *ev = &e->xproperty;
          303  
          304 +        if((c = wintosystrayicon(ev->window))) {
          305 +                if(ev->atom == XA_WM_NORMAL_HINTS) {
          306 +                        updatesizehints(c);
          307 +                        updatesystrayicongeom(c, c->w, c->h);
          308 +                }
          309 +                else
          310 +                        updatesystrayiconstate(c, ev);
          311 +                resizebarwin(selmon);
          312 +                updatesystray();
          313 +        }
          314          if((ev->window == root) && (ev->atom == XA_WM_NAME))
          315                  updatestatus();
          316          else if(ev->state == PropertyDelete)
          317 @@ -1342,12 +1464,33 @@
          318  }
          319  
          320  void
          321 +removesystrayicon(Client *i) {
          322 +        Client **ii;
          323 +
          324 +        if(!showsystray || !i)
          325 +                return;
          326 +        for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
          327 +        if(ii)
          328 +                *ii = i->next;
          329 +        free(i);
          330 +}
          331 +
          332 +
          333 +void
          334  resize(Client *c, int x, int y, int w, int h, Bool interact) {
          335          if(applysizehints(c, &x, &y, &w, &h, interact))
          336                  resizeclient(c, x, y, w, h);
          337  }
          338  
          339  void
          340 +resizebarwin(Monitor *m) {
          341 +        unsigned int w = m->ww;
          342 +        if(showsystray && m == selmon)
          343 +                w -= getsystraywidth();
          344 +        XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
          345 +}
          346 +
          347 +void
          348  resizeclient(Client *c, int x, int y, int w, int h) {
          349          XWindowChanges wc;
          350  
          351 @@ -1412,6 +1555,18 @@
          352  }
          353  
          354  void
          355 +resizerequest(XEvent *e) {
          356 +        XResizeRequestEvent *ev = &e->xresizerequest;
          357 +        Client *i;
          358 +
          359 +        if((i = wintosystrayicon(ev->window))) {
          360 +                updatesystrayicongeom(i, ev->width, ev->height);
          361 +                resizebarwin(selmon);
          362 +                updatesystray();
          363 +        }
          364 +}
          365 +
          366 +void
          367  restack(Monitor *m) {
          368          Client *c;
          369          XEvent ev;
          370 @@ -1495,25 +1650,35 @@
          371  }
          372  
          373  Bool
          374 -sendevent(Client *c, Atom proto) {
          375 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) {
          376          int n;
          377 -        Atom *protocols;
          378 +        Atom *protocols, mt;
          379          Bool exists = False;
          380          XEvent ev;
          381  
          382 -        if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
          383 -                while(!exists && n--)
          384 -                        exists = protocols[n] == proto;
          385 -                XFree(protocols);
          386 +        if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
          387 +                mt = wmatom[WMProtocols];
          388 +                if(XGetWMProtocols(dpy, w, &protocols, &n)) {
          389 +                        while(!exists && n--)
          390 +                                exists = protocols[n] == proto;
          391 +                        XFree(protocols);
          392 +                }
          393 +        }
          394 +        else {
          395 +                exists = True;
          396 +                mt = proto;
          397          }
          398          if(exists) {
          399                  ev.type = ClientMessage;
          400 -                ev.xclient.window = c->win;
          401 -                ev.xclient.message_type = wmatom[WMProtocols];
          402 +                ev.xclient.window = w;
          403 +                ev.xclient.message_type = mt;
          404                  ev.xclient.format = 32;
          405 -                ev.xclient.data.l[0] = proto;
          406 -                ev.xclient.data.l[1] = CurrentTime;
          407 -                XSendEvent(dpy, c->win, False, NoEventMask, &ev);
          408 +                ev.xclient.data.l[0] = d0;
          409 +                ev.xclient.data.l[1] = d1;
          410 +                ev.xclient.data.l[2] = d2;
          411 +                ev.xclient.data.l[3] = d3;
          412 +                ev.xclient.data.l[4] = d4;
          413 +                XSendEvent(dpy, w, False, mask, &ev);
          414          }
          415          return exists;
          416  }
          417 @@ -1522,7 +1687,7 @@
          418  setfocus(Client *c) {
          419          if(!c->neverfocus)
          420                  XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
          421 -        sendevent(c, wmatom[WMTakeFocus]);
          422 +        sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
          423  }
          424  
          425  void
          426 @@ -1602,11 +1767,17 @@
          427          wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
          428          netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
          429          netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
          430 +        netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
          431 +        netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
          432 +        netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
          433          netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
          434          netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
          435          netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
          436          netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
          437          netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
          438 +        xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
          439 +        xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
          440 +        xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
          441          /* init cursors */
          442          cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
          443          cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
          444 @@ -1623,6 +1794,8 @@
          445          XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
          446          if(!dc.font.set)
          447                  XSetFont(dpy, dc.gc, dc.font.xfont->fid);
          448 +        /* init system tray */
          449 +        updatesystray();
          450          /* init bars */
          451          updatebars();
          452          updatestatus();
          453 @@ -1731,7 +1904,18 @@
          454  togglebar(const Arg *arg) {
          455          selmon->showbar = !selmon->showbar;
          456          updatebarpos(selmon);
          457 -        XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
          458 +        resizebarwin(selmon);
          459 +        if(showsystray) {
          460 +                XWindowChanges wc;
          461 +                if(!selmon->showbar)
          462 +                        wc.y = -bh;
          463 +                else if(selmon->showbar) {
          464 +                        wc.y = 0;
          465 +                        if(!selmon->topbar)
          466 +                                wc.y = selmon->mh - bh;
          467 +                }
          468 +                XConfigureWindow(dpy, systray->win, CWY, &wc);
          469 +        }
          470          arrange(selmon);
          471  }
          472  
          473 @@ -1816,18 +2000,28 @@
          474                  else
          475                          unmanage(c, False);
          476          }
          477 +        else if((c = wintosystrayicon(ev->window))) {
          478 +                removesystrayicon(c);
          479 +                resizebarwin(selmon);
          480 +                updatesystray();
          481 +        }
          482  }
          483  
          484  void
          485  updatebars(void) {
          486 +        unsigned int w;
          487          Monitor *m;
          488 +
          489          XSetWindowAttributes wa = {
          490                  .override_redirect = True,
          491                  .background_pixmap = ParentRelative,
          492                  .event_mask = ButtonPressMask|ExposureMask
          493          };
          494          for(m = mons; m; m = m->next) {
          495 -                m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
          496 +                w = m->ww;
          497 +                if(showsystray && m == selmon)
          498 +                        w -= getsystraywidth();
          499 +                m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
          500                                            CopyFromParent, DefaultVisual(dpy, screen),
          501                                            CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
          502                  XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
          503 @@ -2011,6 +2208,107 @@
          504  }
          505  
          506  void
          507 +updatesystrayicongeom(Client *i, int w, int h) {
          508 +        if(i) {
          509 +                i->h = bh;
          510 +                if(w == h)
          511 +                        i->w = bh;
          512 +                else if(h == bh)
          513 +                        i->w = w;
          514 +                else
          515 +                        i->w = (int) ((float)bh * ((float)w / (float)h));
          516 +                applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
          517 +                /* force icons into the systray dimenons if they don't want to */
          518 +                if(i->h > bh) {
          519 +                        if(i->w == i->h)
          520 +                                i->w = bh;
          521 +                        else
          522 +                                i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
          523 +                        i->h = bh;
          524 +                }
          525 +        }
          526 +}
          527 +
          528 +void
          529 +updatesystrayiconstate(Client *i, XPropertyEvent *ev) {
          530 +        long flags;
          531 +        int code = 0;
          532 +
          533 +        if(!showsystray || !i || ev->atom != xatom[XembedInfo] ||
          534 +                        !(flags = getatomprop(i, xatom[XembedInfo])))
          535 +                return;
          536 +
          537 +        if(flags & XEMBED_MAPPED && !i->tags) {
          538 +                i->tags = 1;
          539 +                code = XEMBED_WINDOW_ACTIVATE;
          540 +                XMapRaised(dpy, i->win);
          541 +                setclientstate(i, NormalState);
          542 +        }
          543 +        else if(!(flags & XEMBED_MAPPED) && i->tags) {
          544 +                i->tags = 0;
          545 +                code = XEMBED_WINDOW_DEACTIVATE;
          546 +                XUnmapWindow(dpy, i->win);
          547 +                setclientstate(i, WithdrawnState);
          548 +        }
          549 +        else
          550 +                return;
          551 +        sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
          552 +                        systray->win, XEMBED_EMBEDDED_VERSION);
          553 +}
          554 +
          555 +void
          556 +updatesystray(void) {
          557 +        XSetWindowAttributes wa;
          558 +        Client *i;
          559 +        unsigned int x = selmon->mx + selmon->mw;
          560 +        unsigned int w = 1;
          561 +
          562 +        if(!showsystray)
          563 +                return;
          564 +        if(!systray) {
          565 +                /* init systray */
          566 +                if(!(systray = (Systray *)calloc(1, sizeof(Systray))))
          567 +                        die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
          568 +                systray->win = XCreateSimpleWindow(dpy, root, x, selmon->by, w, bh, 0, 0, dc.sel[ColBG]);
          569 +                wa.event_mask        = ButtonPressMask | ExposureMask;
          570 +                wa.override_redirect = True;
          571 +                wa.background_pixmap = ParentRelative;
          572 +                wa.background_pixel  = dc.norm[ColBG];
          573 +                XSelectInput(dpy, systray->win, SubstructureNotifyMask);
          574 +                XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
          575 +                                PropModeReplace, (unsigned char *)&systrayorientation, 1);
          576 +                XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel|CWBackPixmap, &wa);
          577 +                XMapRaised(dpy, systray->win);
          578 +                XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
          579 +                if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
          580 +                        sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
          581 +                        XSync(dpy, False);
          582 +                }
          583 +                else {
          584 +                        fprintf(stderr, "dwm: unable to obtain system tray.\n");
          585 +                        free(systray);
          586 +                        systray = NULL;
          587 +                        return;
          588 +                }
          589 +        }
          590 +        for(w = 0, i = systray->icons; i; i = i->next) {
          591 +                XMapRaised(dpy, i->win);
          592 +                w += systrayspacing;
          593 +                XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->h);
          594 +                w += i->w;
          595 +                if(i->mon != selmon)
          596 +                        i->mon = selmon;
          597 +        }
          598 +        w = w ? w + systrayspacing : 1;
          599 +         x -= w;
          600 +        XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh);
          601 +        /* redraw background */
          602 +        XSetForeground(dpy, dc.gc, dc.norm[ColBG]);
          603 +        XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh);
          604 +        XSync(dpy, False);
          605 +}
          606 +
          607 +void
          608  updatewindowtype(Client *c) {
          609          Atom state = getatomprop(c, netatom[NetWMState]);
          610          Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
          611 @@ -2080,6 +2372,16 @@
          612          return selmon;
          613  }
          614  
          615 +Client *
          616 +wintosystrayicon(Window w) {
          617 +        Client *i = NULL;
          618 +
          619 +        if(!showsystray || !w)
          620 +                return i;
          621 +        for(i = systray->icons; i && i->win != w; i = i->next) ;
          622 +        return i;
          623 +}
          624 +
          625  /* There's no way to check accesses to destroyed windows, thus those cases are
          626   * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
          627   * default error handler, which may call exit.  */