summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--x11-wm/dwm/Manifest1
-rw-r--r--x11-wm/dwm/dwm-6.0-r1.ebuild84
-rw-r--r--x11-wm/dwm/files/dwm-6.0-userscripts.patch2071
-rw-r--r--x11-wm/dwm/files/dwm-session211
-rw-r--r--x11-wm/dwm/files/dwm.desktop8
-rw-r--r--x11-wm/dwm/metadata.xml14
6 files changed, 2189 insertions, 0 deletions
diff --git a/x11-wm/dwm/Manifest b/x11-wm/dwm/Manifest
new file mode 100644
index 0000000..228e278
--- /dev/null
+++ b/x11-wm/dwm/Manifest
@@ -0,0 +1 @@
+DIST dwm-6.0.tar.gz 20810 SHA256 b2b9483de69259eeea56844899bb2385158d3e79a42d82b10c142099fc8eeb56 SHA512 895d1d363b3756c9ba19dbf06af34be753c1ae5971d540113d7f8901ad174c2e5944ef769b43e65f7b700f34832bb24082bc91d999b287610c9925182ce70c00 WHIRLPOOL bac35d2cb41df313bda2dfd2ca5b12467ec22e41c1640d8d65e67f1e7231baffc96151de03e18d8823918ddd2bdf905a6e0d984592da5cd525e87fb638f0b3dd
diff --git a/x11-wm/dwm/dwm-6.0-r1.ebuild b/x11-wm/dwm/dwm-6.0-r1.ebuild
new file mode 100644
index 0000000..031c5d9
--- /dev/null
+++ b/x11-wm/dwm/dwm-6.0-r1.ebuild
@@ -0,0 +1,84 @@
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/x11-wm/dwm/dwm-6.0.ebuild,v 1.12 2013/02/06 15:19:31 jer Exp $
+
+EAPI="4"
+
+inherit eutils savedconfig toolchain-funcs autotools
+
+DESCRIPTION="a dynamic window manager for X11"
+HOMEPAGE="http://dwm.suckless.org/"
+SRC_URI="http://dl.suckless.org/${PN}/${P}.tar.gz"
+
+LICENSE="MIT"
+SLOT="0"
+KEYWORDS="amd64 ppc ppc64 x86 ~x86-fbsd"
+IUSE="xinerama +userscripts"
+
+DEPEND="x11-libs/libX11
+ xinerama? (
+ x11-proto/xineramaproto
+ x11-libs/libXinerama
+ )"
+RDEPEND="${DEPEND}"
+
+src_prepare() {
+
+ # User Scripts taken from: https://bitbucket.org/jceb81/dwm-patches
+ if use userscripts; then
+ epatch "${FILESDIR}/${P}-userscripts.patch"
+ fi
+
+ sed -i \
+ -e "s/CFLAGS = -std=c99 -pedantic -Wall -Os/CFLAGS += -std=c99 -pedantic -Wall/" \
+ -e "/^LDFLAGS/{s|=|+=|g;s|-s ||g}" \
+ -e "s/#XINERAMALIBS =/XINERAMALIBS ?=/" \
+ -e "s/#XINERAMAFLAGS =/XINERAMAFLAGS ?=/" \
+ -e "s@/usr/X11R6/include@${EPREFIX}/usr/include/X11@" \
+ -e "s@/usr/X11R6/lib@${EPREFIX}/usr/lib@" \
+ -e "s@-I/usr/include@@" -e "s@-L/usr/lib@@" \
+ config.mk || die
+ sed -i \
+ -e '/@echo CC/d' \
+ -e 's|@${CC}|$(CC)|g' \
+ Makefile || die
+
+ restore_config config.h
+ epatch_user
+}
+
+src_compile() {
+ if use xinerama; then
+ emake CC=$(tc-getCC) dwm
+ else
+ emake CC=$(tc-getCC) XINERAMAFLAGS="" XINERAMALIBS="" dwm
+ fi
+}
+
+src_install() {
+ emake DESTDIR="${D}" PREFIX="${EPREFIX}/usr" install
+
+ exeinto /etc/X11/Sessions
+ newexe "${FILESDIR}"/dwm-session2 dwm
+
+ insinto /usr/share/xsessions
+ doins "${FILESDIR}"/dwm.desktop
+
+ dodoc README
+
+ save_config config.h
+}
+
+pkg_postinst() {
+ einfo "This ebuild has support for user defined configs"
+ einfo "Please read this ebuild for more details and re-emerge as needed"
+ einfo "if you want to add or remove functionality for ${PN}"
+ if ! has_version x11-misc/dmenu; then
+ elog "Installing ${PN} without x11-misc/dmenu"
+ einfo "To have a menu you can install x11-misc/dmenu"
+ fi
+ einfo "You can custom status bar with a script in HOME/.dwm/dwmrc"
+ einfo "the ouput is redirected to the standard input of dwm"
+ einfo "Since dwm-5.4, status info in the bar must be set like this:"
+ einfo "xsetroot -name \"\`date\` \`uptime | sed 's/.*,//'\`\""
+}
diff --git a/x11-wm/dwm/files/dwm-6.0-userscripts.patch b/x11-wm/dwm/files/dwm-6.0-userscripts.patch
new file mode 100644
index 0000000..d22277f
--- /dev/null
+++ b/x11-wm/dwm/files/dwm-6.0-userscripts.patch
@@ -0,0 +1,2071 @@
+From: Elijah El Lazkani <ThyArmageddon+Gentoo@Gmail.com>
+Date: Thu Marh 28 21:00:00 UTC 2013
+Subject: Patching DWM adding userscripts to it from: https://bitbucket.org/jceb81/dwm-patches
+
+
+--- config.def.h
++++ config.def.h
+@@ -1,15 +1,19 @@
+ /* See LICENSE file for copyright and license details. */
+
+ /* appearance */
+-static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
++static const char font[] = "-misc-fixed-medium-r-semicondensed-*-13-120-75-75-c-60-iso10646-1";
+ static const char normbordercolor[] = "#444444";
+ static const char normbgcolor[] = "#222222";
+ static const char normfgcolor[] = "#bbbbbb";
+-static const char selbordercolor[] = "#005577";
++static const char selbordercolor[] = "#ff0000";
+ static const char selbgcolor[] = "#005577";
+ static const char selfgcolor[] = "#eeeeee";
++static const char floatnormbordercolor[] = "#885599";
++static const char floatselbordercolor[] = "#ff0000";
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
++static const unsigned int systrayspacing = 2; /* systray spacing */
++static const Bool showsystray = True; /* False means no systray */
+ static const Bool showbar = True; /* False means no bar */
+ static const Bool topbar = True; /* False means bottom bar */
+
+@@ -17,13 +21,20 @@ static const Bool topbar = Tr
+ 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, True, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, False, -1 },
++ { "Pidgin", NULL, NULL, 0, True, -1 },
++ { "Skype", NULL, NULL, 0, True, -1 },
++ { "Kio_uiserver", NULL, NULL, 0, True, -1 },
+ };
+
+ /* layout(s) */
+-static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
++static const float mfact = 0.65; /* factor of master area size [0.05..0.95] */
+ static const int nmaster = 1; /* number of clients in master area */
+ static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
+
+@@ -35,7 +46,7 @@ static const Layout layouts[] = {
+ };
+
+ /* key definitions */
+-#define MODKEY Mod1Mask
++#define MODKEY Mod4Mask
+ #define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+@@ -47,8 +58,14 @@ static const Layout layouts[] = {
+
+ /* commands */
+ static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
+-static const char *termcmd[] = { "uxterm", NULL };
++static const char *termcmd[] = { "x-terminal-emulator", NULL };
+
++#include "moveresize.c"
++#include "tagall.c"
++#include "maximize.c"
++#include "push.c"
++#include "focusmaster.c"
++#include "shifttags.c"
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+@@ -56,11 +73,14 @@ static Key keys[] = {
+ { MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
++ { MODKEY|ShiftMask, XK_j, pushdown, {0} },
++ { MODKEY|ShiftMask, XK_k, pushup, {0} },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+- { MODKEY, XK_d, incnmaster, {.i = -1 } },
++ { MODKEY, XK_o, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
++ { Mod1Mask, XK_Tab, swapfocus, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+@@ -83,7 +103,37 @@ static Key keys[] = {
+ TAGKEYS( XK_7, 6)
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
++ { MODKEY, XK_q, quit, {1} },
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY|ControlMask, XK_l, togglehorizontalmax, {0} },
++ { MODKEY|ControlMask, XK_h, togglehorizontalmax, {0} },
++ { MODKEY|ControlMask, XK_j, toggleverticalmax, {0} },
++ { MODKEY|ControlMask, XK_k, toggleverticalmax, {0} },
++ { MODKEY|ControlMask, XK_m, togglemaximize, {0} },
++ { MODKEY|ShiftMask, XK_F1, tagall, {.v = "F1" } },
++ { MODKEY|ShiftMask, XK_F2, tagall, {.v = "F2" } },
++ { MODKEY|ShiftMask, XK_F3, tagall, {.v = "F3" } },
++ { MODKEY|ShiftMask, XK_F4, tagall, {.v = "F4" } },
++ { MODKEY|ShiftMask, XK_F5, tagall, {.v = "F5" } },
++ { MODKEY|ShiftMask, XK_F6, tagall, {.v = "F6" } },
++ { MODKEY|ShiftMask, XK_F7, tagall, {.v = "F7" } },
++ { MODKEY|ShiftMask, XK_F8, tagall, {.v = "F8" } },
++ { MODKEY|ShiftMask, XK_F9, tagall, {.v = "F9" } },
++ { MODKEY, XK_a, moveresize, {.v = "-10x 0y 0w 0h" } },
++ { MODKEY, XK_d, moveresize, {.v = "10x 0y 0w 0h" } },
++ { MODKEY, XK_s, moveresize, {.v = "0x 10y 0w 0h" } },
++ { MODKEY, XK_w, moveresize, {.v = "0x -10y 0w 0h" } },
++ { MODKEY|ControlMask, XK_a, moveresize, {.v = "0X 0y 0w 0h" } },
++ { MODKEY|ControlMask, XK_d, moveresize, {.v = "9000X 0y 0w 0h" } },
++ { MODKEY|ControlMask, XK_s, moveresize, {.v = "0x 9000Y 0w 0h" } },
++ { MODKEY|ControlMask, XK_w, moveresize, {.v = "0x 15Y 0w 0h" } },
++ { MODKEY|ShiftMask, XK_a, moveresize, {.v = "0x 0y -10w 0h" } },
++ { MODKEY|ShiftMask, XK_d, moveresize, {.v = "0x 0y 10w 0h" } },
++ { MODKEY|ShiftMask, XK_s, moveresize, {.v = "0x 0y 0w 10h" } },
++ { MODKEY|ShiftMask, XK_w, moveresize, {.v = "0x 0y 0w -10h" } },
++ { MODKEY|ControlMask, XK_Return, focusmaster, {0} },
++ { MODKEY, XK_Left, shifttags, {.i = -1} },
++ { MODKEY, XK_Right, shifttags, {.i = +1} },
+ };
+
+ /* button definitions */
+
+--- config.mk
++++ config.mk
+@@ -10,20 +10,19 @@ MANPREFIX = ${PREFIX}/share/man
+ X11INC = /usr/X11R6/include
+ X11LIB = /usr/X11R6/lib
+
+-# Xinerama
+-XINERAMALIBS = -L${X11LIB} -lXinerama
++# Xinerama, comment if you don't want it
++XINERAMALIBS = -lXinerama
+ XINERAMAFLAGS = -DXINERAMA
+
+ # includes and libs
+-INCS = -I. -I/usr/include -I${X11INC}
+-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS}
++INCS = -I${X11INC}
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS}
+
+ # flags
+-CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+-#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
+-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+-#LDFLAGS = -g ${LIBS}
+-LDFLAGS = -s ${LIBS}
++CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
++#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
++CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
++LDFLAGS = -s ${LIBS}
+
+ # Solaris
+ #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+
+--- dwm.c
++++ dwm.c
+@@ -36,6 +36,7 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xproto.h>
+ #include <X11/Xutil.h>
++#include <X11/XKBlib.h>
+ #ifdef XINERAMA
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+@@ -45,7 +46,7 @@
+ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+-#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
++#define ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+ #define MAX(A, B) ((A) > (B) ? (A) : (B))
+ #define MIN(A, B) ((A) < (B) ? (A) : (B))
+@@ -55,12 +56,30 @@
+ #define TAGMASK ((1 << LENGTH(tags)) - 1)
+ #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height)
+
++#define SYSTEM_TRAY_REQUEST_DOCK 0
++#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 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 { ColBorder, ColFG, ColBG, ColLast }; /* color */
+-enum { NetSupported, NetWMName, NetWMState,
+- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+- NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
++enum { ColBorder, ColFG, ColBG, ColBorderFloat, ColLast }; /* color */
++enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
++ NetWMName, NetWMState, 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 */
+@@ -86,11 +105,12 @@ 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;
+ unsigned int tags;
+- Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ Bool ismax, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -124,6 +144,8 @@ typedef struct {
+ void (*arrange)(Monitor *);
+ } Layout;
+
++typedef struct Pertag Pertag;
++typedef struct Clientlist Clientlist;
+ struct Monitor {
+ char ltsymbol[16];
+ float mfact;
+@@ -137,12 +159,12 @@ struct Monitor {
+ unsigned int tagset[2];
+ Bool showbar;
+ Bool topbar;
+- Client *clients;
++ Clientlist *cl;
+ Client *sel;
+- Client *stack;
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ Pertag *pertag;
+ };
+
+ typedef struct {
+@@ -154,12 +176,25 @@ typedef struct {
+ int monitor;
+ } Rule;
+
++typedef struct Systray Systray;
++struct Systray {
++ Window win;
++ Client *icons;
++};
++
++struct Clientlist {
++ Client *clients;
++ Client *stack;
++};
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
+ static void arrange(Monitor *m);
+ static void arrangemon(Monitor *m);
+ static void attach(Client *c);
++static void attachabove(Client *c);
++static void attachclients(Monitor *m);
+ static void attachstack(Client *c);
+ static void buttonpress(XEvent *e);
+ static void checkotherwm(void);
+@@ -186,9 +221,11 @@ 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 unsigned long getcolor(const char *colstr);
+ static Bool getrootptr(int *x, int *y);
+ static long getstate(Window w);
++static unsigned int getsystraywidth();
+ static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
+ static void grabbuttons(Client *c, Bool focused);
+ static void grabkeys(void);
+@@ -202,18 +239,21 @@ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
+-static Client *nexttiled(Client *c);
++static Client *nexttiled(Client *c, Monitor *m);
+ 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, Bool 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 Bool sendevent(Client *c, Atom proto);
++static Bool 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);
+@@ -224,6 +264,7 @@ static void setup(void);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static void swapfocus();
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static int textnw(const char *text, unsigned int len);
+@@ -238,21 +279,30 @@ static void unmapnotify(XEvent *e);
+ static Bool updategeom(void);
+ static void updatebarpos(Monitor *m);
+ static void updatebars(void);
++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 unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
++static Client *prevclient = NULL;
++static Client *prevzoom = NULL;
+ static const char broken[] = "broken";
+ static char stext[256];
+ static int screen;
+@@ -274,19 +324,31 @@ static void (*handler[LASTEvent]) (XEven
+ [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 Bool running = True;
++static Bool restart = False;
+ static Cursor cursor[CurLast];
+ static Display *dpy;
+ static DC dc;
+ static Monitor *mons = NULL, *selmon = NULL;
+ static Window root;
++static Clientlist *cl;
+
+ /* 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 */
++ Bool 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]; };
+
+@@ -313,7 +375,7 @@ applyrules(Client *c) {
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
+- for(m = mons; m && m->num != r->monitor; m = m->next);
++ for(m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ;
+ if(m)
+ c->mon = m;
+ }
+@@ -394,12 +456,13 @@ applysizehints(Client *c, int *x, int *y
+ void
+ arrange(Monitor *m) {
+ if(m)
+- showhide(m->stack);
++ showhide(m->cl->stack);
+ else for(m = mons; m; m = m->next)
+- showhide(m->stack);
+- if(m)
++ showhide(m->cl->stack);
++ if(m) {
+ arrangemon(m);
+- else for(m = mons; m; m = m->next)
++ restack(m);
++ } else for(m = mons; m; m = m->next)
+ arrangemon(m);
+ }
+
+@@ -408,19 +471,64 @@ arrangemon(Monitor *m) {
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
+ if(m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+- restack(m);
+ }
+
+ void
+ attach(Client *c) {
+- c->next = c->mon->clients;
+- c->mon->clients = c;
++ c->next = c->mon->cl->clients;
++ c->mon->cl->clients = c;
++}
++
++void
++attachabove(Client *c) {
++ if(c->mon->sel == NULL || c->mon->sel == c->mon->cl->clients || c->mon->sel->isfloating) {
++ attach(c);
++ return;
++ }
++
++ Client *at;
++ for(at = c->mon->cl->clients; at->next != c->mon->sel; at = at->next);
++ c->next = at->next;
++ at->next = c;
++}
++
++void
++attachclients(Monitor *m) {
++ /* attach clients to the specified monitor */
++ Monitor *tm;
++ Client *c;
++ unsigned int utags = 0;
++ Bool rmons = False;
++ if(!m)
++ return;
++
++ /* collect information about the tags in use */
++ for(tm = mons; tm; tm = tm->next)
++ if(tm != m)
++ utags |= m->tagset[m->seltags];
++
++ for(c = m->cl->clients; c; c = c->next)
++ if(ISVISIBLE(c, m)) {
++ /* if client is also visible on other tags that are displayed on
++ * other monitors, remove these tags */
++ if(c->tags & utags) {
++ c->tags = c->tags & m->tagset[m->seltags];
++ rmons = True;
++ }
++ unfocus(c, True);
++ c->mon = m;
++ }
++
++ if(rmons)
++ for(tm = mons; tm; tm = tm->next)
++ if(tm != m)
++ arrange(tm);
+ }
+
+ void
+ attachstack(Client *c) {
+- c->snext = c->mon->stack;
+- c->mon->stack = c;
++ c->snext = c->mon->cl->stack;
++ c->mon->cl->stack = c;
+ }
+
+ void
+@@ -483,8 +591,8 @@ cleanup(void) {
+ view(&a);
+ selmon->lt[selmon->sellt] = &foo;
+ for(m = mons; m; m = m->next)
+- while(m->stack)
+- unmanage(m->stack, False);
++ while(m->cl->stack)
++ unmanage(m->cl->stack, False);
+ if(dc.font.set)
+ XFreeFontSet(dpy, dc.font.set);
+ else
+@@ -497,8 +605,14 @@ cleanup(void) {
+ XFreeCursor(dpy, cursor[CurMove]);
+ while(mons)
+ cleanupmon(mons);
++ if(showsystray) {
++ XUnmapWindow(dpy, systray->win);
++ XDestroyWindow(dpy, systray->win);
++ free(systray);
++ }
+ XSync(dpy, False);
+ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+
+ void
+@@ -530,9 +644,49 @@ 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));
++ c->win = cme->data.l[2];
++ 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 pixmap */
++ swa.background_pixmap = ParentRelative;
++ swa.background_pixel = dc.norm[ColBG];
++ XChangeWindowAttributes(dpy, c->win, CWBackPixmap|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);
++ resizebarwin(selmon);
++ updatesystray();
++ setclientstate(c, NormalState);
++ }
++ return;
++ }
+ if(!c)
+ return;
+ if(cme->message_type == netatom[NetWMState]) {
+@@ -541,7 +695,7 @@ clientmessage(XEvent *e) {
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ }
+ else if(cme->message_type == netatom[NetActiveWindow]) {
+- if(!ISVISIBLE(c)) {
++ if(!ISVISIBLE(c, c->mon)) {
+ c->mon->seltags ^= 1;
+ c->mon->tagset[c->mon->seltags] = c->tags;
+ }
+@@ -573,8 +727,9 @@ configurenotify(XEvent *e) {
+ XConfigureEvent *ev = &e->xconfigure;
+ Bool dirty;
+
++ // TODO: updategeom handling sucks, needs to be simplified
+ if(ev->window == root) {
+- dirty = (sw != ev->width);
++ dirty = (sw != ev->width || sh != ev->height);
+ sw = ev->width;
+ sh = ev->height;
+ if(updategeom() || dirty) {
+@@ -583,7 +738,7 @@ configurenotify(XEvent *e) {
+ dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
+ updatebars();
+ for(m = mons; m; m = m->next)
+- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
++ resizebarwin(m);
+ focus(NULL);
+ arrange(NULL);
+ }
+@@ -624,7 +779,7 @@ configurerequest(XEvent *e) {
+ c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
+ if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
+ configure(c);
+- if(ISVISIBLE(c))
++ if(ISVISIBLE(c, m))
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ }
+ else
+@@ -645,11 +800,18 @@ configurerequest(XEvent *e) {
+
+ Monitor *
+ createmon(void) {
+- Monitor *m;
++ Monitor *m, *tm;
++ int i;
+
+ if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
+- m->tagset[0] = m->tagset[1] = 1;
++ m->cl = cl;
++ /* reassing tags when creating a new monitor */
++ for(i=1, tm = mons; tm; tm = tm->next, i++) {
++ tm->seltags ^= 1;
++ tm->tagset[tm->seltags] = i;
++ }
++ m->tagset[0] = m->tagset[1] = i;
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+@@ -657,6 +819,24 @@ createmon(void) {
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
++ m->pertag->curtag = m->pertag->prevtag = 1;
++ for(i=0; i <= LENGTH(tags); i++) {
++ /* init nmaster */
++ m->pertag->nmasters[i] = m->nmaster;
++
++ /* init mfacts */
++ m->pertag->mfacts[i] = m->mfact;
++
++ /* init layouts */
++ m->pertag->ltidxs[i][0] = m->lt[0];
++ m->pertag->ltidxs[i][1] = m->lt[1];
++ m->pertag->sellts[i] = m->sellt;
++
++ /* init showbar */
++ m->pertag->showbars[i] = m->showbar;
++ }
+ return m;
+ }
+
+@@ -667,13 +847,18 @@ destroynotify(XEvent *e) {
+
+ if((c = wintoclient(ev->window)))
+ unmanage(c, True);
++ else if((c = wintosystrayicon(ev->window))) {
++ removesystrayicon(c);
++ resizebarwin(selmon);
++ updatesystray();
++ }
+ }
+
+ void
+ detach(Client *c) {
+ Client **tc;
+
+- for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
++ for(tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next);
+ *tc = c->next;
+ }
+
+@@ -681,11 +866,11 @@ void
+ detachstack(Client *c) {
+ Client **tc, *t;
+
+- for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
++ for(tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext);
+ *tc = c->snext;
+
+ if(c == c->mon->sel) {
+- for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
++ for(t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext);
+ c->mon->sel = t;
+ }
+ }
+@@ -722,7 +907,8 @@ drawbar(Monitor *m) {
+ unsigned long *col;
+ Client *c;
+
+- for(c = m->clients; c; c = c->next) {
++ resizebarwin(m);
++ for(c = m->cl->clients; c; c = c->next) {
+ occ |= c->tags;
+ if(c->isurgent)
+ urg |= c->tags;
+@@ -740,17 +926,16 @@ drawbar(Monitor *m) {
+ drawtext(m->ltsymbol, dc.norm, False);
+ dc.x += dc.w;
+ x = dc.x;
+- if(m == selmon) { /* status is only drawn on selected monitor */
+- dc.w = TEXTW(stext);
+- dc.x = m->ww - dc.w;
+- if(dc.x < x) {
+- dc.x = x;
+- dc.w = m->ww - x;
+- }
+- drawtext(stext, dc.norm, False);
++ dc.w = TEXTW(stext);
++ dc.x = m->ww - dc.w;
++ if(showsystray && m == selmon) {
++ dc.x -= getsystraywidth();
+ }
+- else
+- dc.x = m->ww;
++ if(dc.x < x) {
++ dc.x = x;
++ dc.w = m->ww - x;
++ }
++ drawtext(stext, dc.norm, False);
+ if((dc.w = dc.x - x) > bh) {
+ dc.x = x;
+ if(m->sel) {
+@@ -771,6 +956,7 @@ drawbars(void) {
+
+ for(m = mons; m; m = m->next)
+ drawbar(m);
++ updatesystray();
+ }
+
+ void
+@@ -842,8 +1028,8 @@ expose(XEvent *e) {
+
+ void
+ focus(Client *c) {
+- if(!c || !ISVISIBLE(c))
+- for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
++ if(!c || !ISVISIBLE(c, selmon))
++ for(c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext);
+ /* was if(selmon->sel) */
+ if(selmon->sel && selmon->sel != c)
+ unfocus(selmon->sel, False);
+@@ -855,11 +1041,16 @@ focus(Client *c) {
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, True);
+- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
++ if(c->isfloating)
++ XSetWindowBorder(dpy, c->win, dc.sel[ColBorderFloat]);
++ else
++ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
+ setfocus(c);
+ }
+- else
++ else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
++ }
+ selmon->sel = c;
+ drawbars();
+ }
+@@ -880,7 +1071,8 @@ focusmon(const Arg *arg) {
+ return;
+ if((m = dirtomon(arg->i)) == selmon)
+ return;
+- unfocus(selmon->sel, True);
++ unfocus(selmon->sel, False); /* s/True/False/ fixes input focus issues
++ in gedit and anjuta */
+ selmon = m;
+ focus(NULL);
+ }
+@@ -892,17 +1084,17 @@ focusstack(const Arg *arg) {
+ if(!selmon->sel)
+ return;
+ if(arg->i > 0) {
+- for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
++ for(c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next);
+ if(!c)
+- for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
++ for(c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next);
+ }
+ else {
+- for(i = selmon->clients; i != selmon->sel; i = i->next)
+- if(ISVISIBLE(i))
++ for(i = selmon->cl->clients; i != selmon->sel; i = i->next)
++ if(ISVISIBLE(i, selmon))
+ c = i;
+ if(!c)
+ for(; i; i = i->next)
+- if(ISVISIBLE(i))
++ if(ISVISIBLE(i, selmon))
+ c = i;
+ }
+ if(c) {
+@@ -917,10 +1109,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;
+@@ -962,6 +1161,15 @@ 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;
++}
++
+ Bool
+ gettextprop(Window w, Atom atom, char *text, unsigned int size) {
+ char **list = NULL;
+@@ -1028,7 +1236,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);
+ }
+
+@@ -1084,7 +1292,7 @@ keypress(XEvent *e) {
+ XKeyEvent *ev;
+
+ ev = &e->xkey;
+- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
++ keysym = XkbKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0, 0);
+ for(i = 0; i < LENGTH(keys); i++)
+ if(keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+@@ -1096,7 +1304,7 @@ void
+ 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);
+@@ -1149,14 +1357,24 @@ 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, False);
++ c->wasfloating = False;
++ c->ismax = False;
+ if(!c->isfloating)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if(c->isfloating)
+ XRaiseWindow(dpy, c->win);
+- attach(c);
++ if(c->isfloating)
++ XSetWindowBorder(dpy, w, dc.norm[ColBorderFloat]);
++ attachabove(c);
+ attachstack(c);
++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
++ (unsigned char *) &(c->win), 1);
+ XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
+ setclientstate(c, NormalState);
+ if (c->mon == selmon)
+@@ -1180,6 +1398,12 @@ void
+ 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;
+@@ -1191,16 +1415,25 @@ maprequest(XEvent *e) {
+
+ void
+ monocle(Monitor *m) {
+- unsigned int n = 0;
++ unsigned int n = 0, r = 0;
+ Client *c;
+
+- for(c = m->clients; c; c = c->next)
+- if(ISVISIBLE(c))
++ for(c = m->cl->clients; c; c = c->next)
++ if(ISVISIBLE(c, m))
+ n++;
+ if(n > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", 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, False);
++ for(c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m)) {
++ /* remove border when in monocle layout */
++ if(c->bw) {
++ c->oldbw = c->bw;
++ c->bw = 0;
++ r = 1;
++ }
++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False);
++ if(r)
++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw));
++ }
+ }
+
+ void
+@@ -1212,6 +1445,7 @@ motionnotify(XEvent *e) {
+ if(ev->window != root)
+ return;
+ if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
++ unfocus(selmon->sel, True);
+ selmon = m;
+ focus(NULL);
+ }
+@@ -1227,6 +1461,8 @@ movemouse(const Arg *arg) {
+
+ if(!(c = selmon->sel))
+ return;
++ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
++ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+@@ -1274,8 +1510,8 @@ movemouse(const Arg *arg) {
+ }
+
+ Client *
+-nexttiled(Client *c) {
+- for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
++nexttiled(Client *c, Monitor *m) {
++ for(; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
+ return c;
+ }
+
+@@ -1293,6 +1529,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)
+@@ -1325,6 +1571,8 @@ propertynotify(XEvent *e) {
+
+ void
+ quit(const Arg *arg) {
++ if(arg->i)
++ restart = True;
+ running = False;
+ }
+
+@@ -1342,12 +1590,33 @@ 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, Bool interact) {
+ if(applysizehints(c, &x, &y, &w, &h, interact))
+ resizeclient(c, x, y, w, h);
+ }
+
+ void
++resizebarwin(Monitor *m) {
++ unsigned int w = m->ww;
++ if(showsystray && m == selmon)
++ 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;
+
+@@ -1371,6 +1640,8 @@ resizemouse(const Arg *arg) {
+
+ if(!(c = selmon->sel))
+ return;
++ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
++ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+@@ -1412,6 +1683,18 @@ 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;
+ XEvent ev;
+@@ -1425,8 +1708,8 @@ restack(Monitor *m) {
+ if(m->lt[m->sellt]->arrange) {
+ wc.stack_mode = Below;
+ wc.sibling = m->barwin;
+- for(c = m->stack; c; c = c->snext)
+- if(!c->isfloating && ISVISIBLE(c)) {
++ for(c = m->cl->stack; c; c = c->snext)
++ if(!c->isfloating && ISVISIBLE(c, m)) {
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ wc.sibling = c->win;
+ }
+@@ -1476,11 +1759,9 @@ sendmon(Client *c, Monitor *m) {
+ if(c->mon == m)
+ return;
+ unfocus(c, True);
+- detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+- attach(c);
+ attachstack(c);
+ focus(NULL);
+ arrange(NULL);
+@@ -1495,34 +1776,48 @@ setclientstate(Client *c, long state) {
+ }
+
+ Bool
+-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;
+ Bool exists = False;
+ 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;
+ }
+
+ void
+ setfocus(Client *c) {
+- if(!c->neverfocus)
++ if(!c->neverfocus) {
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+- sendevent(c, wmatom[WMTakeFocus]);
++ XChangeProperty(dpy, root, netatom[NetActiveWindow],
++ XA_WINDOW, 32, PropModeReplace,
++ (unsigned char *) &(c->win), 1);
++ }
++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
+ }
+
+ void
+@@ -1555,10 +1850,13 @@ setfullscreen(Client *c, Bool fullscreen
+
+ void
+ setlayout(const Arg *arg) {
+- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+- selmon->sellt ^= 1;
++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
++ }
+ if(arg && arg->v)
+- selmon->lt[selmon->sellt] = (Layout *)arg->v;
++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
+ if(selmon->sel)
+ arrange(selmon);
+@@ -1576,7 +1874,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);
+ }
+
+@@ -1594,6 +1892,8 @@ setup(void) {
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ bh = dc.h = dc.font.height + 2;
++ if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
++ die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
+ updategeom();
+ /* init atoms */
+ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+@@ -1602,11 +1902,18 @@ 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[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] = XCreateFontCursor(dpy, XC_left_ptr);
+ cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
+@@ -1615,20 +1922,25 @@ setup(void) {
+ dc.norm[ColBorder] = getcolor(normbordercolor);
+ dc.norm[ColBG] = getcolor(normbgcolor);
+ dc.norm[ColFG] = getcolor(normfgcolor);
++ dc.norm[ColBorderFloat] = getcolor(floatnormbordercolor);
+ dc.sel[ColBorder] = getcolor(selbordercolor);
+ dc.sel[ColBG] = getcolor(selbgcolor);
+ dc.sel[ColFG] = getcolor(selfgcolor);
++ dc.sel[ColBorderFloat] = getcolor(floatselbordercolor);
+ dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
+ dc.gc = XCreateGC(dpy, root, 0, NULL);
+ XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
+ if(!dc.font.set)
+ XSetFont(dpy, dc.gc, dc.font.xfont->fid);
++ /* init system tray */
++ updatesystray();
+ /* init bars */
+ updatebars();
+ updatestatus();
+ /* EWMH support per view */
+ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) netatom, NetLast);
++ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ /* select for events */
+ wa.cursor = cursor[CurNormal];
+ wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
+@@ -1642,7 +1954,7 @@ void
+ showhide(Client *c) {
+ if(!c)
+ return;
+- if(ISVISIBLE(c)) { /* show clients top down */
++ if(ISVISIBLE(c, c->mon)) { /* show clients top down */
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
+ resize(c, c->x, c->y, c->w, c->h, False);
+@@ -1675,8 +1987,31 @@ spawn(const Arg *arg) {
+ }
+
+ void
++swapfocus(){
++ Client *c;
++ for(c = selmon->cl->clients; c && c != prevclient; c = c->next) ;
++ if(c == prevclient)
++ focus(prevclient);
++}
++
++void
+ tag(const Arg *arg) {
++ Monitor *m;
++ unsigned int newtags;
+ if(selmon->sel && arg->ui & TAGMASK) {
++ newtags = arg->ui & TAGMASK;
++ for(m = mons; m; m = m->next)
++ /* if tag is visible on another monitor, move client to the new monitor */
++ if(m != selmon && m->tagset[m->seltags] & newtags) {
++ /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */
++ if(newtags & selmon->tagset[selmon->seltags])
++ return;
++ selmon->sel->tags = newtags;
++ selmon->sel->mon = m;
++ arrange(m);
++ break;
++ }
++ /* workaround in case just one monitor is connected */
+ selmon->sel->tags = arg->ui & TAGMASK;
+ focus(NULL);
+ arrange(selmon);
+@@ -1703,10 +2038,10 @@ textnw(const char *text, unsigned int le
+
+ void
+ tile(Monitor *m) {
+- unsigned int i, n, h, mw, my, ty;
++ unsigned int i, n, h, mw, my, ty, r;
+ Client *c;
+
+- for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
++ for(n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++);
+ if(n == 0)
+ return;
+
+@@ -1714,24 +2049,54 @@ tile(Monitor *m) {
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww;
+- for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ for(i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++, r = 0) {
++ if(n == 1) {
++ if (c->bw) {
++ /* remove border when only one window is on the current tag */
++ c->oldbw = c->bw;
++ c->bw = 0;
++ r = 1;
++ }
++ }
++ else if(!c->bw && c->oldbw) {
++ /* restore border when more than one window is displayed */
++ c->bw = c->oldbw;
++ c->oldbw = 0;
++ r = 1;
++ }
+ 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), False);
++ if(r)
++ resizeclient(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw));
+ 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), False);
++ if(r)
++ resizeclient(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw));
+ ty += HEIGHT(c);
+ }
++ }
+ }
+
+ 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);
+ }
+
+@@ -1739,21 +2104,46 @@ void
+ togglefloating(const Arg *arg) {
+ if(!selmon->sel)
+ return;
++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
++ 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, False);
++ XSetWindowBorder(dpy, selmon->sel->win, dc.sel[ColBorderFloat]);
++ else
++ XSetWindowBorder(dpy, selmon->sel->win, dc.sel[ColBorder]);
++ if(selmon->sel->isfloating) {
++ /* restore border when moving window into floating mode */
++ if(!selmon->sel->bw && selmon->sel->oldbw) {
++ selmon->sel->bw = selmon->sel->oldbw;
++ selmon->sel->oldbw = 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);
+ }
+
+ void
+ toggletag(const Arg *arg) {
++ Monitor *m;
+ unsigned int newtags;
+
+ if(!selmon->sel)
+ return;
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if(newtags) {
++ /* prevent adding tags that are in use on other monitors */
++ for(m = mons; m; m = m->next)
++ if(m != selmon && newtags & m->tagset[m->seltags])
++ return;
+ selmon->sel->tags = newtags;
+ focus(NULL);
+ arrange(selmon);
+@@ -1762,10 +2152,36 @@ toggletag(const Arg *arg) {
+
+ void
+ toggleview(const Arg *arg) {
++ Monitor *m;
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
++ int i;
+
+ if(newtagset) {
++ /* prevent displaying the same tags on multiple monitors */
++ for(m = mons; m; m = m->next)
++ if(m != selmon && newtagset & m->tagset[m->seltags])
++ return;
++ 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;
++ }
+ selmon->tagset[selmon->seltags] = newtagset;
++
++ /* 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];
++ attachclients(selmon);
++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
++ togglebar(NULL);
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -1775,10 +2191,16 @@ void
+ unfocus(Client *c, Bool setfocus) {
+ if(!c)
+ return;
++ prevclient = c;
+ grabbuttons(c, False);
+- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
+- if(setfocus)
++ if(c->isfloating)
++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorderFloat]);
++ else
++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
++ if(setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
++ }
+ }
+
+ void
+@@ -1802,6 +2224,7 @@ unmanage(Client *c, Bool destroyed) {
+ }
+ free(c);
+ focus(NULL);
++ updateclientlist();
+ arrange(m);
+ }
+
+@@ -1816,21 +2239,35 @@ unmapnotify(XEvent *e) {
+ else
+ unmanage(c, False);
+ }
++ else if((c = wintosystrayicon(ev->window))) {
++ removesystrayicon(c);
++ resizebarwin(selmon);
++ updatesystray();
++ }
+ }
+
+ void
+ updatebars(void) {
++ unsigned int w;
+ Monitor *m;
++
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+ .background_pixmap = ParentRelative,
+ .event_mask = ButtonPressMask|ExposureMask
+ };
+ for(m = mons; m; m = m->next) {
+- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
++ if (m->barwin)
++ continue;
++ w = m->ww;
++ if(showsystray && m == selmon)
++ 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]);
++ if(showsystray && m == selmon)
++ XMapRaised(dpy, systray->win);
+ XMapRaised(dpy, m->barwin);
+ }
+ }
+@@ -1848,6 +2285,19 @@ updatebarpos(Monitor *m) {
+ m->by = -bh;
+ }
+
++void
++updateclientlist() {
++ Client *c;
++ Monitor *m;
++
++ XDeleteProperty(dpy, root, netatom[NetClientList]);
++ for(m = mons; m; m = m->next)
++ for(c = m->cl->clients; c; c = c->next)
++ XChangeProperty(dpy, root, netatom[NetClientList],
++ XA_WINDOW, 32, PropModeAppend,
++ (unsigned char *) &(c->win), 1);
++}
++
+ Bool
+ updategeom(void) {
+ Bool dirty = False;
+@@ -1872,8 +2322,10 @@ updategeom(void) {
+ if(n <= nn) {
+ for(i = 0; i < (nn - n); i++) { /* new monitors available */
+ for(m = mons; m && m->next; m = m->next);
+- if(m)
++ if(m) {
+ m->next = createmon();
++ attachclients(m->next);
++ }
+ else
+ mons = createmon();
+ }
+@@ -1894,17 +2346,13 @@ updategeom(void) {
+ else { /* less monitors available nn < n */
+ for(i = nn; i < n; i++) {
+ for(m = mons; m && m->next; m = m->next);
+- while(m->clients) {
+- dirty = True;
+- c = m->clients;
+- m->clients = c->next;
+- detachstack(c);
+- c->mon = mons;
+- attach(c);
+- attachstack(c);
+- }
+ if(m == selmon)
+ selmon = mons;
++ for(c = m->cl->clients; c; c = c->next) {
++ dirty = True;
++ if(c->mon == m)
++ c->mon = selmon;
++ }
+ cleanupmon(m);
+ }
+ }
+@@ -2005,9 +2453,112 @@ updatetitle(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;
++ Client *i;
++ unsigned int x = selmon->mx + selmon->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, selmon->by, w, bh, 0, 0, dc.sel[ColBG]);
++ wa.event_mask = ButtonPressMask | ExposureMask;
++ wa.override_redirect = True;
++ wa.background_pixmap = ParentRelative;
++ wa.background_pixel = dc.norm[ColBG];
++ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
++ PropModeReplace, (unsigned char *)&systrayorientation, 1);
++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel|CWBackPixmap, &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) {
++ XMapRaised(dpy, i->win);
++ w += systrayspacing;
++ XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->h);
++ w += i->w;
++ if(i->mon != selmon)
++ i->mon = selmon;
++ }
++ w = w ? w + systrayspacing : 1;
++ x -= w;
++ XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh);
++ /* redraw background */
++ XSetForeground(dpy, dc.gc, dc.norm[ColBG]);
++ XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh);
++ XSync(dpy, False);
+ }
+
+ void
+@@ -2017,7 +2568,6 @@ updatewindowtype(Client *c) {
+
+ if(state == netatom[NetWMFullscreen])
+ setfullscreen(c, True);
+-
+ if(wtype == netatom[NetWMWindowTypeDialog])
+ c->isfloating = True;
+ }
+@@ -2043,11 +2593,53 @@ updatewmhints(Client *c) {
+
+ void
+ view(const Arg *arg) {
++ Monitor *m;
++ unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1];
++ int i;
++ unsigned int tmptag;
++
+ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+- selmon->seltags ^= 1; /* toggle sel tagset */
++
++ /* swap tags when trying to display a tag from another monitor */
+ if(arg->ui & TAGMASK)
++ newtagset = arg->ui & TAGMASK;
++ for(m = mons; m; m = m->next)
++ if(m != selmon && newtagset & m->tagset[m->seltags]) {
++ /* prevent displaying all tags (MODKEY-0) when multiple monitors
++ * are connected */
++ if(newtagset & selmon->tagset[selmon->seltags])
++ return;
++ m->seltags ^= 1;
++ m->tagset[m->seltags] = selmon->tagset[selmon->seltags];
++ attachclients(m);
++ arrange(m);
++ break;
++ }
++
++ selmon->seltags ^= 1; /* toggle sel tagset */
++ if(arg->ui & TAGMASK) {
++ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
++ 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];
++ attachclients(selmon);
++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
++ togglebar(NULL);
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -2058,7 +2650,7 @@ wintoclient(Window w) {
+ Monitor *m;
+
+ for(m = mons; m; m = m->next)
+- for(c = m->clients; c; c = c->next)
++ for(c = m->cl->clients; c; c = c->next)
+ if(c->win == w)
+ return c;
+ return NULL;
+@@ -2080,6 +2672,16 @@ wintomon(Window w) {
+ return selmon;
+ }
+
++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;
++}
++
+ /* There's no way to check accesses to destroyed windows, thus those cases are
+ * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
+ * default error handler, which may call exit. */
+@@ -2116,20 +2718,43 @@ xerrorstart(Display *dpy, XErrorEvent *e
+ void
+ zoom(const Arg *arg) {
+ Client *c = selmon->sel;
++ prevclient = selmon->cl->clients;
++ Client *at, *tmp;
+
+ if(!selmon->lt[selmon->sellt]->arrange
+ || (selmon->sel && selmon->sel->isfloating))
+ return;
+- if(c == nexttiled(selmon->clients))
+- if(!c || !(c = nexttiled(c->next)))
+- return;
++ if(c == nexttiled(selmon->cl->clients, selmon)) {
++ for(tmp = selmon->cl->clients; tmp && tmp != prevzoom; tmp = tmp->next) ;
++ if(tmp != prevzoom)
++ prevzoom = NULL;
++ if(!c || !(c = nexttiled(prevzoom, selmon))) {
++ c = selmon->sel;
++ if(!c || !(c = nexttiled(c->next, selmon)))
++ return;
++ }
++ }
++ for(at = selmon->cl->clients; at && at->next && at != c && at->next != c; at = nexttiled(at->next, selmon)) ;
+ pop(c);
++ /* swap windows instead of pushing the previous one down */
++ if(at && at != c) {
++ /* store c's next neighbor - this window needs to be moved away */
++ tmp = prevzoom = c->next;
++ if(c->next != at) {
++ /* detach c's neighbor from the list of windows */
++ c->next = tmp->next;
++ /* attach tmp after c's previous neighbor */
++ tmp->next = at->next;
++ at->next = tmp;
++ arrange(c->mon);
++ }
++ }
+ }
+
+ int
+ main(int argc, char *argv[]) {
+ if(argc == 2 && !strcmp("-v", argv[1]))
+- die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
++ die("dwm-"VERSION", © 2006-2012 dwm engineers, see LICENSE for details\n");
+ else if(argc != 1)
+ die("usage: dwm [-v]\n");
+ if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
+@@ -2140,6 +2765,8 @@ main(int argc, char *argv[]) {
+ setup();
+ scan();
+ run();
++ if(restart)
++ execvp(argv[0], argv);
+ cleanup();
+ XCloseDisplay(dpy);
+ return EXIT_SUCCESS;
+
+--- /dev/null
++++ focusmaster.c
+@@ -0,0 +1,4 @@
++static void
++focusmaster(const Arg *arg) {
++ focus(nexttiled(selmon->cl->clients, selmon));
++}
+
+--- /dev/null
++++ maximize.c
+@@ -0,0 +1,45 @@
++void
++maximize(int x, int y, int w, int h) {
++ XEvent ev;
++
++ if(!selmon->sel || selmon->sel->isfixed)
++ return;
++ XRaiseWindow(dpy, selmon->sel->win);
++ if(!selmon->sel->ismax) {
++ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating)
++ selmon->sel->wasfloating = True;
++ else {
++ togglefloating(NULL);
++ selmon->sel->wasfloating = False;
++ }
++ selmon->sel->oldx = selmon->sel->x;
++ selmon->sel->oldy = selmon->sel->y;
++ selmon->sel->oldw = selmon->sel->w;
++ selmon->sel->oldh = selmon->sel->h;
++ resize(selmon->sel, x, y, w, h, True);
++ selmon->sel->ismax = True;
++ }
++ else {
++ resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, True);
++ if(!selmon->sel->wasfloating)
++ togglefloating(NULL);
++ selmon->sel->ismax = False;
++ }
++ drawbar(selmon);
++ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
++}
++
++void
++togglemaximize(const Arg *arg) {
++ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx);
++}
++
++void
++toggleverticalmax(const Arg *arg) {
++ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx);
++}
++
++void
++togglehorizontalmax(const Arg *arg) {
++ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h);
++}
+
+--- /dev/null
++++ moveresize.c
+@@ -0,0 +1,64 @@
++void
++moveresize(const Arg *arg) {
++ /* only floating windows can be moved */
++ Client *c;
++ c = selmon->sel;
++ int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh;
++ char xAbs, yAbs, wAbs, hAbs;
++ int msx, msy, dx, dy, nmx, nmy;
++ unsigned int dui;
++ Window dummy;
++
++ if (!c || !arg)
++ return;
++ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
++ return;
++ if(sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8)
++ return;
++ /* compute new window position; prevent window from be positioned outside the current monitor */
++ nw = c->w + w;
++ if(wAbs == 'W')
++ nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw;
++
++ nh = c->h + h;
++ if(hAbs == 'H')
++ nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw;
++
++ nx = c->x + x;
++ if(xAbs == 'X') {
++ if(x < selmon->mx)
++ nx = selmon->mx;
++ else if(x > selmon->mx + selmon->mw)
++ nx = selmon->mx + selmon->mw - nw - 2 * c->bw;
++ else
++ nx = x;
++ }
++
++ ny = c->y + y;
++ if(yAbs == 'Y') {
++ if(y < selmon->my)
++ ny = selmon->my;
++ else if(y > selmon->my + selmon->mh)
++ ny = selmon->my + selmon->mh - nh - 2 * c->bw;
++ else
++ ny = y;
++ }
++
++ ox = c->x;
++ oy = c->y;
++ ow = c->w;
++ oh = c->h;
++
++ XRaiseWindow(dpy, c->win);
++ Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui);
++ resize(c, nx, ny, nw, nh, True);
++
++ /* move cursor along with the window to avoid problems caused by the sloppy focus */
++ if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy)
++ {
++ nmx = c->x - ox + c->w - ow;
++ nmy = c->y - oy + c->h - oh;
++ XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy);
++ }
++}
++
+
+--- /dev/null
++++ push.c
+@@ -0,0 +1,58 @@
++static Client *
++prevtiled(Client *c) {
++ Client *p, *r;
++
++ for(p = selmon->cl->clients, r = NULL; p && p != c; p = p->next)
++ if(!p->isfloating && ISVISIBLE(p, selmon))
++ r = p;
++ return r;
++}
++
++static void
++pushup(const Arg *arg) {
++ Client *sel = selmon->sel;
++ Client *c;
++
++ if(!sel || sel->isfloating)
++ return;
++ if((c = prevtiled(sel))) {
++ /* attach before c */
++ detach(sel);
++ sel->next = c;
++ if(selmon->cl->clients == c)
++ selmon->cl->clients = sel;
++ else {
++ for(c = selmon->cl->clients; c->next != sel->next; c = c->next);
++ c->next = sel;
++ }
++ } else {
++ /* move to the end */
++ for(c = sel; c->next; c = c->next);
++ detach(sel);
++ sel->next = NULL;
++ c->next = sel;
++ }
++ focus(sel);
++ arrange(selmon);
++}
++
++static void
++pushdown(const Arg *arg) {
++ Client *sel = selmon->sel;
++ Client *c;
++
++ if(!sel || sel->isfloating)
++ return;
++ if((c = nexttiled(sel->next, selmon))) {
++ /* attach after c */
++ detach(sel);
++ sel->next = c->next;
++ c->next = sel;
++ } else {
++ /* move to the front */
++ detach(sel);
++ attach(sel);
++ }
++ focus(sel);
++ arrange(selmon);
++}
+
+--- /dev/null
++++ shifttags.c
+@@ -0,0 +1,28 @@
++static void
++shifttags(const Arg *arg) {
++ Arg shift;
++ /* wrap around tags when shifting over the ends of tagmask */
++ /* only activate wrapping when the number of tags fits twice into an
++ * unsigned int */
++ Bool wrap = LENGTH(tags) <= (sizeof(shift.ui) * 4) ? True : False;
++
++ if(arg->i == 0)
++ return;
++
++ if(arg->i > 0)
++ shift.ui = selmon->tagset[selmon->seltags] << arg->i;
++ else {
++ if(wrap) {
++ shift.ui = selmon->tagset[selmon->seltags] << LENGTH(tags);
++ shift.ui = shift.ui >> (-1 * arg->i);
++ }
++ else
++ shift.ui = selmon->tagset[selmon->seltags] >> (-1 * arg->i);
++ }
++ if(wrap)
++ shift.ui |= shift.ui >> LENGTH(tags);
++
++ if(!(shift.ui & TAGMASK))
++ return;
++ view(&shift);
++}
+
+--- /dev/null
++++ tagall.c
+@@ -0,0 +1,24 @@
++void
++tagall(const Arg *arg) {
++ if (!selmon->cl->clients)
++ return;
++ /* if parameter starts with F, just move floating windows */
++ int floating_only = (char *)arg->v && ((char *)arg->v)[0] == 'F' ? 1 : 0;
++ int tag = (char *)arg->v ? atoi(((char *)arg->v) + floating_only) : 0;
++ int j;
++ Client* c;
++ if(tag >= 0 && tag < LENGTH(tags))
++ for(c = selmon->cl->clients; c; c = c->next)
++ {
++ if(!floating_only || c->isfloating)
++ for(j = 0; j < LENGTH(tags); j++)
++ {
++ if(c->tags & 1 << j && selmon->tagset[selmon->seltags] & 1 << j)
++ {
++ c->tags = c->tags ^ (1 << j & TAGMASK);
++ c->tags = c->tags | 1 << (tag-1);
++ }
++ }
++ }
++ arrange(selmon);
++}
+
+--- /dev/null
++++ transient.c
+@@ -0,0 +1,42 @@
++/* cc transient.c -o transient -lX11 */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++
++int main(void) {
++ Display *d;
++ Window r, f, t = None;
++ XSizeHints h;
++ XEvent e;
++
++ d = XOpenDisplay(NULL);
++ if (!d)
++ exit(1);
++ r = DefaultRootWindow(d);
++
++ f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0);
++ h.min_width = h.max_width = h.min_height = h.max_height = 400;
++ h.flags = PMinSize | PMaxSize;
++ XSetWMNormalHints(d, f, &h);
++ XStoreName(d, f, "floating");
++ XMapWindow(d, f);
++
++ XSelectInput(d, f, ExposureMask);
++ while (1) {
++ XNextEvent(d, &e);
++
++ if (t == None) {
++ sleep(5);
++ t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0);
++ XSetTransientForHint(d, t, f);
++ XStoreName(d, t, "transient");
++ XMapWindow(d, t);
++ XSelectInput(d, t, ExposureMask);
++ }
++ }
++
++ XCloseDisplay(d);
++ exit(0);
++}
diff --git a/x11-wm/dwm/files/dwm-session2 b/x11-wm/dwm/files/dwm-session2
new file mode 100644
index 0000000..f886ce9
--- /dev/null
+++ b/x11-wm/dwm/files/dwm-session2
@@ -0,0 +1,11 @@
+#!/bin/sh
+DIR=${HOME}/.dwm
+if [ -f "${DIR}"/dwmrc ]; then
+ /bin/sh "${DIR}"/dwmrc &
+else
+ while true; do
+ xsetroot -name "`date`"
+ sleep 1
+ done &
+fi
+exec /usr/bin/dwm
diff --git a/x11-wm/dwm/files/dwm.desktop b/x11-wm/dwm/files/dwm.desktop
new file mode 100644
index 0000000..d6131b5
--- /dev/null
+++ b/x11-wm/dwm/files/dwm.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=dwm
+Comment=dynamic window manager
+Exec=/etc/X11/Sessions/dwm
+TryExec=dwm
+Icon=
+Type=Application
diff --git a/x11-wm/dwm/metadata.xml b/x11-wm/dwm/metadata.xml
new file mode 100644
index 0000000..1871779
--- /dev/null
+++ b/x11-wm/dwm/metadata.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+<herd>desktop-wm</herd>
+<maintainer>
+ <email>cedk@gentoo.org</email>
+</maintainer>
+<maintainer>
+ <email>ThyArmageddon+Gentoo@Gmail.com</email>
+ <name>Elijah El Lazkani</name>
+</maintainer>
+<longdescription>dwm is a dynamic window manager for X. It manages windows in tiling and floating modes. Either mode can be applied dynamically, optimizing the environment for the application in use and the task performed.
+This version is edited by Elijah with patches for different fixes and additions.</longdescription>
+</pkgmetadata>