Hi Jan Cristoph,

Sorry for the extreme delay, it's been six months since the last email
and I read this only yesterday reviewing my inbox but here it is.
There are other things that I patched but nothing extraordinary its
just a basic setup.

Again, I'm really sorry.

>From b44eb5b5adb57eb1d33b8df09c73c28c436fc26e Mon Sep 17 00:00:00 2001
From: Joel Santos <[email protected]>
Date: Thu, 27 Oct 2016 07:46:46 -0300
Subject: [PATCH 1/2] =?UTF-8?q?Aplica=C3=A7=C3=A3o=20do=20patch=20de=20sys?=
 =?UTF-8?q?tray.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .gitignore   |   2 +
 config.def.h |   4 +
 config.h     | 119 ++++++++++++++++++
 dwm.c        | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 496 insertions(+), 24 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 config.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..095e840
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+dwm
diff --git a/config.def.h b/config.def.h
index fd77a07..d21488f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -3,6 +3,10 @@
 /* appearance */
 static const unsigned int borderpx  = 1;        /* border pixel of windows */
 static const unsigned int snap      = 32;       /* snap pixel */
+static const unsigned int systraypinning = 0;   /* 0: sloppy systray
follows selected monitor, >0: pin systray to monitor X */
+static const unsigned int systrayspacing = 2;   /* systray spacing */
+static const int systraypinningfailfirst = 1;   /* 1: if pinning
fails, display systray on the first monitor, False: display systray on
the last monitor*/
+static const int showsystray        = 1;     /* 0 means no systray */
 static const int showbar            = 1;        /* 0 means no bar */
 static const int topbar             = 1;        /* 0 means bottom bar */
 static const char *fonts[]          = { "monospace:size=10" };
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..5730245
--- /dev/null
+++ b/config.h
@@ -0,0 +1,119 @@
+/* See LICENSE file for copyright and license details. */
+
+/* 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[]          = { "Noto Mono:size=8:antialias=true" };
+static const char dmenufont[]       = "Noto Mono:size=8:antialias=true";
+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 *colors[SchemeLast][3]      = {
+ /*               fg         bg         border   */
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+ [SchemeSel] =  { col_gray4, col_cyan,  col_cyan  },
+};
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+static const Rule rules[] = {
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+ /* class      instance    title       tags mask     isfloating   monitor */
+ { "Gimp",     NULL,       NULL,       0,            1,           -1 },
+ { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
+};
+
+/* layout(s) */
+static const float mfact     = 0.55; /* factor of master area size
[0.05..0.95] */
+static const int nmaster     = 1;    /* number of clients in master area */
+static const int resizehints = 0;    /* 1 means respect size hints in
tiled resizals */
+
+static const Layout layouts[] = {
+ /* symbol     arrange function */
+ { "[]=",      tile },    /* first entry is default */
+ { "><>",      NULL },    /* no layout function means floating behavior */
+ { "[M]",      monocle },
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+ { MODKEY,                       KEY,      view,           {.ui = 1
<< TAG} }, \
+ { MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1
<< TAG} }, \
+ { MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1
<< TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated
in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn",
dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf",
col_gray4, NULL };
+static const char *termcmd[]  = { "xfce4-terminal", NULL };
+
+static Key keys[] = {
+ /* modifier                     key        function        argument */
+ { MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
+ { MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
+ { MODKEY,                       XK_b,      togglebar,      {0} },
+ { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
+ { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
+ { MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
+ { MODKEY,                       XK_d,      incnmaster,     {.i = -1 } },
+ { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
+ { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
+ { MODKEY,                       XK_Return, zoom,           {0} },
+ { MODKEY,                       XK_Tab,    view,           {0} },
+ { MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
+ { MODKEY,                       XK_t,      setlayout,      {.v =
&layouts[0]} },
+ { MODKEY,                       XK_f,      setlayout,      {.v =
&layouts[1]} },
+ { MODKEY,                       XK_m,      setlayout,      {.v =
&layouts[2]} },
+ { MODKEY,                       XK_space,  setlayout,      {0} },
+ { MODKEY|ShiftMask,             XK_space,  togglefloating, {0} },
+ { MODKEY,                       XK_0,      view,           {.ui = ~0 } },
+ { MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
+ { MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
+ { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
+ { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
+ { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
+ TAGKEYS(                        XK_1,                      0)
+ TAGKEYS(                        XK_2,                      1)
+ TAGKEYS(                        XK_3,                      2)
+ TAGKEYS(                        XK_4,                      3)
+ TAGKEYS(                        XK_5,                      4)
+ TAGKEYS(                        XK_6,                      5)
+ TAGKEYS(                        XK_7,                      6)
+ TAGKEYS(                        XK_8,                      7)
+ TAGKEYS(                        XK_9,                      8)
+ { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
+};
+
+/* button definitions */
+/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, or ClkRootWin */
+static Button buttons[] = {
+ /* click                event mask      button          function
   argument */
+ { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
+ { ClkLtSymbol,          0,              Button3,        setlayout,
   {.v = &layouts[2]} },
+ { ClkWinTitle,          0,              Button2,        zoom,           {0} },
+ { ClkStatusText,        0,              Button2,        spawn,
   {.v = termcmd } },
+ { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
+ { ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
+ { ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
+ { ClkTagBar,            0,              Button1,        view,           {0} },
+ { ClkTagBar,            0,              Button3,        toggleview,     {0} },
+ { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
+ { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
+};
+
diff --git a/dwm.c b/dwm.c
index 421bf27..21dda9e 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, SchemeLast }; /* color schemes */
 enum { NetSupported, NetWMName, NetWMState,
+       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 */
@@ -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);
@@ -171,8 +195,10 @@ static void focus(Client *c);
 static void focusin(XEvent *e);
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
+static Atom getatomprop(Client *c, Atom prop);
 static int getrootptr(int *x, int *y);
 static long getstate(Window w);
+static unsigned int getsystraywidth();
 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
 static void grabbuttons(Client *c, int focused);
 static void grabkeys(void);
@@ -190,13 +216,16 @@ static void pop(Client *);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
 static Monitor *recttomon(int x, int y, int w, int h);
+static void removesystrayicon(Client *i);
 static void resize(Client *c, int x, int y, int w, int h, int interact);
+static void resizebarwin(Monitor *m);
 static void resizeclient(Client *c, int x, int y, int w, int h);
 static void resizemouse(const Arg *arg);
+static void resizerequest(XEvent *e);
 static void restack(Monitor *m);
 static void run(void);
 static void scan(void);
-static int sendevent(Client *c, Atom proto);
+static int sendevent(Window w, Atom proto, int m, long d0, long d1,
long d2, long d3, long d4);
 static void sendmon(Client *c, Monitor *m);
 static void setclientstate(Client *c, long state);
 static void setfocus(Client *c);
@@ -207,6 +236,7 @@ static void setup(void);
 static void showhide(Client *c);
 static void sigchld(int unused);
 static void spawn(const Arg *arg);
+static Monitor *systraytomon(Monitor *m);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void tile(Monitor *);
@@ -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[SchemeLast];
@@ -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 < SchemeLast; i++)
@@ -523,9 +564,52 @@ clearurgent(Client *c)
 void
 clientmessage(XEvent *e)
 {
+ XWindowAttributes wa;
+ XSetWindowAttributes swa;
  XClientMessageEvent *cme = &e->xclient;
  Client *c = wintoclient(cme->window);

+ if (showsystray && cme->window == systray->win && cme->message_type
== netatom[NetSystemTrayOP]) {
+ /* add systray icons */
+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+ if (!(c = (Client *)calloc(1, sizeof(Client))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+ 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]) {
@@ -580,7 +664,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);
@@ -665,6 +749,11 @@ destroynotify(XEvent *e)

  if ((c = wintoclient(ev->window)))
  unmanage(c, 1);
+ else if ((c = wintosystrayicon(ev->window))) {
+ removesystrayicon(c);
+ resizebarwin(selmon);
+ updatesystray();
+ }
 }

 void
@@ -708,19 +797,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; /* no right padding so status text
hugs the corner */
- drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
+ 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)
@@ -741,7 +834,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);
@@ -752,7 +845,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
@@ -789,8 +882,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
@@ -877,10 +973,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;
@@ -914,6 +1017,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)
 {
@@ -1020,7 +1133,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);
@@ -1108,6 +1221,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;
@@ -1235,6 +1354,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)
@@ -1286,6 +1415,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))
@@ -1293,6 +1436,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;
@@ -1365,6 +1516,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;
@@ -1453,26 +1617,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;
 }
@@ -1486,7 +1660,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
@@ -1572,12 +1746,19 @@ setup(void)
  wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
  netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
  netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy,
"_NET_SYSTEM_TRAY_ORIENTATION", False);
+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy,
"_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
  netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  netatom[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);
@@ -1585,6 +1766,8 @@ setup(void)
  /* init appearance */
  scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3);
  scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3);
+ /* init system tray */
+ updatesystray();
  /* init bars */
  updatebars();
  updatestatus();
@@ -1693,7 +1876,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);
 }

@@ -1789,11 +1983,18 @@ unmapnotify(XEvent *e)
  else
  unmanage(c, 0);
  }
+ else if ((c = wintosystrayicon(ev->window))) {
+ /* KLUDGE! sometimes icons occasionally unmap their windows, but do
+ * _not_ destroy them. We map those windows back */
+ XMapRaised(dpy, c->win);
+ updatesystray();
+ }
 }

 void
 updatebars(void)
 {
+ unsigned int w;
  Monitor *m;
  XSetWindowAttributes wa = {
  .override_redirect = True,
@@ -1803,10 +2004,15 @@ updatebars(void)
  for (m = mons; m; m = m->next) {
  if (m->barwin)
  continue;
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0,
DefaultDepth(dpy, screen),
+ 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);
  }
 }
@@ -1994,6 +2200,121 @@ updatestatus(void)
  if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
  strcpy(stext, "dwm-"VERSION);
  drawbar(selmon);
+ updatesystray();
+}
+
+void
+updatesystrayicongeom(Client *i, int w, int h)
+{
+ if (i) {
+ i->h = bh;
+ if (w == h)
+ i->w = bh;
+ else if (h == bh)
+ i->w = w;
+ else
+ i->w = (int) ((float)bh * ((float)w / (float)h));
+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
+ /* force icons into the systray dimenons if they don't want to */
+ if (i->h > bh) {
+ if (i->w == i->h)
+ i->w = bh;
+ else
+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
+ i->h = bh;
+ }
+ }
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+ long flags;
+ int code = 0;
+
+ if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
+ !(flags = getatomprop(i, xatom[XembedInfo])))
+ return;
+
+ if (flags & XEMBED_MAPPED && !i->tags) {
+ i->tags = 1;
+ code = XEMBED_WINDOW_ACTIVATE;
+ XMapRaised(dpy, i->win);
+ setclientstate(i, NormalState);
+ }
+ else if (!(flags & XEMBED_MAPPED) && i->tags) {
+ i->tags = 0;
+ code = XEMBED_WINDOW_DEACTIVATE;
+ XUnmapWindow(dpy, i->win);
+ setclientstate(i, WithdrawnState);
+ }
+ else
+ return;
+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+ systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+void
+updatesystray(void)
+{
+ XSetWindowAttributes wa;
+ XWindowChanges wc;
+ Client *i;
+ Monitor *m = systraytomon(NULL);
+ unsigned int x = m->mx + m->mw;
+ unsigned int w = 1;
+
+ if (!showsystray)
+ return;
+ if (!systray) {
+ /* init systray */
+ if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
+ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0,
scheme[SchemeSel][ColBg].pixel);
+ wa.event_mask        = ButtonPressMask | ExposureMask;
+ wa.override_redirect = True;
+ wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+ XChangeProperty(dpy, systray->win,
netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
+ XChangeWindowAttributes(dpy, systray->win,
CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
+ XMapRaised(dpy, systray->win);
+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime,
netatom[NetSystemTray], systray->win, 0, 0);
+ XSync(dpy, False);
+ }
+ else {
+ fprintf(stderr, "dwm: unable to obtain system tray.\n");
+ free(systray);
+ systray = NULL;
+ return;
+ }
+ }
+ for (w = 0, i = systray->icons; i; i = i->next) {
+ /* make sure the background color stays the same */
+ wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
+ XMapRaised(dpy, i->win);
+ w += systrayspacing;
+ i->x = w;
+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
+ w += i->w;
+ if (i->mon != m)
+ i->mon = m;
+ }
+ w = w ? w + systrayspacing : 1;
+ x -= w;
+ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
+ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
+ wc.stack_mode = Above; wc.sibling = m->barwin;
+ XConfigureWindow(dpy, systray->win,
CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
+ XMapWindow(dpy, systray->win);
+ XMapSubwindows(dpy, systray->win);
+ /* redraw background */
+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
+ XSync(dpy, False);
 }

 void
@@ -2052,6 +2373,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)
 {
@@ -2105,6 +2436,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
  return -1;
 }

+Monitor *
+systraytomon(Monitor *m) {
+ Monitor *t;
+ int i, n;
+ if(!systraypinning) {
+ if(!m)
+ return selmon;
+ return m == selmon ? m : NULL;
+ }
+ for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
+ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
+ if(systraypinningfailfirst && n < systraypinning)
+ return mons;
+ return t;
+}
+
 void
 zoom(const Arg *arg)
 {
-- 
2.7.4


>From f0b12bd52f497732ee52323c23d8077407b86ff7 Mon Sep 17 00:00:00 2001
From: Joel Santos <[email protected]>
Date: Sun, 18 Dec 2016 10:48:37 -0300
Subject: [PATCH 2/2] =?UTF-8?q?Altera=C3=A7=C3=A3o=20da=20configura=C3=A7?=
 =?UTF-8?q?=C3=A3o.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 config.h | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/config.h b/config.h
index 5730245..566da89 100644
--- a/config.h
+++ b/config.h
@@ -9,8 +9,8 @@ static const int systraypinningfailfirst = 1;   /* 1:
if pinning fails, display
 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[]          = { "Noto Mono:size=8:antialias=true" };
-static const char dmenufont[]       = "Noto Mono:size=8:antialias=true";
+static const char *fonts[]          = { "Source Sans
Pro:size=9:antialias=true" };
+static const char dmenufont[]       = "Source Sans Pro:size=9:antialias=true";
 static const char col_gray1[]       = "#222222";
 static const char col_gray2[]       = "#444444";
 static const char col_gray3[]       = "#bbbbbb";
@@ -42,9 +42,9 @@ static const int resizehints = 0;    /* 1 means
respect size hints in tiled resi

 static const Layout layouts[] = {
  /* symbol     arrange function */
- { "[]=",      tile },    /* first entry is default */
- { "><>",      NULL },    /* no layout function means floating behavior */
- { "[M]",      monocle },
+ { "#",      tile },    /* first entry is default */
+ { "@",      NULL },    /* no layout function means floating behavior */
+ { "M",      monocle },
 };

 /* key definitions */
@@ -62,11 +62,21 @@ static const Layout layouts[] = {
 static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated
in spawn() */
 static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn",
dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf",
col_gray4, NULL };
 static const char *termcmd[]  = { "xfce4-terminal", NULL };
+static const char *mutecmd[] =
{"amixer","-D","pulse","sset","Master","toggle",NULL};
+static const char *lowervolcmd[] =
{"amixer","-D","pulse","sset","Master","3%-",NULL};
+static const char *raisevolcmd[] =
{"amixer","-D","pulse","sset","Master","3%+",NULL};
+static const char *lowerlightcmd[] = {"xbacklight","-dec","10",NULL};
+static const char *raiselightcmd[] = {"xbacklight","-inc","10",NULL};
+static const char *lockcmd[] = {"slock",NULL};
+static const char *mediaplay[] = {"playerctl","play-pause",NULL};
+static const char *medianext[] = {"playerctl","next",NULL};
+static const char *mediaprev[] = {"playerctl","previous",NULL};

 static Key keys[] = {
  /* modifier                     key        function        argument */
  { MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
  { MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
+ { MODKEY|ShiftMask,             XK_l,      spawn,          {.v = lockcmd } },
  { MODKEY,                       XK_b,      togglebar,      {0} },
  { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
  { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
@@ -88,6 +98,14 @@ static Key keys[] = {
  { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
  { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
  { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
+    { 0,                            0x1008ff14,spawn,          {.v =
mediaplay } },
+    { 0,                            0x1008ff17,spawn,          {.v =
medianext } },
+    { 0,                            0x1008ff16,spawn,          {.v =
mediaprev } },
+    { 0,                            0x1008ff12,spawn,          {.v =
mutecmd } },
+    { 0,                            0x1008ff11,spawn,          {.v =
lowervolcmd } },
+    { 0,                            0x1008ff13,spawn,          {.v =
raisevolcmd } },
+    { 0,                            0x1008ff03,spawn,          {.v =
lowerlightcmd } },
+    { 0,                            0x1008ff02,spawn,          {.v =
raiselightcmd } },
  TAGKEYS(                        XK_1,                      0)
  TAGKEYS(                        XK_2,                      1)
  TAGKEYS(                        XK_3,                      2)
-- 
2.7.4
Muito obrigado.
Joel


2016-12-26 6:18 GMT-03:00 Jan Christoph Ebersbach <[email protected]>:
> @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
>
> --
> window manager Improved 2 (wmii) - Google Groups
> http://groups.google.com/group/wmii
> ---
> You received this message because you are subscribed to a topic in the Google 
> Groups "window manager Improved 2 (wmii)" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/wmii/-Lf0fBphJk8/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to 
> [email protected].
> For more options, visit https://groups.google.com/d/optout.
From b44eb5b5adb57eb1d33b8df09c73c28c436fc26e Mon Sep 17 00:00:00 2001
From: Joel Santos <[email protected]>
Date: Thu, 27 Oct 2016 07:46:46 -0300
Subject: [PATCH 1/2] =?UTF-8?q?Aplica=C3=A7=C3=A3o=20do=20patch=20de=20sys?=
 =?UTF-8?q?tray.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .gitignore   |   2 +
 config.def.h |   4 +
 config.h     | 119 ++++++++++++++++++
 dwm.c        | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 496 insertions(+), 24 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 config.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..095e840
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+dwm
diff --git a/config.def.h b/config.def.h
index fd77a07..d21488f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -3,6 +3,10 @@
 /* appearance */
 static const unsigned int borderpx  = 1;        /* border pixel of windows */
 static const unsigned int snap      = 32;       /* snap pixel */
+static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
+static const unsigned int systrayspacing = 2;   /* systray spacing */
+static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
+static const int showsystray        = 1;     /* 0 means no systray */
 static const int showbar            = 1;        /* 0 means no bar */
 static const int topbar             = 1;        /* 0 means bottom bar */
 static const char *fonts[]          = { "monospace:size=10" };
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..5730245
--- /dev/null
+++ b/config.h
@@ -0,0 +1,119 @@
+/* See LICENSE file for copyright and license details. */
+
+/* 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[]          = { "Noto Mono:size=8:antialias=true" };
+static const char dmenufont[]       = "Noto Mono:size=8:antialias=true";
+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 *colors[SchemeLast][3]      = {
+	/*               fg         bg         border   */
+	[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+	[SchemeSel] =  { col_gray4, col_cyan,  col_cyan  },
+};
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+static const Rule rules[] = {
+	/* xprop(1):
+	 *	WM_CLASS(STRING) = instance, class
+	 *	WM_NAME(STRING) = title
+	 */
+	/* class      instance    title       tags mask     isfloating   monitor */
+	{ "Gimp",     NULL,       NULL,       0,            1,           -1 },
+	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
+};
+
+/* layout(s) */
+static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster     = 1;    /* number of clients in master area */
+static const int resizehints = 0;    /* 1 means respect size hints in tiled resizals */
+
+static const Layout layouts[] = {
+	/* symbol     arrange function */
+	{ "[]=",      tile },    /* first entry is default */
+	{ "><>",      NULL },    /* no layout function means floating behavior */
+	{ "[M]",      monocle },
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
+	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
+	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
+	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+static const char *termcmd[]  = { "xfce4-terminal", NULL };
+
+static Key keys[] = {
+	/* modifier                     key        function        argument */
+	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
+	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
+	{ MODKEY,                       XK_b,      togglebar,      {0} },
+	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
+	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
+	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
+	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } },
+	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
+	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
+	{ MODKEY,                       XK_Return, zoom,           {0} },
+	{ MODKEY,                       XK_Tab,    view,           {0} },
+	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
+	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
+	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
+	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} },
+	{ MODKEY,                       XK_space,  setlayout,      {0} },
+	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} },
+	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } },
+	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
+	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
+	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } },
+	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
+	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
+	TAGKEYS(                        XK_1,                      0)
+	TAGKEYS(                        XK_2,                      1)
+	TAGKEYS(                        XK_3,                      2)
+	TAGKEYS(                        XK_4,                      3)
+	TAGKEYS(                        XK_5,                      4)
+	TAGKEYS(                        XK_6,                      5)
+	TAGKEYS(                        XK_7,                      6)
+	TAGKEYS(                        XK_8,                      7)
+	TAGKEYS(                        XK_9,                      8)
+	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} },
+};
+
+/* button definitions */
+/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static Button buttons[] = {
+	/* click                event mask      button          function        argument */
+	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
+	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
+	{ ClkWinTitle,          0,              Button2,        zoom,           {0} },
+	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
+	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
+	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
+	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
+	{ ClkTagBar,            0,              Button1,        view,           {0} },
+	{ ClkTagBar,            0,              Button3,        toggleview,     {0} },
+	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
+	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
+};
+
diff --git a/dwm.c b/dwm.c
index 421bf27..21dda9e 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, SchemeLast }; /* color schemes */
 enum { NetSupported, NetWMName, NetWMState,
+       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 */
@@ -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);
@@ -171,8 +195,10 @@ static void focus(Client *c);
 static void focusin(XEvent *e);
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
+static Atom getatomprop(Client *c, Atom prop);
 static int getrootptr(int *x, int *y);
 static long getstate(Window w);
+static unsigned int getsystraywidth();
 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
 static void grabbuttons(Client *c, int focused);
 static void grabkeys(void);
@@ -190,13 +216,16 @@ static void pop(Client *);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
 static Monitor *recttomon(int x, int y, int w, int h);
+static void removesystrayicon(Client *i);
 static void resize(Client *c, int x, int y, int w, int h, int interact);
+static void resizebarwin(Monitor *m);
 static void resizeclient(Client *c, int x, int y, int w, int h);
 static void resizemouse(const Arg *arg);
+static void resizerequest(XEvent *e);
 static void restack(Monitor *m);
 static void run(void);
 static void scan(void);
-static int sendevent(Client *c, Atom proto);
+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
 static void sendmon(Client *c, Monitor *m);
 static void setclientstate(Client *c, long state);
 static void setfocus(Client *c);
@@ -207,6 +236,7 @@ static void setup(void);
 static void showhide(Client *c);
 static void sigchld(int unused);
 static void spawn(const Arg *arg);
+static Monitor *systraytomon(Monitor *m);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void tile(Monitor *);
@@ -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[SchemeLast];
@@ -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 < SchemeLast; i++)
@@ -523,9 +564,52 @@ clearurgent(Client *c)
 void
 clientmessage(XEvent *e)
 {
+	XWindowAttributes wa;
+	XSetWindowAttributes swa;
 	XClientMessageEvent *cme = &e->xclient;
 	Client *c = wintoclient(cme->window);
 
+	if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
+		/* add systray icons */
+		if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+			if (!(c = (Client *)calloc(1, sizeof(Client))))
+				die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+			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]) {
@@ -580,7 +664,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);
@@ -665,6 +749,11 @@ destroynotify(XEvent *e)
 
 	if ((c = wintoclient(ev->window)))
 		unmanage(c, 1);
+	else if ((c = wintosystrayicon(ev->window))) {
+		removesystrayicon(c);
+		resizebarwin(selmon);
+		updatesystray();
+	}
 }
 
 void
@@ -708,19 +797,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; /* no right padding so status text hugs the corner */
-		drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
+		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)
@@ -741,7 +834,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);
@@ -752,7 +845,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
@@ -789,8 +882,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
@@ -877,10 +973,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;
@@ -914,6 +1017,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)
 {
@@ -1020,7 +1133,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);
@@ -1108,6 +1221,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;
@@ -1235,6 +1354,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)
@@ -1286,6 +1415,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))
@@ -1293,6 +1436,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;
@@ -1365,6 +1516,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;
@@ -1453,26 +1617,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;
 }
@@ -1486,7 +1660,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
@@ -1572,12 +1746,19 @@ setup(void)
 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+	netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
+	netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
+	netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
+	netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
 	netatom[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);
@@ -1585,6 +1766,8 @@ setup(void)
 	/* init appearance */
 	scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3);
 	scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3);
+	/* init system tray */
+	updatesystray();
 	/* init bars */
 	updatebars();
 	updatestatus();
@@ -1693,7 +1876,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);
 }
 
@@ -1789,11 +1983,18 @@ unmapnotify(XEvent *e)
 		else
 			unmanage(c, 0);
 	}
+	else if ((c = wintosystrayicon(ev->window))) {
+		/* KLUDGE! sometimes icons occasionally unmap their windows, but do
+		 * _not_ destroy them. We map those windows back */
+		XMapRaised(dpy, c->win);
+		updatesystray();
+	}
 }
 
 void
 updatebars(void)
 {
+	unsigned int w;
 	Monitor *m;
 	XSetWindowAttributes wa = {
 		.override_redirect = True,
@@ -1803,10 +2004,15 @@ updatebars(void)
 	for (m = mons; m; m = m->next) {
 		if (m->barwin)
 			continue;
-		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+		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);
 	}
 }
@@ -1994,6 +2200,121 @@ updatestatus(void)
 	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
 		strcpy(stext, "dwm-"VERSION);
 	drawbar(selmon);
+	updatesystray();
+}
+
+void
+updatesystrayicongeom(Client *i, int w, int h)
+{
+	if (i) {
+		i->h = bh;
+		if (w == h)
+			i->w = bh;
+		else if (h == bh)
+			i->w = w;
+		else
+			i->w = (int) ((float)bh * ((float)w / (float)h));
+		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
+		/* force icons into the systray dimenons if they don't want to */
+		if (i->h > bh) {
+			if (i->w == i->h)
+				i->w = bh;
+			else
+				i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
+			i->h = bh;
+		}
+	}
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+	long flags;
+	int code = 0;
+
+	if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
+			!(flags = getatomprop(i, xatom[XembedInfo])))
+		return;
+
+	if (flags & XEMBED_MAPPED && !i->tags) {
+		i->tags = 1;
+		code = XEMBED_WINDOW_ACTIVATE;
+		XMapRaised(dpy, i->win);
+		setclientstate(i, NormalState);
+	}
+	else if (!(flags & XEMBED_MAPPED) && i->tags) {
+		i->tags = 0;
+		code = XEMBED_WINDOW_DEACTIVATE;
+		XUnmapWindow(dpy, i->win);
+		setclientstate(i, WithdrawnState);
+	}
+	else
+		return;
+	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+			systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+void
+updatesystray(void)
+{
+	XSetWindowAttributes wa;
+	XWindowChanges wc;
+	Client *i;
+	Monitor *m = systraytomon(NULL);
+	unsigned int x = m->mx + m->mw;
+	unsigned int w = 1;
+
+	if (!showsystray)
+		return;
+	if (!systray) {
+		/* init systray */
+		if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
+			die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
+		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
+		wa.event_mask        = ButtonPressMask | ExposureMask;
+		wa.override_redirect = True;
+		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+		XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
+		XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
+		XMapRaised(dpy, systray->win);
+		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
+		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
+			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
+			XSync(dpy, False);
+		}
+		else {
+			fprintf(stderr, "dwm: unable to obtain system tray.\n");
+			free(systray);
+			systray = NULL;
+			return;
+		}
+	}
+	for (w = 0, i = systray->icons; i; i = i->next) {
+		/* make sure the background color stays the same */
+		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
+		XMapRaised(dpy, i->win);
+		w += systrayspacing;
+		i->x = w;
+		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
+		w += i->w;
+		if (i->mon != m)
+			i->mon = m;
+	}
+	w = w ? w + systrayspacing : 1;
+ 	x -= w;
+	XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
+	wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
+	wc.stack_mode = Above; wc.sibling = m->barwin;
+	XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
+	XMapWindow(dpy, systray->win);
+	XMapSubwindows(dpy, systray->win);
+	/* redraw background */
+	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
+	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
+	XSync(dpy, False);
 }
 
 void
@@ -2052,6 +2373,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)
 {
@@ -2105,6 +2436,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
 	return -1;
 }
 
+Monitor *
+systraytomon(Monitor *m) {
+	Monitor *t;
+	int i, n;
+	if(!systraypinning) {
+		if(!m)
+			return selmon;
+		return m == selmon ? m : NULL;
+	}
+	for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
+	for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
+	if(systraypinningfailfirst && n < systraypinning)
+		return mons;
+	return t;
+}
+
 void
 zoom(const Arg *arg)
 {
-- 
2.7.4


From f0b12bd52f497732ee52323c23d8077407b86ff7 Mon Sep 17 00:00:00 2001
From: Joel Santos <[email protected]>
Date: Sun, 18 Dec 2016 10:48:37 -0300
Subject: [PATCH 2/2] =?UTF-8?q?Altera=C3=A7=C3=A3o=20da=20configura=C3=A7?=
 =?UTF-8?q?=C3=A3o.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 config.h | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/config.h b/config.h
index 5730245..566da89 100644
--- a/config.h
+++ b/config.h
@@ -9,8 +9,8 @@ static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display
 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[]          = { "Noto Mono:size=8:antialias=true" };
-static const char dmenufont[]       = "Noto Mono:size=8:antialias=true";
+static const char *fonts[]          = { "Source Sans Pro:size=9:antialias=true" };
+static const char dmenufont[]       = "Source Sans Pro:size=9:antialias=true";
 static const char col_gray1[]       = "#222222";
 static const char col_gray2[]       = "#444444";
 static const char col_gray3[]       = "#bbbbbb";
@@ -42,9 +42,9 @@ static const int resizehints = 0;    /* 1 means respect size hints in tiled resi
 
 static const Layout layouts[] = {
 	/* symbol     arrange function */
-	{ "[]=",      tile },    /* first entry is default */
-	{ "><>",      NULL },    /* no layout function means floating behavior */
-	{ "[M]",      monocle },
+	{ "#",      tile },    /* first entry is default */
+	{ "@",      NULL },    /* no layout function means floating behavior */
+	{ "M",      monocle },
 };
 
 /* key definitions */
@@ -62,11 +62,21 @@ static const Layout layouts[] = {
 static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
 static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
 static const char *termcmd[]  = { "xfce4-terminal", NULL };
+static const char *mutecmd[] = {"amixer","-D","pulse","sset","Master","toggle",NULL};
+static const char *lowervolcmd[] = {"amixer","-D","pulse","sset","Master","3%-",NULL};
+static const char *raisevolcmd[] = {"amixer","-D","pulse","sset","Master","3%+",NULL};
+static const char *lowerlightcmd[] = {"xbacklight","-dec","10",NULL};
+static const char *raiselightcmd[] = {"xbacklight","-inc","10",NULL};
+static const char *lockcmd[] = {"slock",NULL};
+static const char *mediaplay[] = {"playerctl","play-pause",NULL};
+static const char *medianext[] = {"playerctl","next",NULL};
+static const char *mediaprev[] = {"playerctl","previous",NULL};
 
 static Key keys[] = {
 	/* modifier                     key        function        argument */
 	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
 	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
+	{ MODKEY|ShiftMask,             XK_l,      spawn,          {.v = lockcmd } },
 	{ MODKEY,                       XK_b,      togglebar,      {0} },
 	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
 	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
@@ -88,6 +98,14 @@ static Key keys[] = {
 	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } },
 	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
 	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
+    { 0,                            0x1008ff14,spawn,          {.v = mediaplay } },
+    { 0,                            0x1008ff17,spawn,          {.v = medianext } },
+    { 0,                            0x1008ff16,spawn,          {.v = mediaprev } },
+    { 0,                            0x1008ff12,spawn,          {.v = mutecmd } },
+    { 0,                            0x1008ff11,spawn,          {.v = lowervolcmd } },
+    { 0,                            0x1008ff13,spawn,          {.v = raisevolcmd } },
+    { 0,                            0x1008ff03,spawn,          {.v = lowerlightcmd } },
+    { 0,                            0x1008ff02,spawn,          {.v = raiselightcmd } },
 	TAGKEYS(                        XK_1,                      0)
 	TAGKEYS(                        XK_2,                      1)
 	TAGKEYS(                        XK_3,                      2)
-- 
2.7.4

Reply via email to