Merge branch 'dwm-statusallmons-20160731-56a31dc.diff' into patched
authorDaniel <thefekete@gmail.com>
Sat, 29 Dec 2018 01:06:23 +0000 (02:06 +0100)
committerDaniel <thefekete@gmail.com>
Sat, 29 Dec 2018 01:06:23 +0000 (02:06 +0100)
1  2 
dwm.c

diff --combined dwm.c
--- 1/dwm.c
--- 2/dwm.c
+++ b/dwm.c
@@@ -3,7 -3,7 +3,7 @@@
   * dynamic window manager is designed like any other X client as well. It is
   * driven through handling X events. In contrast to other X clients, a window
   * manager selects for SubstructureRedirectMask on the root window, to receive
 - * events about window (dis-)appearance.  Only one X connection at a time is
 + * events about window (dis-)appearance. Only one X connection at a time is
   * allowed to select for this event mask.
   *
   * The event handlers of dwm are organized in an array which is accessed
@@@ -11,7 -11,7 +11,7 @@@
   * in O(1) time.
   *
   * Each child of the root window is called a client, except windows which have
 - * set the override_redirect flag.  Clients are organized in a linked client
 + * set the override_redirect flag. Clients are organized in a linked client
   * list on each monitor, the focus history is remembered through a stack list
   * on each monitor. Each client contains a bit array to indicate the tags of a
   * client.
  #define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
  #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
  #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, SchemeLast }; /* color schemes */
 -enum { NetSupported, NetWMName, NetWMState,
 +enum { SchemeNorm, SchemeSel }; /* color schemes */
 +enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
 +       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
  enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
         ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@@@ -106,7 -89,6 +106,7 @@@ struct Client 
        char name[256];
        float mina, maxa;
        int x, y, w, h;
 +      int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
        int oldx, oldy, oldw, oldh;
        int basew, baseh, incw, inch, maxw, maxh, minw, minh;
        int bw, oldbw;
@@@ -160,12 -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);
@@@ -177,6 -153,7 +177,6 @@@ static void buttonpress(XEvent *e)
  static void checkotherwm(void);
  static void cleanup(void);
  static void cleanupmon(Monitor *mon);
 -static void clearurgent(Client *c);
  static void clientmessage(XEvent *e);
  static void configure(Client *c);
  static void configurenotify(XEvent *e);
@@@ -194,10 -171,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);
@@@ -215,16 -190,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);
@@@ -232,11 -204,9 +232,11 @@@ static void setfullscreen(Client *c, in
  static void setlayout(const Arg *arg);
  static void setmfact(const Arg *arg);
  static void setup(void);
 +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 *);
@@@ -247,30 -217,25 +247,30 @@@ static void toggleview(const Arg *arg)
  static void unfocus(Client *c, int setfocus);
  static void unmanage(Client *c, int destroyed);
  static void unmapnotify(XEvent *e);
 -static int updategeom(void);
  static void updatebarpos(Monitor *m);
  static void updatebars(void);
  static void updateclientlist(void);
 +static int updategeom(void);
  static void updatenumlockmask(void);
  static void updatesizehints(Client *c);
  static void updatestatus(void);
 -static void updatewindowtype(Client *c);
 +static void updatesystray(void);
 +static void updatesystrayicongeom(Client *i, int w, int h);
 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
  static void updatetitle(Client *c);
 +static void updatewindowtype(Client *c);
  static void updatewmhints(Client *c);
  static void view(const Arg *arg);
  static Client *wintoclient(Window w);
  static Monitor *wintomon(Window w);
 +static Client *wintosystrayicon(Window w);
  static int xerror(Display *dpy, XErrorEvent *ee);
  static int xerrordummy(Display *dpy, XErrorEvent *ee);
  static int xerrorstart(Display *dpy, XErrorEvent *ee);
  static void zoom(const Arg *arg);
  
  /* variables */
 +static Systray *systray =  NULL;
  static const char broken[] = "broken";
  static char stext[256];
  static int screen;
@@@ -293,17 -258,16 +293,17 @@@ static void (*handler[LASTEvent]) (XEve
        [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[SchemeLast];
 +static Clr **scheme;
  static Display *dpy;
  static Drw *drw;
  static Monitor *mons, *selmon;
 -static Window root;
 +static Window root, wmcheckwin;
  
  /* configuration, allows nested code to access above variables */
  #include "config.h"
@@@ -482,8 -446,6 +482,8 @@@ buttonpress(XEvent *e
                        click = ClkWinTitle;
        } else if ((c = wintoclient(ev->window))) {
                focus(c);
 +              restack(selmon);
 +              XAllowEvents(dpy, ReplayPointer, CurrentTime);
                click = ClkClientWin;
        }
        for (i = 0; i < LENGTH(buttons); i++)
@@@ -519,16 -481,10 +519,16 @@@ cleanup(void
        XUngrabKey(dpy, AnyKey, AnyModifier, root);
        while (mons)
                cleanupmon(mons);
 +      if (showsystray) {
 +              XUnmapWindow(dpy, systray->win);
 +              XDestroyWindow(dpy, systray->win);
 +              free(systray);
 +      }
        for (i = 0; i < CurLast; i++)
                drw_cur_free(drw, cursor[i]);
 -      for (i = 0; i < SchemeLast; i++)
 +      for (i = 0; i < LENGTH(colors); i++)
                free(scheme[i]);
 +      XDestroyWindow(dpy, wmcheckwin);
        drw_free(drw);
        XSync(dpy, False);
        XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
@@@ -551,65 -507,37 +551,65 @@@ cleanupmon(Monitor *mon
        free(mon);
  }
  
 -void
 -clearurgent(Client *c)
 -{
 -      XWMHints *wmh;
 -
 -      c->isurgent = 0;
 -      if (!(wmh = XGetWMHints(dpy, c->win)))
 -              return;
 -      wmh->flags &= ~XUrgencyHint;
 -      XSetWMHints(dpy, c->win, wmh);
 -      XFree(wmh);
 -}
 -
  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]) {
 -              if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
 +              if (cme->data.l[1] == netatom[NetWMFullscreen]
 +              || cme->data.l[2] == netatom[NetWMFullscreen])
                        setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
 -                                    || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
 +                              || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
        } else if (cme->message_type == netatom[NetActiveWindow]) {
 -              if (!ISVISIBLE(c)) {
 -                      c->mon->seltags ^= 1;
 -                      c->mon->tagset[c->mon->seltags] = c->tags;
 -              }
 -              pop(c);
 +              if (c != selmon->sel && !c->isurgent)
 +                      seturgent(c, 1);
        }
  }
  
@@@ -652,7 -580,7 +652,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);
@@@ -737,11 -665,6 +737,11 @@@ destroynotify(XEvent *e
  
        if ((c = wintoclient(ev->window)))
                unmanage(c, 1);
 +      else if ((c = wintosystrayicon(ev->window))) {
 +              removesystrayicon(c);
 +              resizebarwin(selmon);
 +              updatesystray();
 +      }
  }
  
  void
@@@ -785,23 -708,19 +785,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 */
+       if (m == selmon || 1) { /* status is only drawn on selected monitor */
                drw_setscheme(drw, scheme[SchemeNorm]);
 -              sw = TEXTW(stext) - lrpad / 2; /* no right padding so status text hugs the corner */
 -              drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
 +              sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
 +              drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
        }
  
 +      resizebarwin(m);
        for (c = m->clients; c; c = c->next) {
                occ |= c->tags;
                if (c->isurgent)
                drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
                if (occ & 1 << i)
                        drw_rect(drw, x + boxs, boxs, boxw, boxw,
 -                               m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
 -                               urg & 1 << i);
 +                              m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
 +                              urg & 1 << i);
                x += w;
        }
        w = blw = TEXTW(m->ltsymbol);
        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);
                        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
@@@ -870,11 -789,8 +870,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
@@@ -882,13 -798,14 +882,13 @@@ focus(Client *c
  {
        if (!c || !ISVISIBLE(c))
                for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
 -      /* was if (selmon->sel) */
        if (selmon->sel && selmon->sel != c)
                unfocus(selmon->sel, 0);
        if (c) {
                if (c->mon != selmon)
                        selmon = c->mon;
                if (c->isurgent)
 -                      clearurgent(c);
 +                      seturgent(c, 0);
                detachstack(c);
                attachstack(c);
                grabbuttons(c, 1);
        drawbars();
  }
  
 -/* there are some broken focus acquiring clients */
 +/* there are some broken focus acquiring clients needing extra handling */
  void
  focusin(XEvent *e)
  {
@@@ -921,7 -838,8 +921,7 @@@ focusmon(const Arg *arg
                return;
        if ((m = dirtomon(arg->i)) == selmon)
                return;
 -      unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues
 -                                      in gedit and anjuta */
 +      unfocus(selmon->sel, 0);
        selmon = m;
        focus(NULL);
  }
@@@ -959,17 -877,10 +959,17 @@@ getatomprop(Client *c, Atom prop
        unsigned long dl;
        unsigned char *p = NULL;
        Atom da, atom = None;
 -
 -      if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
 -                            &da, &di, &dl, &dl, &p) == Success && p) {
 +      /* 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, 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;
@@@ -995,7 -906,7 +995,7 @@@ getstate(Window w
        Atom real;
  
        if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
 -                            &real, &format, &n, &extra, (unsigned char **)&p) != Success)
 +              &real, &format, &n, &extra, (unsigned char **)&p) != Success)
                return -1;
        if (n != 0)
                result = *p;
        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)
  {
        if (!text || size == 0)
                return 0;
        text[0] = '\0';
 -      XGetTextProperty(dpy, w, &name, atom);
 -      if (!name.nitems)
 +      if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
                return 0;
        if (name.encoding == XA_STRING)
                strncpy(text, (char *)name.value, size - 1);
@@@ -1046,16 -948,17 +1046,16 @@@ grabbuttons(Client *c, int focused
                unsigned int i, j;
                unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
                XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 -              if (focused) {
 -                      for (i = 0; i < LENGTH(buttons); i++)
 -                              if (buttons[i].click == ClkClientWin)
 -                                      for (j = 0; j < LENGTH(modifiers); j++)
 -                                              XGrabButton(dpy, buttons[i].button,
 -                                                          buttons[i].mask | modifiers[j],
 -                                                          c->win, False, BUTTONMASK,
 -                                                          GrabModeAsync, GrabModeSync, None, None);
 -              } else
 +              if (!focused)
                        XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
 -                                  BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
 +                              BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
 +              for (i = 0; i < LENGTH(buttons); i++)
 +                      if (buttons[i].click == ClkClientWin)
 +                              for (j = 0; j < LENGTH(modifiers); j++)
 +                                      XGrabButton(dpy, buttons[i].button,
 +                                              buttons[i].mask | modifiers[j],
 +                                              c->win, False, BUTTONMASK,
 +                                              GrabModeAsync, GrabModeSync, None, None);
        }
  }
  
@@@ -1073,7 -976,7 +1073,7 @@@ grabkeys(void
                        if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
                                for (j = 0; j < LENGTH(modifiers); j++)
                                        XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
 -                                               True, GrabModeAsync, GrabModeAsync);
 +                                              True, GrabModeAsync, GrabModeAsync);
        }
  }
  
@@@ -1117,7 -1020,7 +1117,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);
@@@ -1160,7 -1063,7 +1160,7 @@@ manage(Window w, XWindowAttributes *wa
        c->x = MAX(c->x, c->mon->mx);
        /* only fix client y-offset, if the client center might cover the bar */
        c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
 -                 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
 +              && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
        c->bw = borderpx;
  
        wc.border_width = c->bw;
        updatewindowtype(c);
        updatesizehints(c);
        updatewmhints(c);
 +      c->sfx = c->x;
 +      c->sfy = c->y;
 +      c->sfw = c->w;
 +      c->sfh = c->h;
        XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
        grabbuttons(c, 0);
        if (!c->isfloating)
        attach(c);
        attachstack(c);
        XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
 -                      (unsigned char *) &(c->win), 1);
 +              (unsigned char *) &(c->win), 1);
        XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
        setclientstate(c, NormalState);
        if (c->mon == selmon)
@@@ -1209,12 -1108,6 +1209,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;
@@@ -1273,7 -1166,7 +1273,7 @@@ movemouse(const Arg *arg
        ocx = c->x;
        ocy = c->y;
        if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 -      None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
 +              None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
                return;
        if (!getrootptr(&x, &y))
                return;
  
                        nx = ocx + (ev.xmotion.x - x);
                        ny = ocy + (ev.xmotion.y - y);
 -                      if (nx >= selmon->wx && nx <= selmon->wx + selmon->ww
 -                      && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
 -                              if (abs(selmon->wx - nx) < snap)
 -                                      nx = selmon->wx;
 -                              else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
 -                                      nx = selmon->wx + selmon->ww - WIDTH(c);
 -                              if (abs(selmon->wy - ny) < snap)
 -                                      ny = selmon->wy;
 -                              else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
 -                                      ny = selmon->wy + selmon->wh - HEIGHT(c);
 -                              if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
 -                              && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
 -                                      togglefloating(NULL);
 -                      }
 +                      if (abs(selmon->wx - nx) < snap)
 +                              nx = selmon->wx;
 +                      else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
 +                              nx = selmon->wx + selmon->ww - WIDTH(c);
 +                      if (abs(selmon->wy - ny) < snap)
 +                              ny = selmon->wy;
 +                      else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
 +                              ny = selmon->wy + selmon->wh - HEIGHT(c);
 +                      if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
 +                      && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
 +                              togglefloating(NULL);
                        if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
                                resize(c, nx, ny, c->w, c->h, 1);
                        break;
@@@ -1339,16 -1235,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)
                default: break;
                case XA_WM_TRANSIENT_FOR:
                        if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
 -                         (c->isfloating = (wintoclient(trans)) != NULL))
 +                              (c->isfloating = (wintoclient(trans)) != NULL))
                                arrange(c->mon);
                        break;
                case XA_WM_NORMAL_HINTS:
@@@ -1399,20 -1285,6 +1399,20 @@@ recttomon(int x, int y, int w, int h
        return r;
  }
  
 +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)
  {
                resizeclient(c, x, y, w, h);
  }
  
 +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)
  {
@@@ -1460,7 -1324,7 +1460,7 @@@ resizemouse(const Arg *arg
        ocx = c->x;
        ocy = c->y;
        if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 -                      None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
 +              None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
                return;
        XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
        do {
        }
  }
  
 +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)
  {
@@@ -1598,40 -1449,30 +1598,40 @@@ setclientstate(Client *c, long state
        long data[] = { state, None };
  
        XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
 -                      PropModeReplace, (unsigned char *)data, 2);
 +              PropModeReplace, (unsigned char *)data, 2);
  }
  
  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;
  }
@@@ -1642,10 -1483,10 +1642,10 @@@ setfocus(Client *c
        if (!c->neverfocus) {
                XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
                XChangeProperty(dpy, root, netatom[NetActiveWindow],
 -                              XA_WINDOW, 32, PropModeReplace,
 -                              (unsigned char *) &(c->win), 1);
 +                      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
@@@ -1653,7 -1494,7 +1653,7 @@@ setfullscreen(Client *c, int fullscreen
  {
        if (fullscreen && !c->isfullscreen) {
                XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
 -                              PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
 +                      PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
                c->isfullscreen = 1;
                c->oldstate = c->isfloating;
                c->oldbw = c->bw;
                XRaiseWindow(dpy, c->win);
        } else if (!fullscreen && c->isfullscreen){
                XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
 -                              PropModeReplace, (unsigned char*)0, 0);
 +                      PropModeReplace, (unsigned char*)0, 0);
                c->isfullscreen = 0;
                c->isfloating = c->oldstate;
                c->bw = c->oldbw;
@@@ -1690,7 -1531,7 +1690,7 @@@ setlayout(const Arg *arg
                drawbar(selmon);
  }
  
 -/* arg > 1.0 will set mfact absolutly */
 +/* arg > 1.0 will set mfact absolutely */
  void
  setmfact(const Arg *arg)
  {
  void
  setup(void)
  {
 +      int i;
        XSetWindowAttributes wa;
 +      Atom utf8string;
  
        /* clean up any zombies immediately */
        sigchld(0);
        root = RootWindow(dpy, screen);
        drw = drw_create(dpy, screen, root, sw, sh);
        if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
 -              die("no fonts could be loaded.\n");
 +              die("no fonts could be loaded.");
        lrpad = drw->fonts->h;
        bh = drw->fonts->h + 2;
        updategeom();
        /* init atoms */
 +      utf8string = XInternAtom(dpy, "UTF8_STRING", False);
        wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
        wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
        wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
        wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
        netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
        netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
 +      netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
 +      netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
 +      netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
 +      netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
        netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
        netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
 +      netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
        netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
        netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
        netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
        netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
 +      xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
 +      xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
 +      xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
        /* init cursors */
        cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
        cursor[CurResize] = drw_cur_create(drw, XC_sizing);
        cursor[CurMove] = drw_cur_create(drw, XC_fleur);
        /* init appearance */
 -      scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3);
 -      scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3);
 +      scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
 +      for (i = 0; i < LENGTH(colors); i++)
 +              scheme[i] = drw_scm_create(drw, colors[i], 3);
 +      /* init system tray */
 +      updatesystray();
        /* init bars */
        updatebars();
        updatestatus();
 +      /* supporting window for NetWMCheck */
 +      wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
 +      XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
 +              PropModeReplace, (unsigned char *) &wmcheckwin, 1);
 +      XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
 +              PropModeReplace, (unsigned char *) "dwm", 3);
 +      XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
 +              PropModeReplace, (unsigned char *) &wmcheckwin, 1);
        /* EWMH support per view */
        XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
 -                      PropModeReplace, (unsigned char *) netatom, NetLast);
 +              PropModeReplace, (unsigned char *) netatom, NetLast);
        XDeleteProperty(dpy, root, netatom[NetClientList]);
 -      /* select for events */
 +      /* select events */
        wa.cursor = cursor[CurNormal]->cursor;
 -      wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
 -                      |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
 +      wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
 +              |ButtonPressMask|PointerMotionMask|EnterWindowMask
 +              |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
        XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
        XSelectInput(dpy, root, wa.event_mask);
        grabkeys();
        focus(NULL);
  }
  
 +
 +void
 +seturgent(Client *c, int urg)
 +{
 +      XWMHints *wmh;
 +
 +      c->isurgent = urg;
 +      if (!(wmh = XGetWMHints(dpy, c->win)))
 +              return;
 +      wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
 +      XSetWMHints(dpy, c->win, wmh);
 +      XFree(wmh);
 +}
 +
  void
  showhide(Client *c)
  {
@@@ -1889,18 -1693,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);
  }
  
@@@ -1913,16 -1706,8 +1913,16 @@@ togglefloating(const Arg *arg
                return;
        selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
        if (selmon->sel->isfloating)
 -              resize(selmon->sel, selmon->sel->x, selmon->sel->y,
 -                     selmon->sel->w, selmon->sel->h, 0);
 +              /* restore last known float dimensions */
 +              resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy,
 +                     selmon->sel->sfw, selmon->sel->sfh, False);
 +      else {
 +              /* save last known float dimensions */
 +              selmon->sel->sfx = selmon->sel->x;
 +              selmon->sel->sfy = selmon->sel->y;
 +              selmon->sel->sfw = selmon->sel->w;
 +              selmon->sel->sfh = selmon->sel->h;
 +      }
        arrange(selmon);
  }
  
@@@ -1972,11 -1757,12 +1972,11 @@@ unmanage(Client *c, int destroyed
        Monitor *m = c->mon;
        XWindowChanges wc;
  
 -      /* The server grab construct avoids race conditions. */
        detach(c);
        detachstack(c);
        if (!destroyed) {
                wc.border_width = c->oldbw;
 -              XGrabServer(dpy);
 +              XGrabServer(dpy); /* avoid race conditions */
                XSetErrorHandler(xerrordummy);
                XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
                XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
@@@ -2003,39 -1789,25 +2003,39 @@@ 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,
                .event_mask = ButtonPressMask|ExposureMask
        };
 +      XClassHint ch = {"dwm", "dwm"};
        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, DefaultDepth(dpy, screen),
 +                              CopyFromParent, DefaultVisual(dpy, screen),
 +                              CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
                XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
 +              if (showsystray && m == systraytomon(m))
 +                      XMapRaised(dpy, systray->win);
                XMapRaised(dpy, m->barwin);
 +              XSetClassHint(dpy, m->barwin, &ch);
        }
  }
  
@@@ -2062,8 -1834,8 +2062,8 @@@ updateclientlist(
        for (m = mons; m; m = m->next)
                for (c = m->clients; c; c = c->next)
                        XChangeProperty(dpy, root, netatom[NetClientList],
 -                                      XA_WINDOW, 32, PropModeAppend,
 -                                      (unsigned char *) &(c->win), 1);
 +                              XA_WINDOW, 32, PropModeAppend,
 +                              (unsigned char *) &(c->win), 1);
  }
  
  int
@@@ -2087,8 -1859,8 +2087,8 @@@ updategeom(void
                                memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
                XFree(info);
                nn = j;
 -              if (n <= nn) {
 -                      for (i = 0; i < (nn - n); i++) { /* new monitors available */
 +              if (n <= nn) { /* new monitors available */
 +                      for (i = 0; i < (nn - n); i++) {
                                for (m = mons; m && m->next; m = m->next);
                                if (m)
                                        m->next = createmon();
                        }
                        for (i = 0, m = mons; i < nn && m; m = m->next, i++)
                                if (i >= n
 -                              || (unique[i].x_org != m->mx || unique[i].y_org != m->my
 -                                  || unique[i].width != m->mw || unique[i].height != m->mh))
 +                              || unique[i].x_org != m->mx || unique[i].y_org != m->my
 +                              || unique[i].width != m->mw || unique[i].height != m->mh)
                                {
                                        dirty = 1;
                                        m->num = i;
                                        m->mh = m->wh = unique[i].height;
                                        updatebarpos(m);
                                }
 -              } else {
 -                      /* less monitors available nn < n */
 +              } else { /* less monitors available nn < n */
                        for (i = nn; i < n; i++) {
                                for (m = mons; m && m->next; m = m->next);
 -                              while (m->clients) {
 +                              while ((c = m->clients)) {
                                        dirty = 1;
 -                                      c = m->clients;
                                        m->clients = c->next;
                                        detachstack(c);
                                        c->mon = mons;
                free(unique);
        } else
  #endif /* XINERAMA */
 -      /* default monitor setup */
 -      {
 +      { /* default monitor setup */
                if (!mons)
                        mons = createmon();
                if (mons->mw != sw || mons->mh != sh) {
@@@ -2155,7 -1930,7 +2155,7 @@@ updatenumlockmask(void
        for (i = 0; i < 8; i++)
                for (j = 0; j < modmap->max_keypermod; j++)
                        if (modmap->modifiermap[i * modmap->max_keypermod + j]
 -                         == XKeysymToKeycode(dpy, XK_Num_Lock))
 +                              == XKeysymToKeycode(dpy, XK_Num_Lock))
                                numlockmask = (1 << i);
        XFreeModifiermap(modmap);
  }
@@@ -2200,141 -1975,29 +2200,142 @@@ updatesizehints(Client *c
                c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
        } else
                c->maxa = c->mina = 0.0;
 -      c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
 -                   && c->maxw == c->minw && c->maxh == c->minh);
 -}
 -
 -void
 -updatetitle(Client *c)
 -{
 -      if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
 -              gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
 -      if (c->name[0] == '\0') /* hack to mark broken clients */
 -              strcpy(c->name, broken);
 +      c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
  }
  
  void
  updatestatus(void)
  {
+       Monitor* m;
        if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
                strcpy(stext, "dwm-"VERSION);
-       drawbar(selmon);
-       updatesystray();
+       for(m = mons; m; m = m->next)
+               drawbar(m);
  }
  
 +void
 +updatesystrayicongeom(Client *i, int w, int h)
 +{
 +      if (i) {
 +              i->h = bh;
 +              if (w == h)
 +                      i->w = bh;
 +              else if (h == bh)
 +                      i->w = w;
 +              else
 +                      i->w = (int) ((float)bh * ((float)w / (float)h));
 +              applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
 +              /* force icons into the systray dimenons if they don't want to */
 +              if (i->h > bh) {
 +                      if (i->w == i->h)
 +                              i->w = bh;
 +                      else
 +                              i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
 +                      i->h = bh;
 +              }
 +      }
 +}
 +
 +void
 +updatesystrayiconstate(Client *i, XPropertyEvent *ev)
 +{
 +      long flags;
 +      int code = 0;
 +
 +      if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
 +                      !(flags = getatomprop(i, xatom[XembedInfo])))
 +              return;
 +
 +      if (flags & XEMBED_MAPPED && !i->tags) {
 +              i->tags = 1;
 +              code = XEMBED_WINDOW_ACTIVATE;
 +              XMapRaised(dpy, i->win);
 +              setclientstate(i, NormalState);
 +      }
 +      else if (!(flags & XEMBED_MAPPED) && i->tags) {
 +              i->tags = 0;
 +              code = XEMBED_WINDOW_DEACTIVATE;
 +              XUnmapWindow(dpy, i->win);
 +              setclientstate(i, WithdrawnState);
 +      }
 +      else
 +              return;
 +      sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
 +                      systray->win, XEMBED_EMBEDDED_VERSION);
 +}
 +
 +void
 +updatesystray(void)
 +{
 +      XSetWindowAttributes wa;
 +      XWindowChanges wc;
 +      Client *i;
 +      Monitor *m = systraytomon(NULL);
 +      unsigned int x = m->mx + m->mw;
 +      unsigned int w = 1;
 +
 +      if (!showsystray)
 +              return;
 +      if (!systray) {
 +              /* init systray */
 +              if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
 +                      die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
 +              systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
 +              wa.event_mask        = ButtonPressMask | ExposureMask;
 +              wa.override_redirect = True;
 +              wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
 +              XSelectInput(dpy, systray->win, SubstructureNotifyMask);
 +              XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
 +                              PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
 +              XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
 +              XMapRaised(dpy, systray->win);
 +              XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
 +              if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
 +                      sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
 +                      XSync(dpy, False);
 +              }
 +              else {
 +                      fprintf(stderr, "dwm: unable to obtain system tray.\n");
 +                      free(systray);
 +                      systray = NULL;
 +                      return;
 +              }
 +      }
 +      for (w = 0, i = systray->icons; i; i = i->next) {
 +              /* make sure the background color stays the same */
 +              wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
 +              XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
 +              XMapRaised(dpy, i->win);
 +              w += systrayspacing;
 +              i->x = w;
 +              XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
 +              w += i->w;
 +              if (i->mon != m)
 +                      i->mon = m;
 +      }
 +      w = w ? w + systrayspacing : 1;
 +      x -= w;
 +      XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
 +      wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
 +      wc.stack_mode = Above; wc.sibling = m->barwin;
 +      XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
 +      XMapWindow(dpy, systray->win);
 +      XMapSubwindows(dpy, systray->win);
 +      /* redraw background */
 +      XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
 +      XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
 +      XSync(dpy, False);
 +}
 +
 +void
 +updatetitle(Client *c)
 +{
 +      if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
 +              gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
 +      if (c->name[0] == '\0') /* hack to mark broken clients */
 +              strcpy(c->name, broken);
 +}
 +
  void
  updatewindowtype(Client *c)
  {
@@@ -2391,16 -2054,6 +2392,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)
  {
  }
  
  /* There's no way to check accesses to destroyed windows, thus those cases are
 - * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
 - * default error handler, which may call exit.  */
 + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
 + * default error handler, which may call exit. */
  int
  xerror(Display *dpy, XErrorEvent *ee)
  {
        || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
                return 0;
        fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
 -                      ee->request_code, ee->error_code);
 +              ee->request_code, ee->error_code);
        return xerrorxlib(dpy, ee); /* may call exit */
  }
  
@@@ -2450,26 -2103,10 +2451,26 @@@ xerrordummy(Display *dpy, XErrorEvent *
  int
  xerrorstart(Display *dpy, XErrorEvent *ee)
  {
 -      die("dwm: another window manager is already running\n");
 +      die("dwm: another window manager is already running");
        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)
  {
  main(int argc, char *argv[])
  {
        if (argc == 2 && !strcmp("-v", argv[1]))
 -              die("dwm-"VERSION "\n");
 +              die("dwm-"VERSION);
        else if (argc != 1)
 -              die("usage: dwm [-v]\n");
 +              die("usage: dwm [-v]");
        if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
                fputs("warning: no locale support\n", stderr);
        if (!(dpy = XOpenDisplay(NULL)))
 -              die("dwm: cannot open display\n");
 +              die("dwm: cannot open display");
        checkotherwm();
        setup();
 +#ifdef __OpenBSD__
 +      if (pledge("stdio rpath proc exec", NULL) == -1)
 +              die("pledge");
 +#endif /* __OpenBSD__ */
        scan();
        run();
        cleanup();