Merge tag '6.2' into danno
authorDaniel <thefekete@gmail.com>
Thu, 28 Feb 2019 23:29:17 +0000 (00:29 +0100)
committerDaniel <thefekete@gmail.com>
Thu, 28 Feb 2019 23:29:17 +0000 (00:29 +0100)
.gitignore [new file with mode: 0644]
config.def.h
config.h [new file with mode: 0644]
dwm.1
dwm.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1223b23
--- /dev/null
@@ -0,0 +1,3 @@
+tags
+*.o
+dwm
index 1c0b587..750f181 100644 (file)
@@ -2,7 +2,12 @@
 
 /* appearance */
 static const unsigned int borderpx  = 1;        /* border pixel of windows */
+static const unsigned int gappx     = 1;        /* gap pixel between 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 (file)
index 0000000..c43ca81
--- /dev/null
+++ b/config.h
@@ -0,0 +1,144 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <X11/XF86keysym.h>
+
+/* appearance */
+static const unsigned int borderpx  = 1;        /* border pixel of windows */
+static const unsigned int gappx     = 8;        /* gap pixel between windows */
+static const unsigned int snap      = 16;       /* snap pixel */
+static const unsigned int systraypinning = 1;   /* 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 */
+#define BARFONT "DejaVu Sans:pixelsize=12"
+static const char *fonts[]          = { BARFONT };
+static const char dmenufont[]       = BARFONT;
+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[]        = "#007799";
+static const char *colors[][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 = 1;    /* 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 */
+       { "🔍",      monocle },  // TODO hide unfocused windows for background transparency?
+};
+
+/* key definitions */
+#define MODKEY Mod4Mask
+#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} },
+#define MEDIAKEY(KEY,CMD) {0, KEY, spawn, {.v = (const char *[]){ "sh", "-c", CMD, NULL } } }  /* TODO don't fire up unnecessary shells */
+
+/* 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[]  = { "st", NULL };
+static const char *helpcmd[]  = { "st", "-e", "man", "dwm", NULL };
+static const char *killx[]  = { "pkill", "xinit", 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_r,      quit,           {0} },  // just exits dwm, allows for restart
+       { MODKEY|ShiftMask,             XK_q,      spawn,          {.v = killx } },  // kills x session
+
+       { MODKEY|ShiftMask,             XK_h,      spawn,          {.v = helpcmd } },
+       { MODKEY,                       XK_w,      spawn,          {.v = (const char*[]){ "tabbed", "-cdps+1", "surf", "-e", NULL } } },
+       { MODKEY|ShiftMask,             XK_w,      spawn,          {.v = (const char*[]){ "chromium", NULL } } },
+       { MODKEY|ShiftMask,             XK_x,      spawn,          {.v = (const char*[]){ "st", "-c", "ish", "-t", "ish", "ish", NULL } } },
+       { MODKEY|ShiftMask,             XK_p,      spawn,          {.v = (const char*[]){ "mpc", "toggle", NULL } } },
+       { MODKEY|ShiftMask,             XK_n,      spawn,          {.v = (const char*[]){ "mpc", "next", NULL } } },
+
+       /* XF86 Keys */
+       MEDIAKEY( XF86XK_MonBrightnessUp,   "xbacklight -time 100 -inc 5"),
+       MEDIAKEY( XF86XK_MonBrightnessDown, "xbacklight -time 100 -dec 5"),
+       MEDIAKEY( XF86XK_AudioMute,         "pactl set-sink-mute @DEFAULT_SINK@ toggle"),
+       MEDIAKEY( XF86XK_AudioLowerVolume,  "pactl set-sink-volume @DEFAULT_SINK@ -10%"),
+       MEDIAKEY( XF86XK_AudioRaiseVolume,  "pactl set-sink-volume @DEFAULT_SINK@ +5%"),
+       MEDIAKEY( XF86XK_AudioMicMute,      "pactl set-source-mute @DEFAULT_SOURCE@ toggle"),
+       MEDIAKEY( XF86XK_WebCam,            "mpv --untimed /dev/video0"),
+
+};
+
+/* button definitions */
+/* click can be ClkTagBar, 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.1 b/dwm.1
index 13b3729..dc8f4d5 100644 (file)
--- a/dwm.1
+++ b/dwm.1
@@ -49,108 +49,108 @@ label toggles between tiled and floating layout.
 .B Button3
 click on a tag label adds/removes all windows with that tag to/from the view.
 .TP
-.B Mod1\-Button1
+.B Super\-Button1
 click on a tag label applies that tag to the focused window.
 .TP
-.B Mod1\-Button3
+.B Super\-Button3
 click on a tag label adds/removes that tag to/from the focused window.
 .SS Keyboard commands
 .TP
-.B Mod1\-Shift\-Return
+.B Super\-Shift\-Return
 Start
 .BR st(1).
 .TP
-.B Mod1\-p
+.B Super\-p
 Spawn
 .BR dmenu(1)
 for launching other programs.
 .TP
-.B Mod1\-,
+.B Super\-,
 Focus previous screen, if any.
 .TP
-.B Mod1\-.
+.B Super\-.
 Focus next screen, if any.
 .TP
-.B Mod1\-Shift\-,
+.B Super\-Shift\-,
 Send focused window to previous screen, if any.
 .TP
-.B Mod1\-Shift\-.
+.B Super\-Shift\-.
 Send focused window to next screen, if any.
 .TP
-.B Mod1\-b
+.B Super\-b
 Toggles bar on and off.
 .TP
-.B Mod1\-t
+.B Super\-t
 Sets tiled layout.
 .TP
-.B Mod1\-f
+.B Super\-f
 Sets floating layout.
 .TP
-.B Mod1\-m
+.B Super\-m
 Sets monocle layout.
 .TP
-.B Mod1\-space
+.B Super\-space
 Toggles between current and previous layout.
 .TP
-.B Mod1\-j
+.B Super\-j
 Focus next window.
 .TP
-.B Mod1\-k
+.B Super\-k
 Focus previous window.
 .TP
-.B Mod1\-i
+.B Super\-i
 Increase number of windows in master area.
 .TP
-.B Mod1\-d
+.B Super\-d
 Decrease number of windows in master area.
 .TP
-.B Mod1\-l
+.B Super\-l
 Increase master area size.
 .TP
-.B Mod1\-h
+.B Super\-h
 Decrease master area size.
 .TP
-.B Mod1\-Return
+.B Super\-Return
 Zooms/cycles focused window to/from master area (tiled layouts only).
 .TP
-.B Mod1\-Shift\-c
+.B Super\-Shift\-c
 Close focused window.
 .TP
-.B Mod1\-Shift\-space
+.B Super\-Shift\-space
 Toggle focused window between tiled and floating state.
 .TP
-.B Mod1\-Tab
+.B Super\-Tab
 Toggles to the previously selected tags.
 .TP
-.B Mod1\-Shift\-[1..n]
+.B Super\-Shift\-[1..n]
 Apply nth tag to focused window.
 .TP
-.B Mod1\-Shift\-0
+.B Super\-Shift\-0
 Apply all tags to focused window.
 .TP
-.B Mod1\-Control\-Shift\-[1..n]
+.B Super\-Control\-Shift\-[1..n]
 Add/remove nth tag to/from focused window.
 .TP
-.B Mod1\-[1..n]
+.B Super\-[1..n]
 View all windows with nth tag.
 .TP
-.B Mod1\-0
+.B Super\-0
 View all windows with any tag.
 .TP
-.B Mod1\-Control\-[1..n]
+.B Super\-Control\-[1..n]
 Add/remove all windows with nth tag to/from the view.
 .TP
-.B Mod1\-Shift\-q
+.B Super\-Shift\-q
 Quit dwm.
 .SS Mouse commands
 .TP
-.B Mod1\-Button1
+.B Super\-Button1
 Move focused window while dragging. Tiled windows will be toggled to the floating state.
 .TP
-.B Mod1\-Button2
+.B Super\-Button2
 Toggles focused window between floating and tiled state.
 .TP
-.B Mod1\-Button3
+.B Super\-Button3
 Resize focused window while dragging. Tiled windows will be toggled to the floating state.
 .SH CUSTOMIZATION
 dwm is customized by creating a custom config.h and (re)compiling the source
diff --git a/dwm.c b/dwm.c
index 4465af1..04e34ce 100644 (file)
--- a/dwm.c
+++ b/dwm.c
 #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
 #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
 
+#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,
        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 */
@@ -88,6 +106,7 @@ struct Client {
        char name[256];
        float mina, maxa;
        int x, y, w, h;
+       int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
        int oldx, oldy, oldw, oldh;
        int basew, baseh, incw, inch, maxw, maxh, minw, minh;
        int bw, oldbw;
@@ -111,6 +130,7 @@ typedef struct {
        void (*arrange)(Monitor *);
 } Layout;
 
+typedef struct Pertag Pertag;
 struct Monitor {
        char ltsymbol[16];
        float mfact;
@@ -130,6 +150,7 @@ struct Monitor {
        Monitor *next;
        Window barwin;
        const Layout *lt[2];
+       Pertag *pertag;
 };
 
 typedef struct {
@@ -141,6 +162,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);
@@ -169,8 +196,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);
@@ -188,13 +217,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);
@@ -206,6 +238,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 *);
@@ -223,18 +256,23 @@ static int updategeom(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 updatetitle(Client *c);
 static void updatewindowtype(Client *c);
 static void updatewmhints(Client *c);
 static void view(const Arg *arg);
 static Client *wintoclient(Window w);
 static Monitor *wintomon(Window w);
+static Client *wintosystrayicon(Window w);
 static int xerror(Display *dpy, XErrorEvent *ee);
 static int xerrordummy(Display *dpy, XErrorEvent *ee);
 static int xerrorstart(Display *dpy, XErrorEvent *ee);
 static void zoom(const Arg *arg);
 
 /* variables */
+static Systray *systray =  NULL;
 static const char broken[] = "broken";
 static char stext[256];
 static int screen;
@@ -257,9 +295,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 Clr **scheme;
@@ -271,6 +310,15 @@ static Window root, wmcheckwin;
 /* configuration, allows nested code to access above variables */
 #include "config.h"
 
+struct Pertag {
+       unsigned int curtag, prevtag; /* current and previous tag */
+       int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+       float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+       unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+       const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes  */
+       int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+};
+
 /* compile-time check if all tags fit into an unsigned int bit array. */
 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
 
@@ -482,6 +530,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++)
@@ -512,9 +565,52 @@ cleanupmon(Monitor *mon)
 void
 clientmessage(XEvent *e)
 {
+       XWindowAttributes wa;
+       XSetWindowAttributes swa;
        XClientMessageEvent *cme = &e->xclient;
        Client *c = wintoclient(cme->window);
 
+       if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
+               /* add systray icons */
+               if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+                       if (!(c = (Client *)calloc(1, sizeof(Client))))
+                               die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+                       if (!(c->win = cme->data.l[2])) {
+                               free(c);
+                               return;
+                       }
+                       c->mon = selmon;
+                       c->next = systray->icons;
+                       systray->icons = c;
+                       XGetWindowAttributes(dpy, c->win, &wa);
+                       c->x = c->oldx = c->y = c->oldy = 0;
+                       c->w = c->oldw = wa.width;
+                       c->h = c->oldh = wa.height;
+                       c->oldbw = wa.border_width;
+                       c->bw = 0;
+                       c->isfloating = True;
+                       /* reuse tags field as mapped status */
+                       c->tags = 1;
+                       updatesizehints(c);
+                       updatesystrayicongeom(c, wa.width, wa.height);
+                       XAddToSaveSet(dpy, c->win);
+                       XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
+                       XReparentWindow(dpy, c->win, systray->win, 0, 0);
+                       /* use parents background color */
+                       swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+                       XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       /* FIXME not sure if I have to send these events, too */
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       XSync(dpy, False);
+                       resizebarwin(selmon);
+                       updatesystray();
+                       setclientstate(c, NormalState);
+               }
+               return;
+       }
        if (!c)
                return;
        if (cme->message_type == netatom[NetWMState]) {
@@ -567,7 +663,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);
@@ -631,6 +727,7 @@ Monitor *
 createmon(void)
 {
        Monitor *m;
+       unsigned int i;
 
        m = ecalloc(1, sizeof(Monitor));
        m->tagset[0] = m->tagset[1] = 1;
@@ -641,6 +738,20 @@ createmon(void)
        m->lt[0] = &layouts[0];
        m->lt[1] = &layouts[1 % LENGTH(layouts)];
        strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+       m->pertag = ecalloc(1, sizeof(Pertag));
+       m->pertag->curtag = m->pertag->prevtag = 1;
+
+       for (i = 0; i <= LENGTH(tags); i++) {
+               m->pertag->nmasters[i] = m->nmaster;
+               m->pertag->mfacts[i] = m->mfact;
+
+               m->pertag->ltidxs[i][0] = m->lt[0];
+               m->pertag->ltidxs[i][1] = m->lt[1];
+               m->pertag->sellts[i] = m->sellt;
+
+               m->pertag->showbars[i] = m->showbar;
+       }
+
        return m;
 }
 
@@ -652,6 +763,11 @@ destroynotify(XEvent *e)
 
        if ((c = wintoclient(ev->window)))
                unmanage(c, 1);
+       else if ((c = wintosystrayicon(ev->window))) {
+               removesystrayicon(c);
+               resizebarwin(selmon);
+               updatesystray();
+       }
 }
 
 void
@@ -695,19 +811,23 @@ dirtomon(int dir)
 void
 drawbar(Monitor *m)
 {
-       int x, w, sw = 0;
+       int x, w, sw = 0, stw = 0;
        int boxs = drw->fonts->h / 9;
        int boxw = drw->fonts->h / 6 + 2;
        unsigned int i, occ = 0, urg = 0;
        Client *c;
 
+       if(showsystray && m == systraytomon(m))
+               stw = getsystraywidth();
+
        /* draw status first so it can be overdrawn by tags later */
-       if (m == selmon) { /* status is only drawn on selected monitor */
+       if (m == selmon || 1) { /* status is only drawn on selected monitor */
                drw_setscheme(drw, scheme[SchemeNorm]);
-               sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
-               drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0);
+               sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
+               drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
        }
 
+       resizebarwin(m);
        for (c = m->clients; c; c = c->next) {
                occ |= c->tags;
                if (c->isurgent)
@@ -728,7 +848,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);
@@ -739,7 +859,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
@@ -776,8 +896,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 +985,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 +1029,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)
 {
@@ -966,7 +1106,7 @@ grabkeys(void)
 void
 incnmaster(const Arg *arg)
 {
-       selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+       selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
        arrange(selmon);
 }
 
@@ -1003,7 +1143,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);
@@ -1056,6 +1196,10 @@ manage(Window w, XWindowAttributes *wa)
        updatewindowtype(c);
        updatesizehints(c);
        updatewmhints(c);
+       c->sfx = c->x;
+       c->sfy = c->y;
+       c->sfw = c->w;
+       c->sfh = c->h;
        XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
        grabbuttons(c, 0);
        if (!c->isfloating)
@@ -1091,6 +1235,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;
@@ -1110,7 +1260,7 @@ monocle(Monitor *m)
                if (ISVISIBLE(c))
                        n++;
        if (n > 0) /* override layout symbol */
-               snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
+               snprintf(m->ltsymbol, sizeof m->ltsymbol, "%s/%d", layouts[2].symbol, n);
        for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
                resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
 }
@@ -1215,6 +1365,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)
@@ -1265,6 +1425,20 @@ recttomon(int x, int y, int w, int h)
        return r;
 }
 
+void
+removesystrayicon(Client *i)
+{
+       Client **ii;
+
+       if (!showsystray || !i)
+               return;
+       for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
+       if (ii)
+               *ii = i->next;
+       free(i);
+}
+
+
 void
 resize(Client *c, int x, int y, int w, int h, int interact)
 {
@@ -1272,6 +1446,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
                resizeclient(c, x, y, w, h);
 }
 
+void
+resizebarwin(Monitor *m) {
+       unsigned int w = m->ww;
+       if (showsystray && m == systraytomon(m))
+               w -= getsystraywidth();
+       XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
+}
+
 void
 resizeclient(Client *c, int x, int y, int w, int h)
 {
@@ -1282,6 +1464,13 @@ resizeclient(Client *c, int x, int y, int w, int h)
        c->oldw = c->w; c->w = wc.width = w;
        c->oldh = c->h; c->h = wc.height = h;
        wc.border_width = c->bw;
+       if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
+           || &monocle == c->mon->lt[c->mon->sellt]->arrange)
+           && !c->isfullscreen) {
+               c->w = wc.width += c->bw * 2;
+               c->h = wc.height += c->bw * 2;
+               wc.border_width = 0;
+       }
        XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
        configure(c);
        XSync(dpy, False);
@@ -1344,6 +1533,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)
 {
@@ -1433,26 +1635,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;
 }
@@ -1466,7 +1678,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
@@ -1501,9 +1713,9 @@ void
 setlayout(const Arg *arg)
 {
        if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
-               selmon->sellt ^= 1;
+               selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
        if (arg && arg->v)
-               selmon->lt[selmon->sellt] = (Layout *)arg->v;
+               selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
        strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
        if (selmon->sel)
                arrange(selmon);
@@ -1522,7 +1734,7 @@ setmfact(const Arg *arg)
        f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
        if (f < 0.1 || f > 0.9)
                return;
-       selmon->mfact = f;
+       selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
        arrange(selmon);
 }
 
@@ -1555,6 +1767,10 @@ 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[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
@@ -1562,6 +1778,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);
@@ -1570,6 +1789,8 @@ setup(void)
        scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
        for (i = 0; i < LENGTH(colors); i++)
                scheme[i] = drw_scm_create(drw, colors[i], 3);
+       /* init system tray */
+       updatesystray();
        /* init bars */
        updatebars();
        updatestatus();
@@ -1671,37 +1892,50 @@ tagmon(const Arg *arg)
 }
 
 void
-tile(Monitor *m)
-{
-       unsigned int i, n, h, mw, my, ty;
+tile(Monitor *m) {
+       unsigned int i, n, h, r, g = 0, mw, my, ty;
        Client *c;
 
        for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
        if (n == 0)
                return;
 
-       if (n > m->nmaster)
-               mw = m->nmaster ? m->ww * m->mfact : 0;
+       if(n > m->nmaster)
+               mw = m->nmaster ? (m->ww - (g = gappx)) * m->mfact : 0;
        else
                mw = m->ww;
-       for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
-               if (i < m->nmaster) {
-                       h = (m->wh - my) / (MIN(n, m->nmaster) - i);
-                       resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
-                       my += HEIGHT(c);
-               } else {
-                       h = (m->wh - ty) / (n - i);
-                       resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
-                       ty += HEIGHT(c);
+       for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+               if(i < m->nmaster) {
+                       r = MIN(n, m->nmaster) - i;
+                       h = (m->wh - my - gappx * (r - 1)) / r;
+                       resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
+                       my += HEIGHT(c) + gappx;
+               }
+               else {
+                       r = n - i;
+                       h = (m->wh - ty - gappx * (r - 1)) / r;
+                       resize(c, m->wx + mw + g, m->wy + ty, m->ww - mw - g - (2*c->bw), h - (2*c->bw), False);
+                       ty += HEIGHT(c) + gappx;
                }
 }
 
 void
 togglebar(const Arg *arg)
 {
-       selmon->showbar = !selmon->showbar;
+       selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !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);
 }
 
@@ -1714,8 +1948,16 @@ togglefloating(const Arg *arg)
                return;
        selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
        if (selmon->sel->isfloating)
-               resize(selmon->sel, selmon->sel->x, selmon->sel->y,
-                       selmon->sel->w, selmon->sel->h, 0);
+               /* restore last known float dimensions */
+               resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy,
+                      selmon->sel->sfw, selmon->sel->sfh, False);
+       else {
+               /* save last known float dimensions */
+               selmon->sel->sfx = selmon->sel->x;
+               selmon->sel->sfy = selmon->sel->y;
+               selmon->sel->sfw = selmon->sel->w;
+               selmon->sel->sfh = selmon->sel->h;
+       }
        arrange(selmon);
 }
 
@@ -1738,9 +1980,33 @@ void
 toggleview(const Arg *arg)
 {
        unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+       int i;
 
        if (newtagset) {
                selmon->tagset[selmon->seltags] = newtagset;
+
+               if (newtagset == ~0) {
+                       selmon->pertag->prevtag = selmon->pertag->curtag;
+                       selmon->pertag->curtag = 0;
+               }
+
+               /* test if the user did not select the same tag */
+               if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+                       selmon->pertag->prevtag = selmon->pertag->curtag;
+                       for (i = 0; !(newtagset & 1 << i); i++) ;
+                       selmon->pertag->curtag = i + 1;
+               }
+
+               /* apply settings for this view */
+               selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+               selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+               selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+               selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+               selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+               if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+                       togglebar(NULL);
+
                focus(NULL);
                arrange(selmon);
        }
@@ -1796,11 +2062,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,
@@ -1811,10 +2084,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);
                XSetClassHint(dpy, m->barwin, &ch);
        }
@@ -1987,9 +2265,125 @@ updatesizehints(Client *c)
 void
 updatestatus(void)
 {
+       Monitor* m;
        if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
                strcpy(stext, "dwm-"VERSION);
-       drawbar(selmon);
+       for(m = mons; m; m = m->next)
+               drawbar(m);
+}
+
+void
+updatesystrayicongeom(Client *i, int w, int h)
+{
+       if (i) {
+               i->h = bh;
+               if (w == h)
+                       i->w = bh;
+               else if (h == bh)
+                       i->w = w;
+               else
+                       i->w = (int) ((float)bh * ((float)w / (float)h));
+               applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
+               /* force icons into the systray dimenons if they don't want to */
+               if (i->h > bh) {
+                       if (i->w == i->h)
+                               i->w = bh;
+                       else
+                               i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
+                       i->h = bh;
+               }
+       }
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+       long flags;
+       int code = 0;
+
+       if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
+                       !(flags = getatomprop(i, xatom[XembedInfo])))
+               return;
+
+       if (flags & XEMBED_MAPPED && !i->tags) {
+               i->tags = 1;
+               code = XEMBED_WINDOW_ACTIVATE;
+               XMapRaised(dpy, i->win);
+               setclientstate(i, NormalState);
+       }
+       else if (!(flags & XEMBED_MAPPED) && i->tags) {
+               i->tags = 0;
+               code = XEMBED_WINDOW_DEACTIVATE;
+               XUnmapWindow(dpy, i->win);
+               setclientstate(i, WithdrawnState);
+       }
+       else
+               return;
+       sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+                       systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+void
+updatesystray(void)
+{
+       XSetWindowAttributes wa;
+       XWindowChanges wc;
+       Client *i;
+       Monitor *m = systraytomon(NULL);
+       unsigned int x = m->mx + m->mw;
+       unsigned int w = 1;
+
+       if (!showsystray)
+               return;
+       if (!systray) {
+               /* init systray */
+               if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
+                       die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
+               systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
+               wa.event_mask        = ButtonPressMask | ExposureMask;
+               wa.override_redirect = True;
+               wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+               XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+               XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+                               PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
+               XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
+               XMapRaised(dpy, systray->win);
+               XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
+               if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
+                       sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
+                       XSync(dpy, False);
+               }
+               else {
+                       fprintf(stderr, "dwm: unable to obtain system tray.\n");
+                       free(systray);
+                       systray = NULL;
+                       return;
+               }
+       }
+       for (w = 0, i = systray->icons; i; i = i->next) {
+               /* make sure the background color stays the same */
+               wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+               XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
+               XMapRaised(dpy, i->win);
+               w += systrayspacing;
+               i->x = w;
+               XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
+               w += i->w;
+               if (i->mon != m)
+                       i->mon = m;
+       }
+       w = w ? w + systrayspacing : 1;
+       x -= w;
+       XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
+       wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
+       wc.stack_mode = Above; wc.sibling = m->barwin;
+       XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
+       XMapWindow(dpy, systray->win);
+       XMapSubwindows(dpy, systray->win);
+       /* redraw background */
+       XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
+       XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
+       XSync(dpy, False);
 }
 
 void
@@ -2035,11 +2429,37 @@ updatewmhints(Client *c)
 void
 view(const Arg *arg)
 {
+       int i;
+       unsigned int tmptag;
+
        if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
                return;
        selmon->seltags ^= 1; /* toggle sel tagset */
-       if (arg->ui & TAGMASK)
+       if (arg->ui & TAGMASK) {
                selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+               selmon->pertag->prevtag = selmon->pertag->curtag;
+
+               if (arg->ui == ~0)
+                       selmon->pertag->curtag = 0;
+               else {
+                       for (i = 0; !(arg->ui & 1 << i); i++) ;
+                       selmon->pertag->curtag = i + 1;
+               }
+       } else {
+               tmptag = selmon->pertag->prevtag;
+               selmon->pertag->prevtag = selmon->pertag->curtag;
+               selmon->pertag->curtag = tmptag;
+       }
+
+       selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+       selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+       selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+       selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+       selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+       if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+               togglebar(NULL);
+
        focus(NULL);
        arrange(selmon);
 }
@@ -2057,6 +2477,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)
 {
@@ -2110,6 +2540,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)
 {