diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml
deleted file mode 100644
index 3866e31..0000000
--- a/.forgejo/workflows/build.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
-name: Build/Publish XBPS
-
-on:
-  push:
-    paths:
-      - "config**"
-
-jobs:
-  build-and-publish:
-    runs-on: docker
-    container: git.snaile.de/snailed/xbps-builder:2024.0502.1733@sha256:0ca263f8a97fbd29f88349e731153f60569d19ddd7320f2c7c80047a35260c9b
-    env:
-      LICENSE: "GPL-2.0"
-      SHORT_DESCRIPTION: "Customized DWM"
-      DEPENDENCIES: "pango>=1.44,glibc>=2.32,libX11>=1.2,libXft>=2.3.8,libXinerama>=1.0.3,fontconfig>=2.6.0"
-      MAINTAINER: "Luca Bilke <luca@bil.ke>"
-      NAME: "dwm-custom"
-      ARCH: "x86_64"
-    steps:
-      - name: Checkout
-        uses: https://code.forgejo.org/actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
-        with:
-          submodules: true
-
-      - name: Generate tag and package name
-        run: |
-          set -xeu
-          MAJOR=$(date +%Y)
-          MINOR=$(date +%m%d)
-          PATCH=$(date +%H%M)
-          echo "PACKAGE_NAME=${{ env.NAME }}-${MAJOR}.${MINOR}.${PATCH}_1" >> $GITHUB_ENV
-
-      - name: Build
-        run: |
-          set -xeu
-          make clean install DESTDIR="${GITHUB_WORKSPACE}/pkg" PREFIX="/usr"
-
-      - name: Create package
-        run: |
-          set -xeu
-          export XBPS_TARGET_ARCH=${{ env.ARCH }}
-          mkdir /target
-          cd /target || exit 1
-          xbps-create -A ${{ env.ARCH }} \
-            -H "${{ github.server_url }}/${{ github.repository }}" \
-            -l "${{ env.LICENSE }}" \
-            -n "${{ env.PACKAGE_NAME }}" \
-            -m "${{ env.MAINTAINER }}" \
-            -s "${{ env.SHORT_DESCRIPTION }}" \
-            -D "${{ env.DEPENDENCIES }}" \
-            "${GITHUB_WORKSPACE}/pkg"
-
-      - name: Push Package
-        run: |
-          set -xeu
-          curl -so "/target/${{ env.ARCH }}-repodata" "https://xbps.snaile.de/${{ env.ARCH }}-repodata"
-          xbps-rindex --add "/target/${{ env.PACKAGE_NAME }}.${{ env.ARCH }}.xbps"
-          echo '${{ secrets.XBPS_SIGNING_KEY }}' >/tmp/privkey.pem
-          XBPS_PASSPHRASE=${{ secrets.XBPS_SIGNING_PASSPHRASE }} xbps-rindex --privkey /tmp/privkey.pem --sign-pkg --signedby "${{ env.MAINTAINER }}" "/target/${{ env.PACKAGE_NAME }}.${{ env.ARCH }}.xbps"
-          rm /tmp/privkey.pem
-          ls -lAH /target
-          find /target -type f -exec sh -c 'curl -X PUT --digest -u "${{ vars.XBPS_WEBDAV_USER }}:${{ secrets.XBPS_WEBDAV_KEY }}" -T "${1}" "https://xbps.snaile.de/$(basename $1)"' find-shell {} \;
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 648f5aa..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-dwm-final
-dwm-dev-1.0.0_1.x86_64.xbps
-pkg/usr
-patch
-LICENSE
-README
-config.def.h
-config.h
-config.mk
-drw.c
-drw.h
-dwm.1
-dwm.c
-dwm.c.orig
-dwm.desktop
-dwm.png
-transient.c
-util.c
-util.h
-util.o
-drw.o
-dwm.o
-dwm
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 1b17b6d..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "dwm-flexipatch"]
-	path = dwm-flexipatch
-	url = https://github.com/bakkeby/dwm-flexipatch
-[submodule "flexipatch-finalizer"]
-	path = flexipatch-finalizer
-	url = https://github.com/bakkeby/flexipatch-finalizer
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..995172f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,38 @@
+MIT/X Consortium License
+
+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
+© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
+© 2007-2009 Christof Musik <christof at sendfax dot de>
+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
+© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
+© 2008 Martin Hurton <martin dot hurton at gmail dot com>
+© 2008 Neale Pickett <neale dot woozle dot org>
+© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2011 Christoph Lohmann <20h@r-36.net>
+© 2015-2016 Quentin Rameau <quinq@fifth.space>
+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
+© 2020-2022 Chris Down <chris@chrisdown.name>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
index 10de8bd..a166452 100644
--- a/Makefile
+++ b/Makefile
@@ -1,50 +1,57 @@
 # dwm - dynamic window manager
 # See LICENSE file for copyright and license details.
-.PHONY: all submodule clean dist install uninstall
 
 include config.mk
 
 SRC = drw.c dwm.c util.c
 OBJ = ${SRC:.c=.o}
 
+# FreeBSD users, prefix all ifdef, else and endif statements with a . for this to work (e.g. .ifdef)
+
+ifdef YAJLLIBS
+all: dwm dwm-msg
+else
 all: dwm
+endif
 
 .c.o:
 	${CC} -c ${CFLAGS} $<
 
-config.mk:
-	cp config/config.mk config.mk
+${OBJ}: config.h config.mk
 
 config.h:
-	cp config/config.h config.h
-
-${SRC}: buildroot
-
-${OBJ}: config.h config.mk
+	cp config.def.h $@
 
 dwm: ${OBJ}
 	${CC} -o $@ ${OBJ} ${LDFLAGS}
 
-submodule:
-	git submodule update --init
+ifdef YAJLLIBS
+dwm-msg:
+	${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS}
+endif
 
 clean:
-	find . -maxdepth 1 -type f  | grep -Pv "^\./\.|Makefile$$" | xargs -r rm
-	rm -r tmp patch 2>/dev/null || true
-	git -C dwm-flexipatch reset --hard HEAD
-	git -C dwm-flexipatch clean -ffdx
+	rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
+	rm -f dwm-msg
 
-buildroot: submodule
-	cp config/patches.h dwm-flexipatch/patches.h
-	flexipatch-finalizer/flexipatch-finalizer.sh -r -d dwm-flexipatch -o tmp
-	rm -r tmp/Makefile tmp/config.mk patch 2>/dev/null || true
-	mv tmp/* ./
-	for patch in config/patches/*.diff; do patch <"$$patch"; done
+dist: clean
+	mkdir -p dwm-${VERSION}
+	cp -R LICENSE Makefile README config.def.h config.mk\
+		dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
+	tar -cf dwm-${VERSION}.tar dwm-${VERSION}
+	gzip dwm-${VERSION}.tar
+	rm -rf dwm-${VERSION}
 
 install: all
 	mkdir -p ${DESTDIR}${PREFIX}/bin
 	cp -f dwm ${DESTDIR}${PREFIX}/bin
+ifdef YAJLLIBS
+	cp -f dwm-msg ${DESTDIR}${PREFIX}/bin
+endif
 	chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
+ifdef YAJLLIBS
+	chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg
+endif
 	mkdir -p ${DESTDIR}${MANPREFIX}/man1
 	sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
@@ -56,3 +63,5 @@ uninstall:
 	rm -f ${DESTDIR}${PREFIX}/bin/dwm\
 		${DESTDIR}${MANPREFIX}/man1/dwm.1\
 		${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop
+
+.PHONY: all clean dist install uninstall
diff --git a/README b/README
new file mode 100644
index 0000000..95d4fd0
--- /dev/null
+++ b/README
@@ -0,0 +1,48 @@
+dwm - dynamic window manager
+============================
+dwm is an extremely fast, small, and dynamic window manager for X.
+
+
+Requirements
+------------
+In order to build dwm you need the Xlib header files.
+
+
+Installation
+------------
+Edit config.mk to match your local setup (dwm is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install dwm (if
+necessary as root):
+
+    make clean install
+
+
+Running dwm
+-----------
+Add the following line to your .xinitrc to start dwm using startx:
+
+    exec dwm
+
+In order to connect dwm to a specific display, make sure that
+the DISPLAY environment variable is set correctly, e.g.:
+
+    DISPLAY=foo.bar:1 exec dwm
+
+(This will start dwm on display :1 of the host foo.bar.)
+
+In order to display status info in the bar, you can do something
+like this in your .xinitrc:
+
+    while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
+    do
+    	sleep 1
+    done &
+    exec dwm
+
+
+Configuration
+-------------
+The configuration of dwm is done by creating a custom config.h
+and (re)compiling the source code.
diff --git a/config.def.h b/config.def.h
new file mode 100644
index 0000000..e592d6d
--- /dev/null
+++ b/config.def.h
@@ -0,0 +1,341 @@
+/* See LICENSE file for copyright and license details. */
+
+/* appearance */
+static const unsigned int borderpx       = 1;   /* border pixel of windows */
+static const unsigned int snap           = 32;  /* snap pixel */
+static const int showbar                 = 1;   /* 0 means no bar */
+static const int topbar                  = 1;   /* 0 means bottom bar */
+static const int focusonwheel            = 0;
+static int floatposgrid_x                = 5;  /* float grid columns */
+static int floatposgrid_y                = 5;  /* float grid rows */
+/* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */
+static const int statusmon               = 'A';
+
+/* Indicators: see patch/bar_indicators.h for options */
+static int tagindicatortype              = INDICATOR_TOP_LEFT_SQUARE;
+static int tiledindicatortype            = INDICATOR_NONE;
+static int floatindicatortype            = INDICATOR_TOP_LEFT_SQUARE;
+static const char font[]                 = "monospace 10";
+static const char dmenufont[]            = "monospace:size=10";
+
+static char c000000[]                    = "#000000"; // placeholder value
+
+static char normfgcolor[]                = "#bbbbbb";
+static char normbgcolor[]                = "#222222";
+static char normbordercolor[]            = "#444444";
+static char normfloatcolor[]             = "#db8fd9";
+
+static char selfgcolor[]                 = "#eeeeee";
+static char selbgcolor[]                 = "#005577";
+static char selbordercolor[]             = "#005577";
+static char selfloatcolor[]              = "#005577";
+
+static char titlenormfgcolor[]           = "#bbbbbb";
+static char titlenormbgcolor[]           = "#222222";
+static char titlenormbordercolor[]       = "#444444";
+static char titlenormfloatcolor[]        = "#db8fd9";
+
+static char titleselfgcolor[]            = "#eeeeee";
+static char titleselbgcolor[]            = "#005577";
+static char titleselbordercolor[]        = "#005577";
+static char titleselfloatcolor[]         = "#005577";
+
+static char tagsnormfgcolor[]            = "#bbbbbb";
+static char tagsnormbgcolor[]            = "#222222";
+static char tagsnormbordercolor[]        = "#444444";
+static char tagsnormfloatcolor[]         = "#db8fd9";
+
+static char tagsselfgcolor[]             = "#eeeeee";
+static char tagsselbgcolor[]             = "#005577";
+static char tagsselbordercolor[]         = "#005577";
+static char tagsselfloatcolor[]          = "#005577";
+
+static char hidnormfgcolor[]             = "#005577";
+static char hidselfgcolor[]              = "#227799";
+static char hidnormbgcolor[]             = "#222222";
+static char hidselbgcolor[]              = "#222222";
+
+static char urgfgcolor[]                 = "#bbbbbb";
+static char urgbgcolor[]                 = "#222222";
+static char urgbordercolor[]             = "#ff0000";
+static char urgfloatcolor[]              = "#db8fd9";
+
+static char scratchselfgcolor[]          = "#FFF7D4";
+static char scratchselbgcolor[]          = "#77547E";
+static char scratchselbordercolor[]      = "#894B9F";
+static char scratchselfloatcolor[]       = "#894B9F";
+
+static char scratchnormfgcolor[]         = "#FFF7D4";
+static char scratchnormbgcolor[]         = "#664C67";
+static char scratchnormbordercolor[]     = "#77547E";
+static char scratchnormfloatcolor[]      = "#77547E";
+
+static char *colors[][ColCount] = {
+	/*                       fg                bg                border                float */
+	[SchemeNorm]         = { normfgcolor,      normbgcolor,      normbordercolor,      normfloatcolor },
+	[SchemeSel]          = { selfgcolor,       selbgcolor,       selbordercolor,       selfloatcolor },
+	[SchemeTitleNorm]    = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor },
+	[SchemeTitleSel]     = { titleselfgcolor,  titleselbgcolor,  titleselbordercolor,  titleselfloatcolor },
+	[SchemeTagsNorm]     = { tagsnormfgcolor,  tagsnormbgcolor,  tagsnormbordercolor,  tagsnormfloatcolor },
+	[SchemeTagsSel]      = { tagsselfgcolor,   tagsselbgcolor,   tagsselbordercolor,   tagsselfloatcolor },
+	[SchemeHidNorm]      = { hidnormfgcolor,   hidnormbgcolor,   c000000,              c000000 },
+	[SchemeHidSel]       = { hidselfgcolor,    hidselbgcolor,    c000000,              c000000 },
+	[SchemeUrg]          = { urgfgcolor,       urgbgcolor,       urgbordercolor,       urgfloatcolor },
+	[SchemeScratchSel]  = { scratchselfgcolor, scratchselbgcolor, scratchselbordercolor, scratchselfloatcolor },
+	[SchemeScratchNorm] = { scratchnormfgcolor, scratchnormbgcolor, scratchnormbordercolor, scratchnormfloatcolor },
+};
+
+static const char *const autostart[] = {
+	"st", NULL,
+	NULL /* terminate */
+};
+
+static const char *scratchpadcmd[] = {"s", "st", "-n", "spterm", NULL};
+
+/* Tags
+ * In a traditional dwm the number of tags in use can be changed simply by changing the number
+ * of strings in the tags array. This build does things a bit different which has some added
+ * benefits. If you need to change the number of tags here then change the NUMTAGS macro in dwm.c.
+ *
+ * Examples:
+ *
+ *  1) static char *tagicons[][NUMTAGS*2] = {
+ *         [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" },
+ *     }
+ *
+ *  2) static char *tagicons[][1] = {
+ *         [DEFAULT_TAGS] = { "•" },
+ *     }
+ *
+ * The first example would result in the tags on the first monitor to be 1 through 9, while the
+ * tags for the second monitor would be named A through I. A third monitor would start again at
+ * 1 through 9 while the tags on a fourth monitor would also be named A through I. Note the tags
+ * count of NUMTAGS*2 in the array initialiser which defines how many tag text / icon exists in
+ * the array. This can be changed to *3 to add separate icons for a third monitor.
+ *
+ * For the second example each tag would be represented as a bullet point. Both cases work the
+ * same from a technical standpoint - the icon index is derived from the tag index and the monitor
+ * index. If the icon index is is greater than the number of tag icons then it will wrap around
+ * until it an icon matches. Similarly if there are two tag icons then it would alternate between
+ * them. This works seamlessly with alternative tags and alttagsdecoration patches.
+ */
+static char *tagicons[][NUMTAGS] =
+{
+	[DEFAULT_TAGS]        = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
+	[ALTERNATIVE_TAGS]    = { "A", "B", "C", "D", "E", "F", "G", "H", "I" },
+	[ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
+};
+
+/* There are two options when it comes to per-client rules:
+ *  - a typical struct table or
+ *  - using the RULE macro
+ *
+ * A traditional struct table looks like this:
+ *    // class      instance  title  wintype  tags mask  isfloating  monitor
+ *    { "Gimp",     NULL,     NULL,  NULL,    1 << 4,    0,          -1 },
+ *    { "Firefox",  NULL,     NULL,  NULL,    1 << 7,    0,          -1 },
+ *
+ * The RULE macro has the default values set for each field allowing you to only
+ * specify the values that are relevant for your rule, e.g.
+ *
+ *    RULE(.class = "Gimp", .tags = 1 << 4)
+ *    RULE(.class = "Firefox", .tags = 1 << 7)
+ *
+ * Refer to the Rule struct definition for the list of available fields depending on
+ * the patches you enable.
+ */
+static const Rule rules[] = {
+	/* xprop(1):
+	 *	WM_CLASS(STRING) = instance, class
+	 *	WM_NAME(STRING) = title
+	 *	WM_WINDOW_ROLE(STRING) = role
+	 *	_NET_WM_WINDOW_TYPE(ATOM) = wintype
+	 */
+	RULE(.wintype = WTYPE "DIALOG", .isfloating = 1)
+	RULE(.wintype = WTYPE "UTILITY", .isfloating = 1)
+	RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1)
+	RULE(.wintype = WTYPE "SPLASH", .isfloating = 1)
+	RULE(.class = "Gimp", .tags = 1 << 4)
+	RULE(.class = "Firefox", .tags = 1 << 7)
+	RULE(.instance = "spterm", .scratchkey = 's', .isfloating = 1)
+};
+
+/* Bar rules allow you to configure what is shown where on the bar, as well as
+ * introducing your own bar modules.
+ *
+ *    monitor:
+ *      -1  show on all monitors
+ *       0  show on monitor 0
+ *      'A' show on active monitor (i.e. focused / selected) (or just -1 for active?)
+ *    bar - bar index, 0 is default, 1 is extrabar
+ *    alignment - how the module is aligned compared to other modules
+ *    widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions
+ *    name - does nothing, intended for visual clue and for logging / debugging
+ */
+static const BarRule barrules[] = {
+	/* monitor   bar    alignment         widthfunc                 drawfunc                clickfunc                hoverfunc                name */
+	{ -1,        0,     BAR_ALIGN_LEFT,   width_tags,               draw_tags,              click_tags,              hover_tags,              "tags" },
+	{ -1,        0,     BAR_ALIGN_LEFT,   width_ltsymbol,           draw_ltsymbol,          click_ltsymbol,          NULL,                    "layout" },
+	{ statusmon, 0,     BAR_ALIGN_RIGHT,  width_status,             draw_status,            click_statuscmd,         NULL,                    "status" },
+	{ -1,        0,     BAR_ALIGN_NONE,   width_wintitle,           draw_wintitle,          click_wintitle,          NULL,                    "wintitle" },
+};
+
+/* layout(s) */
+static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster     = 1;    /* number of clients in master area */
+static const int resizehints = 0;    /* 1 means respect size hints in tiled resizals */
+static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+
+static const Layout layouts[] = {
+	/* symbol     arrange function */
+	{ "[]=",      tile },    /* first entry is default */
+	{ "><>",      NULL },    /* no layout function means floating behavior */
+	{ "[M]",      monocle },
+	{ "TTT",      bstack },
+	{ "|M|",      centeredmaster },
+	{ "[D]",      deck },
+	{ ":::",      gaplessgrid },
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
+	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
+	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
+	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
+
+#define STACKKEYS(MOD,ACTION) \
+	{ MOD, XK_j,     ACTION##stack, {.i = INC(+1) } }, \
+	{ MOD, XK_k,     ACTION##stack, {.i = INC(-1) } }, \
+	{ MOD, XK_s,     ACTION##stack, {.i = PREVSEL } }, \
+	{ MOD, XK_w,     ACTION##stack, {.i = 0 } }, \
+	{ MOD, XK_e,     ACTION##stack, {.i = 1 } }, \
+	{ MOD, XK_a,     ACTION##stack, {.i = 2 } }, \
+	{ MOD, XK_z,     ACTION##stack, {.i = -1 } },
+
+/* 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 const char *dmenucmd[] = {
+	"dmenu_run",
+	"-fn", dmenufont,
+	"-nb", normbgcolor,
+	"-nf", normfgcolor,
+	"-sb", selbgcolor,
+	"-sf", selfgcolor,
+	NULL
+};
+static const char *termcmd[]  = { "st", NULL };
+
+/* This defines the name of the executable that handles the bar (used for signalling purposes) */
+#define STATUSBAR "dwmblocks"
+
+static const Key keys[] = {
+	/* modifier                     key            function                argument */
+	{ MODKEY,                       XK_p,          spawn,                  {.v = dmenucmd } },
+	{ MODKEY|ShiftMask,             XK_Return,     spawn,                  {.v = termcmd } },
+	{ MODKEY,                       XK_b,          togglebar,              {0} },
+	STACKKEYS(MODKEY,                              focus)
+	STACKKEYS(MODKEY|ShiftMask,                    push)
+	{ MODKEY,                       XK_Left,       focusdir,               {.i = 0 } }, // left
+	{ MODKEY,                       XK_Right,      focusdir,               {.i = 1 } }, // right
+	{ MODKEY,                       XK_Up,         focusdir,               {.i = 2 } }, // up
+	{ MODKEY,                       XK_Down,       focusdir,               {.i = 3 } }, // down
+	{ 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|ShiftMask,             XK_q,          quit,                   {0} },
+	{ MODKEY|ControlMask|ShiftMask, XK_q,          quit,                   {1} },
+	{ 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_grave,      togglescratch,          {.v = scratchpadcmd } },
+	{ MODKEY|ControlMask,           XK_grave,      setscratch,             {.v = scratchpadcmd } },
+	{ MODKEY|ShiftMask,             XK_grave,      removescratch,          {.v = scratchpadcmd } },
+	{ MODKEY|Mod4Mask,              XK_space,      unfloatvisible,         {0} },
+	{ MODKEY|ShiftMask,             XK_t,          unfloatvisible,         {.v = &layouts[0]} },
+	{ MODKEY,                       XK_y,          togglefullscreen,       {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 } },
+	/* Note that due to key limitations the below example kybindings are defined with a Mod3Mask,
+	 * which is not always readily available. Refer to the patch wiki for more details. */
+	/* Client position is limited to monitor window area */
+	{ Mod3Mask,                     XK_u,            floatpos,               {.v = "-26x -26y" } }, // ↖
+	{ Mod3Mask,                     XK_i,            floatpos,               {.v = "  0x -26y" } }, // ↑
+	{ Mod3Mask,                     XK_o,            floatpos,               {.v = " 26x -26y" } }, // ↗
+	{ Mod3Mask,                     XK_j,            floatpos,               {.v = "-26x   0y" } }, // ←
+	{ Mod3Mask,                     XK_l,            floatpos,               {.v = " 26x   0y" } }, // →
+	{ Mod3Mask,                     XK_m,            floatpos,               {.v = "-26x  26y" } }, // ↙
+	{ Mod3Mask,                     XK_comma,        floatpos,               {.v = "  0x  26y" } }, // ↓
+	{ Mod3Mask,                     XK_period,       floatpos,               {.v = " 26x  26y" } }, // ↘
+	/* Absolute positioning (allows moving windows between monitors) */
+	{ Mod3Mask|ControlMask,         XK_u,            floatpos,               {.v = "-26a -26a" } }, // ↖
+	{ Mod3Mask|ControlMask,         XK_i,            floatpos,               {.v = "  0a -26a" } }, // ↑
+	{ Mod3Mask|ControlMask,         XK_o,            floatpos,               {.v = " 26a -26a" } }, // ↗
+	{ Mod3Mask|ControlMask,         XK_j,            floatpos,               {.v = "-26a   0a" } }, // ←
+	{ Mod3Mask|ControlMask,         XK_l,            floatpos,               {.v = " 26a   0a" } }, // →
+	{ Mod3Mask|ControlMask,         XK_m,            floatpos,               {.v = "-26a  26a" } }, // ↙
+	{ Mod3Mask|ControlMask,         XK_comma,        floatpos,               {.v = "  0a  26a" } }, // ↓
+	{ Mod3Mask|ControlMask,         XK_period,       floatpos,               {.v = " 26a  26a" } }, // ↘
+	/* Resize client, client center position is fixed which means that client expands in all directions */
+	{ Mod3Mask|ShiftMask,           XK_u,            floatpos,               {.v = "-26w -26h" } }, // ↖
+	{ Mod3Mask|ShiftMask,           XK_i,            floatpos,               {.v = "  0w -26h" } }, // ↑
+	{ Mod3Mask|ShiftMask,           XK_o,            floatpos,               {.v = " 26w -26h" } }, // ↗
+	{ Mod3Mask|ShiftMask,           XK_j,            floatpos,               {.v = "-26w   0h" } }, // ←
+	{ Mod3Mask|ShiftMask,           XK_k,            floatpos,               {.v = "800W 800H" } }, // ·
+	{ Mod3Mask|ShiftMask,           XK_l,            floatpos,               {.v = " 26w   0h" } }, // →
+	{ Mod3Mask|ShiftMask,           XK_m,            floatpos,               {.v = "-26w  26h" } }, // ↙
+	{ Mod3Mask|ShiftMask,           XK_comma,        floatpos,               {.v = "  0w  26h" } }, // ↓
+	{ Mod3Mask|ShiftMask,           XK_period,       floatpos,               {.v = " 26w  26h" } }, // ↘
+	/* Client is positioned in a floating grid, movement is relative to client's current position */
+	{ Mod3Mask|Mod1Mask,            XK_u,            floatpos,               {.v = "-1p -1p" } }, // ↖
+	{ Mod3Mask|Mod1Mask,            XK_i,            floatpos,               {.v = " 0p -1p" } }, // ↑
+	{ Mod3Mask|Mod1Mask,            XK_o,            floatpos,               {.v = " 1p -1p" } }, // ↗
+	{ Mod3Mask|Mod1Mask,            XK_j,            floatpos,               {.v = "-1p  0p" } }, // ←
+	{ Mod3Mask|Mod1Mask,            XK_k,            floatpos,               {.v = " 0p  0p" } }, // ·
+	{ Mod3Mask|Mod1Mask,            XK_l,            floatpos,               {.v = " 1p  0p" } }, // →
+	{ Mod3Mask|Mod1Mask,            XK_m,            floatpos,               {.v = "-1p  1p" } }, // ↙
+	{ Mod3Mask|Mod1Mask,            XK_comma,        floatpos,               {.v = " 0p  1p" } }, // ↓
+	{ Mod3Mask|Mod1Mask,            XK_period,       floatpos,               {.v = " 1p  1p" } }, // ↘
+	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)
+};
+
+/* button definitions */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static const 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,                   Button1,        sigstatusbar,   {.i = 1 } },
+	{ ClkStatusText,        0,                   Button2,        sigstatusbar,   {.i = 2 } },
+	{ ClkStatusText,        0,                   Button3,        sigstatusbar,   {.i = 3 } },
+	{ 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/config/config.h b/config.h
similarity index 100%
rename from config/config.h
rename to config.h
diff --git a/config/config.mk b/config.mk
similarity index 100%
rename from config/config.mk
rename to config.mk
diff --git a/config/patches.h b/config/patches.h
deleted file mode 100644
index 4b63e4d..0000000
--- a/config/patches.h
+++ /dev/null
@@ -1,1499 +0,0 @@
-/*
- * This file contains patch control flags.
- *
- * In principle you should be able to mix and match any patches
- * you may want. In cases where patches are logically incompatible
- * one patch may take precedence over the other as noted in the
- * relevant descriptions.
- *
- * Although layouts typically come as patches they are differentiated
- * here for grouping purposes.
- */
-
-/**
- * Bar modules
- */
-
-/* Enhanced taskbar that shows the titles of all visible windows in the status bar
- * and allows focus / hiding / unhiding of windows by clicking on the status bar.
- * Awesomebar takes precedence over fancybar.
- * https://dwm.suckless.org/patches/awesomebar/
- */
-#define BAR_AWESOMEBAR_PATCH 0
-
-/* This patch depends on statuscmd patch and adds integration with a (patched)
- * dwmblocks instance to give a clickable status bar. One must not necessarily
- * have to use dwmblocks for this feature, any status updater that has support
- * for real-time signals (SIGRTMIN) can be used.
- *
- * dwmblocks: https://github.com/torrinfail/dwmblocks
- * https://dwm.suckless.org/patches/statuscmd/
- */
-#define BAR_DWMBLOCKS_PATCH 1
-
-/* Originally the dwmblocks + statuscmd patch used a user defined signal (SIGUSR1)
- * for communicating with dwmblocks to indicate update signal and what button was
- * pressed. The signalling was later changed to SIGRTMIN instead.
- *
- * Ultimately this makes dwmblocks instances that were patched with the old patch
- * are incompatible with the new dwm patch and vice versa.
- *
- * This is a compatibility patch that makes dwm use SIGUSR1 instead of SIGRTMIN so
- * if button clicks are not working then you may want to try enabling this.
- *
- * If dwmblocks happen to die like this when clicking on a status
- *
- *    [1]    54355 user-defined signal 1  dwmblocks
- *
- * then it suggests that dwmblocks does not support user defined signals and this
- * patch should be left disabled.
- *
- * Patch: https://gist.github.com/danbyl/54f7c1d57fc6507242a95b71c3d8fdea
- * https://dwm.suckless.org/patches/statuscmd/
- */
-#define BAR_DWMBLOCKS_SIGUSR1_PATCH 0
-
-/* This patch shows the titles of all visible windows in the status bar
- * (as opposed to showing only the selected one).
- * Awesomebar takes precedence over fancybar. Fancybar takes precedence over
- * the centeredwindowname patch.
- * https://dwm.suckless.org/patches/fancybar/
- */
-#define BAR_FANCYBAR_PATCH 0
-
-/* Being an evolution of the bartabgroups patch the flexwintitle patch specifically
- * taps into the many layout options that flextile-deluxe offers to produce a window
- * title section in the bar that is representative of what is shown on screen.
- */
-#define BAR_FLEXWINTITLE_PATCH 0
-
-/* This patch adds a context menu for layout switching.
- *   - xmenu needs to be installed.
- *   - Edit layoutmenu.sh with the installed layouts and with correct indexes.
- *   - Place layoutmenu.sh in PATH.
- *   - The text of the menu items is for display only. Name them however you want.
- * https://dwm.suckless.org/patches/layoutmenu/
- */
-#define BAR_LAYOUTMENU_PATCH 0
-
-/* Show layout symbol in bar */
-#define BAR_LTSYMBOL_PATCH 1
-
-/* Adds powerline arrows for the status.
- * This uses statuscolors logic for choosing colors for the powerline. As these markers
- * are also control characters there is no explicit statuscmd support for this patch.
- *
- * Powerline separators are defined as:
- *    |\xXX  (creates a hard edge)
- *    <\xXX  (creates a less than arrow)
- *    /\xXX  (creates a diagonal line)
- *
- * Examples:
- *    xsetroot -name "$(echo -e '<\x01a<\x02b<\x03c')"
- *    xsetroot -name "$(echo -e '/\x01d/\x02e/\x03f')"
- *
- * https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40#4b1a539194be7467cefbda22f675a3b7c19ceca7
- * https://dwm.suckless.org/patches/statuscolors/
- */
-#define BAR_POWERLINE_STATUS_PATCH 0
-
-/* Adds powerline arrows for the tags.
- * https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40#4b1a539194be7467cefbda22f675a3b7c19ceca7
- */
-#define BAR_POWERLINE_TAGS_PATCH 0
-
-/* Alters the tags powerline to use forward slash instead of arrows */
-#define BAR_POWERLINE_TAGS_SLASH_PATCH 0
-
-/* This patch turns the titlebar area into a mfact-respecting tabbar showing each client's title.
- * https://dwm.suckless.org/patches/bartabgroups/
- */
-#define BAR_TABGROUPS_PATCH 0
-
-/* This patch adds an option to place tags in rows like in many other window managers.
- * https://dwm.suckless.org/patches/taggrid/
- */
-#define BAR_TAGGRID_PATCH 0
-
-/* Hover tag icons to see a preview of the windows on that tag.
- *
- * The patch depends on Imlib2 for icon scaling.
- * You need to uncomment the corresponding line in config.mk to use the -lImlib2 library
- *
- * Arch Linux:
- *     sudo pacman -S imlib2
- * Debian:
- *     sudo apt install libimlib2-dev
- *
- * As with the winicon patch you may want to consider adding the compiler flags of -O3 and
- * -march=native to enable auto loop vectorize for better performance.
- *
- * https://dwm.suckless.org/patches/tag-previews/
- */
-#define BAR_TAGPREVIEW_PATCH 0
-
-/* Show status in bar */
-#define BAR_STATUS_PATCH 1
-
-/* This patch adds a clickable button to the left hand side of the statusbar.
- * https://dwm.suckless.org/patches/statusbutton/
- */
-#define BAR_STATUSBUTTON_PATCH 0
-
-/* This patch adds the ability to execute shell commands based on the mouse button and position
- * when clicking the status bar. Refer to the website for usage.
- * https://dwm.suckless.org/patches/statuscmd/
- */
-#define BAR_STATUSCMD_PATCH 1
-
-/* Status2d allows colors and rectangle drawing in your dwm status bar.
- * This patch is incompatible with the statuscolors patch which takes precedence.
- * This patch is incompatible with the extrabar patch.
- * https://dwm.suckless.org/patches/status2d/
- */
-#define BAR_STATUS2D_PATCH 0
-
-/* Supplementary patch should you want to disable alpha for the status2d section */
-#define BAR_STATUS2D_NO_ALPHA_PATCH 0
-
-/* Addition to the status2d patch that allows the use of terminal colors (color0 through color15)
- * from xrdb in the status, allowing programs like pywal to change statusbar colors.
- * This adds the C and B codes to use terminal foreground and background colors respectively.
- * E.g. ^B5^ would use color5 as the background color.
- * https://dwm.suckless.org/patches/status2d/
- */
-#define BAR_STATUS2D_XRDB_TERMCOLORS_PATCH 0
-
-/* The systray patch adds systray for the status bar.
- * https://dwm.suckless.org/patches/systray/
- */
-#define BAR_SYSTRAY_PATCH 0
-
-/* Show tag symbols in the bar. */
-#define BAR_TAGS_PATCH 1
-
-/* Show tag symbols + class of master window in the bar.
- * https://dwm.suckless.org/patches/taglabels/
- */
-#define BAR_TAGLABELS_PATCH 0
-
-/* This patch underlines the selected tag, or optionally all tags.
- * https://dwm.suckless.org/patches/underlinetags/
- */
-#define BAR_UNDERLINETAGS_PATCH 0
-
-/* This patch adds the window icon next to the window title in the bar.
- *
- * The patch depends on Imlib2 for icon scaling.
- * You need to uncomment the corresponding line in config.mk to use the -lImlib2 library
- *
- * Arch Linux:
- *     sudo pacman -S imlib2
- * Debian:
- *     sudo apt install libimlib2-dev
- *
- * The author recommends adding the compiler flags of -O3 and -march=native to enable auto loop
- * vectorize for better performance.
- *
- * https://github.com/AdamYuan/dwm-winicon
- * https://dwm.suckless.org/patches/winicon
- */
-#define BAR_WINICON_PATCH 0
-
-/* Show window title in bar */
-#define BAR_WINTITLE_PATCH 1
-
-/* Shows window titles in the bar, but only for floating clients.
- * This depends on code from the flexwintitle patch.
- * Note that the configuration in config.def.h for this is merely an example. If combined
- * with the corresponding hidden patch then these two will overlap unless the width of the
- * modules are controlled.
- */
-#define BAR_WINTITLE_FLOATING_PATCH 0
-
-/* Shows window titles in the bar, but only for floating clients.
- * This depends on code from the flexwintitle patch.
- * Note that the configuration in config.def.h for this is merely an example. If combined
- * with the corresponding floating patch then these two will overlap unless the width of the
- * modules are controlled.
- */
-#define BAR_WINTITLE_HIDDEN_PATCH 0
-
-/* Title bar modules such as wintitle (default), fancybar and awesomebar
- * do not by default add left and/or right padding as they take up the
- * remaining space. These options allow you explicitly add padding should
- * you need it.
- */
-#define BAR_TITLE_RIGHT_PAD_PATCH 0
-#define BAR_TITLE_LEFT_PAD_PATCH 0
-
-/**
- * Bar options
- */
-
-/* This patch changes the rectangle indicating if a tag is used by a client into a bar
- * above the tag name for better visibility.
- * Set the tagindicatortype variable in config.h to INDICATOR_TOP_BAR to enable this.
- * https://dwm.suckless.org/patches/activetagindicatorbar/
- */
-#define BAR_ACTIVETAGINDICATORBAR_PATCH N/A
-
-/* Alternative patch to the activetagindicatorbar patch, adds the bar below the tag
- * icon rather than above.
- * Set the tagindicatortype variable in config.h to INDICATOR_BOTTOM_BAR to enable this.
- */
-#define BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH N/A
-
-/* The alpha patch adds transparency for the status bar.
- * You need to uncomment the corresponding line in config.mk to use the -lXrender library
- * when including this patch.
- * https://dwm.suckless.org/patches/alpha/
- */
-#define BAR_ALPHA_PATCH 0
-
-/* This patch introduces alternative tags which can be switched on the fly for the
- * sole purpose of providing visual aid.
- * https://dwm.suckless.org/patches/alternativetags/
- */
-#define BAR_ALTERNATIVE_TAGS_PATCH 0
-
-/* This patches provides the ability to use alternative text for tags which contain at
- * least one window.
- * https://dwm.suckless.org/patches/alttagsdecoration/
- */
-#define BAR_ALTTAGSDECORATION_PATCH 0
-
-/* This patch enables dwm to manage external status bars such as lemonbar and polybar.
- * dwm treats the external bar as it would its own, so all regular dwm commands such as
- * togglebar affect the external bar in the same way.
- *
- * NB: Unless you want both anybar + dwm bar(s) then the recommendation is to disable all
- * bar modules and have { -2 } in the barrules.
- *
- * https://dwm.suckless.org/patches/anybar/
- */
-#define BAR_ANYBAR_PATCH 0
-
-/* Anybar option to place the next bar depending on previous bar's position (top or bottom) */
-#define BAR_ANYBAR_TOP_AND_BOTTOM_BARS_PATCH 0
-
-/* Anybar option to let dwm manage the width of the bar */
-#define BAR_ANYBAR_MANAGE_WIDTH_PATCH 0
-
-/* This patch adds a border around the status bar(s) just like the border of client windows.
- * https://codemadness.org/paste/dwm-border-bar.patch
- */
-#define BAR_BORDER_PATCH 0
-
-/* This patch centers the WM_NAME of the currently selected window on the status bar.
- * This is compatible with the wintitle, bartabgroups, flexwintitle and awesomebar bar
- * modules.
- * https://dwm.suckless.org/patches/centeredwindowname/
- */
-#define BAR_CENTEREDWINDOWNAME_PATCH 0
-
-/* Draws a dot indicator overlayed on each tag icon for each client. The selected client
- * is drawn as a larger horizontal line.
- * Set the tagindicatortype variable in config.h to INDICATOR_CLIENT_DOTS to enable this.
- * https://dwm.suckless.org/patches/clientindicators/
- */
-#define BAR_CLIENTINDICATOR_PATCH N/A
-
-/* Updates the position of dmenu to match that of the bar. I.e. if topbar is 0 then dmenu
- * will appear at the bottom and if 1 then dmenu will appear at the top.
- * https://dwm.suckless.org/patches/dmenumatchtop
- */
-#define BAR_DMENUMATCHTOP_PATCH 0
-
-/* Originally this was the extrabar patch, but as the handling of extra bars is now built-in
- * only the splitting of the status by a designated separator remains. As such this has been
- * renamed to more accurately reflect what it does - creating an extra status.
- * https://dwm.suckless.org/patches/extrabar/
- */
-#define BAR_EXTRASTATUS_PATCH 0
-
-/* Adds EWMH support for _NET_NUMBER_OF_DESKTOPS, _NET_CURRENT_DESKTOP, _NET_DESKTOP_NAMES
- * and _NET_DESKTOP_VIEWPORT, which allows for compatibility with other bars and programs
- * that request workspace information. For example polybar's xworkspaces module.
- *
- * This patch also includes support for adding the _IS_FLOATING property for floating windows
- * allowing for compositors to treat floating windows differently to tiled windows.
- *
- * E.g. this setting makes picom only render shadows for floating windows:
- *
- *     shadow-exclude = [ "! _IS_FLOATING@:32c = 1" ];
- *
- * https://github.com/bakkeby/dwm-flexipatch/issues/50 (_IS_FLOATING patch)
- * https://dwm.suckless.org/patches/ewmhtags/
- */
-#define BAR_EWMHTAGS_PATCH 1
-
-/* Allows the bar height to be explicitly set rather than being derived from font.
- * https://dwm.suckless.org/patches/bar_height/
- */
-#define BAR_HEIGHT_PATCH 0
-
-/* This patch prevents dwm from drawing tags with no clients (i.e. vacant) on the bar.
- * https://dwm.suckless.org/patches/hide_vacant_tags/
- */
-#define BAR_HIDEVACANTTAGS_PATCH 1
-
-/* With this patch dwm's built-in status bar is only shown when HOLDKEY is pressed
- * and the bar will now overlay the display.
- * http://dwm.suckless.org/patches/holdbar/
- */
-#define BAR_HOLDBAR_PATCH 0
-
-/* Sometimes dwm crashes when it cannot render some glyphs in window titles (usually emoji).
- * This patch is essentially a hack to ignore any errors when drawing text on the status bar.
- * https://groups.google.com/forum/m/#!topic/wmii/7bncCahYIww
- * https://docs.google.com/viewer?a=v&pid=forums&srcid=MDAwODA2MTg0MDQyMjE0OTgzMzMBMDQ3ODQzODkyMTU3NTAyMTMxNTYBX2RUMVNtOUtDQUFKATAuMQEBdjI&authuser=0
- */
-#define BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH 1
-
-/* This patch adds back in the workaround for a BadLength error in the Xft library when color
- * glyphs are used. This is for systems that do not have an updated version of the Xft library
- * (or generally prefer monochrome fonts).
- */
-#define BAR_NO_COLOR_EMOJI_PATCH 0
-
-/* This patch adds vertical and horizontal space between the statusbar and the edge of the screen.
- * https://dwm.suckless.org/patches/barpadding/
- */
-#define BAR_PADDING_PATCH 0
-
-/* Same as barpadding patch but specifically tailored for the vanitygaps patch in that the outer
- * bar padding is derived from the vanitygaps settings. In addition to this the bar padding is
- * toggled in unison when vanitygaps are toggled. Increasing or decreasing gaps during runtime
- * will not affect the bar padding.
- */
-#define BAR_PADDING_VANITYGAPS_PATCH 0
-
-/* This patch adds simple markup for status messages using pango markup.
- * This depends on the pango library v1.44 or greater.
- * You need to uncomment the corresponding lines in config.mk to use the pango libraries
- * when including this patch.
- *
- * Note that the pango patch does not protect against the BadLength error from Xft
- * when color glyphs are used, which means that dwm will crash if color emoji is used.
- *
- * If you need color emoji then you may want to install this patched library from the AUR:
- * https://aur.archlinux.org/packages/libxft-bgra/
- *
- * A long term fix for the libXft library is pending approval of this pull request:
- * https://gitlab.freedesktop.org/xorg/lib/libxft/-/merge_requests/1
- *
- * Also see:
- * https://developer.gnome.org/pygtk/stable/pango-markup-language.html
- * https://lists.suckless.org/hackers/2004/17285.html
- * https://dwm.suckless.org/patches/pango/
- */
-#define BAR_PANGO_PATCH 1
-
-/* This patch allows the status text to be fixed to the bar on a specific
- * monitor rather than being drawn on the focused monitor.
- * The statusallmons patch takes precedence over this patch.
- * https://dwm.suckless.org/patches/staticstatus/
- */
-#define BAR_STATICSTATUS_PATCH 0
-
-/* This patch draws and updates the statusbar on all monitors.
- * https://dwm.suckless.org/patches/statusallmons/
- */
-#define BAR_STATUSALLMONS_PATCH 0
-
-/* This patch enables colored text in the status bar. It changes the way colors are defined
- * in config.h allowing multiple color combinations for use in the status script.
- * This patch is incompatible with and takes precedence over the status2d patch.
- *
- * This patch is compatible with the statuscmd patch with the caveat that the first 16 markers
- * are reserved for status colors restricting block signals to 17 through 31.
- *
- * https://dwm.suckless.org/patches/statuscolors/
- */
-#define BAR_STATUSCOLORS_PATCH 0
-
-/* This patch adds configuration options for horizontal and vertical padding in the status bar.
- * https://dwm.suckless.org/patches/statuspadding/
- */
-#define BAR_STATUSPADDING_PATCH 0
-
-/* This patch adds the ability for dwm to read colors from the linux virtual console.
- *    /sys/module/vt/parameters/default_{red,grn,blu}
- * Essentially this way the colors you use in your regular tty is "mirrored" to dwm.
- * https://dwm.suckless.org/patches/vtcolors/
- */
-#define BAR_VTCOLORS_PATCH 0
-
-/* This patch allows client windows to be hidden. This code was originally part of awesomebar,
- * but has been separated out so that other bar modules can take advantage of it.
- * Both awesomebar and bartabgroups patches depend on this patch and it will be auto-enabled
- * during compile time if it is needed. Note that if using flexipatch-finalizer this must be
- * explicitly enabled.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-barmodules-wintitleactions-6.2.diff
- */
-#define BAR_WINTITLEACTIONS_PATCH BAR_AWESOMEBAR_PATCH || BAR_TABGROUPS_PATCH || BAR_FLEXWINTITLE_PATCH
-
-/***
- * Other patches
- */
-
-/* Adds a window task switcher toggled using alt-tab.
- * https://dwm.suckless.org/patches/alt-tab/
- */
-#define ALT_TAB_PATCH 0
-
-/* All floating windows are centered, like the center patch, but without a rule.
- * The center patch takes precedence over this patch.
- * This patch interferes with the center transient windows patches.
- * https://dwm.suckless.org/patches/alwayscenter/
- */
-#define ALWAYSCENTER_PATCH 0
-
-/* This patch allows windows to be resized with its aspect ratio remaining constant.
- * https://dwm.suckless.org/patches/aspectresize/
- */
-#define ASPECTRESIZE_PATCH 0
-
-/* This patch adds new clients above the selected client, instead of always
- * becoming the new master. This behaviour is known from Xmonad.
- * This patch takes precedence over ATTACHASIDE_PATCH.
- * https://dwm.suckless.org/patches/attachabove/
- */
-#define ATTACHABOVE_PATCH 0
-
-/* This patch adds new clients on top of the stack.
- * This patch takes precedence over ATTACHBELOW_PATCH.
- * https://dwm.suckless.org/patches/attachaside/
- */
-#define ATTACHASIDE_PATCH 0
-
-/* This patch adds new clients below the selected client.
- * This patch takes precedence over ATTACHBOTTOM_PATCH.
- * https://dwm.suckless.org/patches/attachbelow/
- */
-#define ATTACHBELOW_PATCH 0
-
-/* This patch adds new clients at the bottom of the stack.
- * https://dwm.suckless.org/patches/attachbottom/
- */
-#define ATTACHBOTTOM_PATCH 1
-
-/* This patch will make dwm run "~/.local/share/dwm/autostart_blocking.sh" and
- * "~/.local/share/dwm/autostart.sh &" before entering the handler loop. One or
- * both of these files can be ommited. Note the path inside .local/share rather
- * than the original ~/.dwm folder.
- * https://dwm.suckless.org/patches/autostart/
- */
-#define AUTOSTART_PATCH 0
-
-/* By default, windows that are not visible when requesting a resize/move will not
- * get resized/moved. With this patch, they will.
- * https://dwm.suckless.org/patches/autoresize/
- */
-#define AUTORESIZE_PATCH 0
-
-/* This patch adds proper support for Right-To-Left languages. (such as Farsi, Arabic or Hebrew).
- *
- * You need to uncomment the corresponding lines in config.mk to use the -lfribidi library
- * when including this patch.
- *
- * This patch depends on the following additional library:
- *    - fribidi
- *
- * https://dwm.suckless.org/patches/bidi/
- */
-#define BIDI_PATCH 0
-
-/* This patch adds an iscentered rule to automatically center clients on the current monitor.
- * This patch takes precedence over centeredwindowname, alwayscenter and fancybar patches.
- * https://dwm.suckless.org/patches/center/
- */
-#define CENTER_PATCH 1
-
-/* A transient window is one that is meant to be short lived and is usually raised by a
- * parent window. Such windows are typically dialog boxes and the like.
- * It should be noted that in dwm transient windows are not subject to normal client rules
- * and they are always floating by default.
- * This patch centers transient windows on the screen like the center patch does. Note that
- * the 6.2 center patch piggy-backed on the updatewindowtype function to ensure that all
- * dialog boxes were centered, transient or not. This function was removed in relation to
- * adding wintype as a client rule filter, hence this no longer works out of the box. This
- * patch restores previous behaviour with the center patch.
- */
-#define CENTER_TRANSIENT_WINDOWS_PATCH 0
-
-/* As above, except that the transient window is centered within the position of the parent
- * window, rather than at the center of the screen. This takes precedence over the above patch.
- */
-#define CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH 1
-
-/* This patch provides the ability to assign different weights to clients in their
- * respective stack in tiled layout.
- * https://dwm.suckless.org/patches/cfacts/
- */
-#define CFACTS_PATCH 0
-
-/* This patch allows color attributes to be set through the command line.
- * https://dwm.suckless.org/patches/cmdcustomize/
- */
-#define CMDCUSTOMIZE_PATCH 0
-
-/* This patch tweaks the tagging interface so that you can select multiple tags for tag
- * or view by pressing all the right keys as a combo. For example to view tags 1 and 3,
- * hold MOD and then press and hold 1 and 3 together.
- * https://dwm.suckless.org/patches/combo/
- */
-#define COMBO_PATCH 0
-
-/* Allow dwm to execute commands from autostart array in your config.h file. When dwm exits
- * then all processes from autostart array will be killed.
- * https://dwm.suckless.org/patches/cool_autostart/
- */
-#define COOL_AUTOSTART_PATCH 1
-
-/* The cyclelayouts patch lets you cycle through all your layouts.
- * https://dwm.suckless.org/patches/cyclelayouts/
- */
-#define CYCLELAYOUTS_PATCH 0
-
-/* Make dwm respect _MOTIF_WM_HINTS property, and not draw borders around windows requesting
- * for it. Some applications use this property to notify window managers to not draw window
- * decorations.
- * Not respecting this property leads to issues with applications that draw their own borders,
- * like chromium (with "Use system title bar and borders" turned off) or vlc in fullscreen mode.
- * https://dwm.suckless.org/patches/decoration_hints/
- */
-#define DECORATION_HINTS_PATCH 0
-
-/* This feature distributes all clients on the current monitor evenly across all tags.
- * It is a variant of the reorganizetags patch.
- * https://dwm.suckless.org/patches/reorganizetags/
- */
-#define DISTRIBUTETAGS_PATCH 0
-
-/* By default dwm will terminate on color allocation failure and the behaviour is intended to
- * catch and inform the user of color configuration issues.
- *
- * Some patches like status2d and xresources / xrdb can change colours during runtime, which
- * means that if a color can't be allocated at this time then the window manager will abruptly
- * terminate.
- *
- * This patch will ignore color allocation failures and continue on as normal. The effect of
- * this is that the existing color, that was supposed to be replaced, will remain as-is.
- */
-#define DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH 0
-
-/* Similarly to the dragmfact patch this allows you to click and drag clients to change the
- * cfact to adjust the client's size in the stack. This patch depends on the cfacts patch.
- */
-#define DRAGCFACT_PATCH 0
-
-/* This patch lets you resize the split in the tile layout (i.e. modify mfact) by holding
- * the modkey and dragging the mouse.
- * This patch can be a bit wonky with other layouts, but generally works.
- * https://dwm.suckless.org/patches/dragmfact/
- */
-#define DRAGMFACT_PATCH 0
-
-/* Simple dwmc client using a fork of fsignal to communicate with dwm.
- * To use this either copy the patch/dwmc shell script to somewhere in your path or
- * uncomment the following line in Makefile:
- *    #cp -f patch/dwmc ${DESTDIR}${PREFIX}/bin
- * http://dwm.suckless.org/patches/dwmc/
- */
-#define DWMC_PATCH 0
-
-/* This patch allows no tag at all to be selected. The result is that dwm will start with
- * no tag selected and when you start a client with no tag rule and no tag selected then
- * it will be opened on the first tag.
- * https://dwm.suckless.org/patches/emptyview/
- */
-#define EMPTYVIEW_PATCH 0
-
-/* This patch allows the user to change size and placement of floating windows using only the
- * keyboard. It also allows for temporary vertical and horizontal extension of windows similar
- * to other WMs fill command.
- * https://dwm.suckless.org/patches/exresize/
- */
-#define EXRESIZE_PATCH 0
-
-/* Only allow clients to "fullscreen" into the space currently given to them.
- * As an example, this will allow you to view a fullscreen video in your browser on
- * one half of the screen, while having the other half available for other tasks.
- * This patch takes precedence over the fakefullscreen client patch below.
- * https://dwm.suckless.org/patches/fakefullscreen/
- */
-#define FAKEFULLSCREEN_PATCH 0
-
-/* Similarly to the fakefullscreen patch this patch only allows clients to "fullscreen" into
- * the space currently given to them.
- * The "twist" with this patch is that fake fullscreen can be toggled on a per client basis
- * rather than applying to all clients globally.
- * Also see the selectivefakefullscreen option that adds a rule option to enabled this on client
- * startup.
- */
-#define FAKEFULLSCREEN_CLIENT_PATCH 0
-
-/* This patch adds a float rule allowing the size and position of floating windows to be specified
- * It also allows the size and position of floating windows to be controlled similar to the
- * exresize, moveresize, and moveplace patches.
- * The size and position can be specified using absolute, relative or fixed co-ordinates and
- * https://github.com/bakkeby/patches/wiki/floatpos/
- */
-#define FLOATPOS_PATCH 1
-
-/* Add-on functionality for the above: make the float positions respect outer (vanity)gaps. */
-#define FLOATPOS_RESPECT_GAPS_PATCH 0
-
-/* This patch provides the ability to focus the tag on the immediate left or right of the
- * currently focused tag. It also allows to send the focused window either on the left or
- * the right tag.
- * http://dwm.suckless.org/patches/focusadjacenttag/
- */
-#define FOCUSADJACENTTAG_PATCH 0
-
-/* Allows focusing on clients based on direction (up, down, left, right) instead of client order.
- * https://github.com/bakkeby/patches/wiki/focusdir/
- */
-#define FOCUSDIR_PATCH 1
-
-/* When changing tags, closing windows or moving clients out of view then focus will revert to the
- * client window that remains under the mouse cursor rather than the most recently focused window.
- * https://github.com/bakkeby/patches/wiki/focusfollowmouse
- */
-#define FOCUSFOLLOWMOUSE_PATCH 0
-
-/* A simple patch that just puts focus back to the master client.
- * https://dwm.suckless.org/patches/focusmaster/
- */
-#define FOCUSMASTER_PATCH 0
-
-/* A variant of the focusmaster patch that additionally allows the focus to be returned to the
- * previously focused client
- * https://dwm.suckless.org/patches/focusmaster/
- */
-#define FOCUSMASTER_RETURN_PATCH 0
-
-/* Switch focus only by mouse click and not sloppy (focus follows mouse pointer).
- * https://dwm.suckless.org/patches/focusonclick/
- */
-#define FOCUSONCLICK_PATCH 1
-
-/* Selects the next window having the urgent flag regardless of the tag it is on.
- * The urgent flag can be artificially set with the following xdotool command on any window:
- *   xdotool selectwindow -- set_window --urgency 1
- * https://dwm.suckless.org/patches/focusurgent/
- */
-#define FOCUSURGENT_PATCH 0
-
-/* By default, dwm responds to _NET_ACTIVE_WINDOW client messages by setting
- * the urgency bit on the named window. This patch activates the window instead.
- * https://dwm.suckless.org/patches/focusonnetactive/
- */
-#define FOCUSONNETACTIVE_PATCH 0
-
-/* Send "fake signals" to dwm for handling, using xsetroot. This will not conflict with the
- * status bar, which also is managed using xsetroot.
- * Also see the dwmc patch, which takes precedence over this patch.
- * https://dwm.suckless.org/patches/fsignal/
- */
-#define FSIGNAL_PATCH 0
-
-/* Applies the monocle layout with the focused client on top and hides the bar. When pressed
- * again it shows the bar and restores the layout that was active before going fullscreen.
- * https://dwm.suckless.org/patches/fullscreen/
- */
-#define FULLSCREEN_PATCH 0
-
-/* This patch provides a keybinding to rotate all clients in the currently selected
- * area (master or stack) without affecting the other area.
- * https://dwm.suckless.org/patches/inplacerotate/
- */
-#define INPLACEROTATE_PATCH 0
-
-/* This patch lets you define custom insets from each edge of the screen. One use case would be
- * to arrange space for an external bar.
- * https://dwm.suckless.org/patches/insets/
- */
-#define INSETS_PATCH 0
-
-/* This patch (v1.5.7) implements inter-process communication through a UNIX socket for dwm. This
- * allows for the window manager to be queried for information, e.g. listen for events such as tag
- * or layout changes, as well as send commands to control the window manager via other programs.
- *
- * You need to uncomment the corresponding lines in config.mk to use the -lyajl library
- * when including this patch.
- * This patch depends on the following additional library:
- *    - yajl
- *
- * https://github.com/mihirlad55/dwm-ipc
- * https://dwm.suckless.org/patches/ipc/
- */
-#define IPC_PATCH 0
-
-/* Adds rule option for clients to avoid accidental termination by killclient for sticky windows.
- * https://dwm.suckless.org/patches/ispermanent/
- */
-#define ISPERMANENT_PATCH 0
-
-/* This patch adds key modes (like in vim or emacs) where chains of keyboard shortcuts
- * can be performed.
- * https://dwm.suckless.org/patches/keymodes/
- */
-#define KEYMODES_PATCH 0
-
-/* This patch adds a keybinding to kills all visible clients that are not selected.
- * https://dwm.suckless.org/patches/killunsel/
- */
-#define KILLUNSEL_PATCH 0
-
-/* This changes the window manager name to LG3d instead of dwm as a workaround for Java
- * applications that assume that the window manager is using window reparenting.
- * Refer to the ISSUES secton of the dwm man page for more details.
- */
-#define LG3D_PATCH 0
-
-/* By default in dwm it is possible to make an application fullscreen, then use
- * the focusstack keybindings to focus on other windows beneath the current window.
- * It is also possible to spawn new windows (e.g. a terminal) that end up getting
- * focus while the previous window remains in fullscreen. This patch ensures that
- * in such scenarios the previous window loses fullscreen.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-losefullscreen-6.2.diff
- */
-#define LOSEFULLSCREEN_PATCH 1
-
-/* This patch adds helper functions for maximizing, horizontally and vertically, floating
- * windows using keybindings.
- * https://dwm.suckless.org/patches/maximize/
- */
-#define MAXIMIZE_PATCH 0
-
-/* Control Music Player Daemon via keybinds.
- * You need to uncomment the corresponding line in config.mk to use the -lmpdclient library
- * when including this patch.
- * This patch depends on the following additional library:
- *    - libmpdclient
- * https://dwm.suckless.org/patches/mpdcontrol/
- */
-#define MPDCONTROL_PATCH 0
-
-/* Adds rules per monitor, e.g. have default layouts per monitor.
- * The use case for this is if the second monitor is vertical (i.e. rotated) then
- * you may want to use a different default layout for this monitor than what is
- * used for the main monitor. E.g. normal vertical split for main monitor and
- * horizontal split for the second.
- */
-#define MONITOR_RULES_PATCH 0
-
-/* Always display the the monocle-symbol as defined in config.h if the monocle-layout
- * is activated. Do not display the number of open clients in the current tag.
- * https://dwm.suckless.org/patches/monoclesymbol/
- */
-#define MONOCLESYMBOL_PATCH 0
-
-/* Makes a window floating and 1/3rd the height and 1/3rd the width of the screen and is
- * positioned in either the center or one of the 8 cardinal directions depending on which
- * key is pressed.
- * https://dwm.suckless.org/patches/moveplace/
- */
-#define MOVEPLACE_PATCH 0
-
-/* This patch allows you to move and resize dwm's clients using keyboard bindings.
- * https://dwm.suckless.org/patches/moveresize/
- */
-#define MOVERESIZE_PATCH 0
-
-/* This patch allows you to move clients around in the stack and swap them with the master.
- * https://dwm.suckless.org/patches/movestack/
- */
-#define MOVESTACK_PATCH 0
-
-/* This patch allows you to change the names of tags during runtime.
- *
- * This is a bespoke version implemented specifically in relation to tagicons, which is integrated
- * into dwm-flexipatch. By default it uses dmenu to retrieve the new name, but this can be
- * customised via config along with the maximum text length and the format string.
- *
- * Special behaviour:
- *    - if more than one tag is selected then the name change applies to all selected tags
- *    - if tagicons is configured to have unique tags per monitor then the change only applies
- *      for the current monitor
- *    - the name change applies to the tag set that is active for the current tag:
- *       * if used in combination with BAR_ALTTAGSDECORATION_PATCH and there are clients on the
- *         given tag then the name change only applies to the ALT_TAGS_DECORATION tag set
- *       * if used in combination with the BAR_ALTERNATIVE_TAGS_PATCH and alternative tags are
- *         shown then the name change only applies to the ALTERNATIVE_TAGS tag set
- *       * if used in combination with both then BAR_ALTTAGSDECORATION_PATCH takes precedence
- *       * otherwise the name change applies to the DEFAULT_TAGS tag set
- *
- * https://dwm.suckless.org/patches/nametag/
- */
-#define NAMETAG_PATCH 0
-
-/* Variant of the above which prepends the tag number to the given string.
- * The toggle does nothing on its own and need to be enabled in combination with the above. */
-#define NAMETAG_PREPEND_PATCH 0
-
-/* Adds support for the _NET_CLIENT_LIST_STACKING atom, needed by certain applications like the
- * Zoom video conferencing application.
- * https://github.com/bakkeby/patches/wiki/netclientliststacking/
- */
-#define NET_CLIENT_LIST_STACKING_PATCH 1
-
-/* Removes the border when there is only one window visible.
- * https://dwm.suckless.org/patches/noborder/
- */
-#define NOBORDER_PATCH 0
-
-/* Enable modifying or removing dmenu in config.def.h which resulted previously in a
- * compilation error because two lines of code hardcode dmenu into dwm.
- * https://dwm.suckless.org/patches/nodmenu/
- */
-#define NODMENU_PATCH 1
-
-/* This patch allows for toggleable client button bindings that have no modifiers.
- * This can, for example, allow you to move or resize using the mouse alone without holding
- * down a modifier key. This can be practical if you have extra buttons on your mouse.
- * While you can use button bindings with no modifiers without this patch in a bare dwm,
- * those buttons are then unavailable for use within the application itself so being able to
- * toggle these on and off can be necessary in certain situations (e.g. being able to use
- * back and forward buttons in a browser).
-
- * Example bindings:
- *     { ClkClientWin,              0,              Button8,        movemouse,      {0} },
- *     { ClkClientWin,              0,              Button9,        resizemouse,    {0} },
- */
-#define NO_MOD_BUTTONS_PATCH 0
-
-/* When terminals have transparency then their borders also become transparent.
- * This patch ensures that borders have no transparency. Note that this patch is
- * only relevant if you are not using the alpha patch.
- * https://github.com/szatanjl/dwm/commit/1529909466206016f2101457bbf37c67195714c8
- * https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff
- */
-#define NO_TRANSPARENT_BORDERS_PATCH 1
-
-/* Port of InstantWM's on_empty_keys functionality allowing keybindings that apply only when
- * a tag is empty. An example use case is being able to launch applications with first hand
- * keys like "f" to launch firefox.
- *
- * https://github.com/instantOS/instantWM/
- * https://github.com/bakkeby/dwm-flexipatch/issues/51
- */
-#define ON_EMPTY_KEYS_PATCH 0
-
-/* Minor patch that prevents more than one rule being matched for a given client. */
-#define ONLY_ONE_RULE_MATCH_PATCH 0
-
-/* This patch makes it so dwm will only exit via quit() if no windows are open.
- * This is to prevent you accidentally losing all your work.
- * https://dwm.suckless.org/patches/onlyquitonempty/
- */
-#define ONLYQUITONEMPTY_PATCH 0
-
-/* The pertag patch adds nmaster, mfacts and layouts per tag rather than per
- * monitor (default).
- * https://dwm.suckless.org/patches/pertag/
- */
-#define PERTAG_PATCH 1
-
-/* Option to enable gaps on a per tag basis rather than globally.
- * Depends on both pertag and vanitygaps patches being enabled.
- */
-#define PERTAG_VANITYGAPS_PATCH 0
-
-/* This patch allows configuring vanity gaps on a per-monitor basis rather than
- * all monitors (default).
- */
-#define PERMON_VANITYGAPS_PATCH 0
-
-/* This controls whether or not to also store bar position on a per
- * tag basis, or leave it as one bar per monitor.
- */
-#define PERTAGBAR_PATCH 0
-
-/* This patch lets you change the position of a client in the stack using the mouse.
- * https://github.com/bakkeby/patches/wiki/placemouse
- */
-#define PLACEMOUSE_PATCH 0
-
-/* This patch provides a way to move clients up and down inside the client list.
- * https://dwm.suckless.org/patches/push/
- */
-#define PUSH_PATCH 0
-
-/* This patch provides a way to move clients up and down inside the client list,
- * but does not push up or down into the master area (except that it does not take
- * nmaster into account).
- * This takes precedence over the push patch above.
- * https://dwm.suckless.org/patches/push/
- */
-#define PUSH_NO_MASTER_PATCH 0
-
-/* Variant of the named scratchpads patch allowing scratch keys to be added or removed
- * on demand, allowing multiple scratchpad windows to be toggled into and out of view
- * in unison, as well as including multi-monitor support.
- *
- * https://github.com/bakkeby/patches/wiki/renamedscratchpads
- */
-#define RENAMED_SCRATCHPADS_PATCH 1
-
-/* Renamed scratchpads option to auto-hide scratchpads when moving to a different tag.
- * This behaviour is similar to that of the (multiple) scratchpads patch. */
-#define RENAMED_SCRATCHPADS_AUTO_HIDE_PATCH 0
-
-/* Shifts all clients per tag to leftmost unoccupied tags.
- *
- * For example, if clients A, B, C are tagged on tags 1, 5, 9 respectively, when
- * this function is called, they will now be on 1, 2, and 3. The focused client
- * will also remain focused.
- *
- * Clients on multiple tags will be treated as if they only were only on their
- * leftmost tag, and will be reduced to one tag after the operation is complete.
- * https://dwm.suckless.org/patches/reorganizetags/
- */
-#define REORGANIZETAGS_PATCH 0
-
-/* By default, windows only resize from the bottom right corner. With this
- * patch the mouse is warped to the nearest corner and you resize from there.
- * https://dwm.suckless.org/patches/resizecorners/
- */
-#define RESIZECORNERS_PATCH 0
-
-/* Practically the same as resizecorners, but the cursor does not warp to corners.
- * This takes precedence over the resizecorners patch.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-resizepoint-6.2.diff
- */
-#define RESIZEPOINT_PATCH 1
-
-/* Adds a keyboard shortcut to restart dwm or alternatively by using kill -HUP dwmpid.
- * Additionally dwm can quit cleanly by using kill -TERM dwmpid.
- * https://dwm.suckless.org/patches/restartsig/
- */
-#define RESTARTSIG_PATCH 1
-
-/* Adds rio-like drawing to resize the selected client.
- * This depends on an external tool slop being installed.
- * This patch was backported from instantWM.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-riodraw-6.2.diff
- */
-#define RIODRAW_PATCH 0
-
-/* This patch let's you rotate through the stack using keyboard shortcuts.
- * https://dwm.suckless.org/patches/rotatestack/
- */
-#define ROTATESTACK_PATCH 0
-
-/* This patch adds rounded corners to client windows in dwm.
- * You need to uncomment the corresponding line in config.mk to use the -lXext library
- * when including this patch. You will also want to set "borderpx = 0;" in your config.h.
- * https://github.com/mitchweaver/suckless/blob/master/dwm/patches/mitch-06-rounded_corners-f04cac6d6e39cd9e3fc4fae526e3d1e8df5e34b2.patch
- */
-#define ROUNDED_CORNERS_PATCH 0
-
-/* This patch saves size and position of every floating window before it is forced
- * into tiled mode. If the window is made floating again then the old dimensions
- * will be restored.
- * https://dwm.suckless.org/patches/save_floats/
- */
-#define SAVEFLOATS_PATCH 1
-
-/* The scratchpad patch allows you to spawn or restore floating terminal windows.
- * It is typically useful when one need to do some short typing.
- *
- * Note that this patch changes TAGMASK to make room for special scratchpad tags,
- * so ~0 does more than select all tags with this patch. Code that relies on ~0 to
- * represent all tags should use ~SPTAGMASK instead.
- *
- * Upgraded to Christian Tenllado's multiple scratchpad version.
- * https://lists.suckless.org/hackers/2004/17205.html
- * https://dwm.suckless.org/patches/scratchpads/
- */
-#define SCRATCHPADS_PATCH 0
-
-/* Minor alteration of the above allowing clients to keep their size and position when shown */
-#define SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH 0
-
-/* This alternative patch enables a scratchpad feature in dwm similar to the scratchpad
- * feature in i3wm.
- * https://github.com/GasparVardanyan/dwm-scratchpad
- */
-#define SCRATCHPAD_ALT_1_PATCH 0
-
-/* This patch persists some settings across window manager restarts. These include but are not
- * limited to:
- *    - client's assigned tag(s) on which monitor
- *    - the order of clients
- *    - nmaster
- *    - selected layout
- *    - plus various additions depending on what other patches are used
- *
- * The above is not persisted across reboots, however.
- */
-#define SEAMLESS_RESTART_PATCH 1
-
-/* As opposed to the original patch this only adds a rule option allowing fake fullscreen
- * to be enabled for applications when they start. This is intended to be used in combination
- * with the fakefullscreenclient patch and offers no practical functionality without it.
- * https://dwm.suckless.org/patches/selectivefakefullscreen/
- */
-#define SELECTIVEFAKEFULLSCREEN_PATCH 0
-
-/* Allows restarting dwm without the dependency of an external script.
- * https://dwm.suckless.org/patches/selfrestart/
- */
-#define SELFRESTART_PATCH 0
-
-/* Floating windows being sent to another monitor will be centered.
- * https://dwm.suckless.org/patches/sendmoncenter/
- */
-#define SENDMON_CENTER_PATCH 0
-
-/* This patch allow clients to keep focus when being sent to another monitor.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-sendmon_keepfocus-6.2.diff
- */
-#define SENDMON_KEEPFOCUS_PATCH 1
-
-/* This patch allows border pixels to be changed during runtime.
- * https://dwm.suckless.org/patches/setborderpx/
- */
-#define SETBORDERPX_PATCH 0
-
-/* Combines shifttag and shiftview. Basically moves the window to the next/prev tag and follows it.
- * Also see the focusadjacenttag patch.
- * https://dwm.suckless.org/patches/shift-tools/
- */
-#define SHIFTBOTH_PATCH 0
-
-/* Swaps all the clients on the current tag with all the client on the next/prev tag.
- * Depends on the swaptags patch.
- * https://dwm.suckless.org/patches/shift-tools/
- */
-#define SHIFTSWAPTAGS_PATCH 0
-
-/* Moves the current selected client to the adjacent tag.
- * Also see the focusadjacenttag patch.
- * https://dwm.suckless.org/patches/shift-tools/
- */
-#define SHIFTTAG_PATCH 0
-
-/* Moves the current selected client to the adjacent tag that has at least one client, if none
- * then it acts as shifttag.
- * https://dwm.suckless.org/patches/shift-tools/
- */
-#define SHIFTTAGCLIENTS_PATCH 0
-
-/* This patch adds keybindings for left and right circular shift through tags.
- * https://github.com/chau-bao-long/dotfiles/blob/master/suckless/dwm/shiftview.diff
- */
-#define SHIFTVIEW_PATCH 0
-
-/* This variant of the shiftview patch adds left and right circular shift through tags,
- * but skips tags where there are no clients.
- */
-#define SHIFTVIEW_CLIENTS_PATCH 0
-
-/* This patch makes dwm obey even "soft" sizehints for new clients. Any window
- * that requests a specific initial size will be floated and set to that size.
- * Unlike with "fixed size" windows, you are able to resize and/or unfloat these
- * windows freely - only the initial state is affected.
- * This version of the patch is honestly of limited utility since there are many
- * clients that will abuse it.
- * https://dwm.suckless.org/patches/sizehints/
- */
-#define SIZEHINTS_PATCH 0
-
-/* This patch makes dwm obey even "soft" sizehints for new clients. This ruled
- * version is essentially the same patch except it obeys the "isfloating" rule
- * if it is available in config.h for the given client.
- * https://dwm.suckless.org/patches/sizehints/
- */
-#define SIZEHINTS_RULED_PATCH 1
-
-/* This patch makes dwm obey even "soft" sizehints for new clients. The isfreesize
- * version is similar to the sizehints ruled patch except it allows you to specify
- * via client rules which clients this should apply to. Soft sizehints applies by
- * default to clients that are not ruled, and will be disabled by default for clients
- * that are.
- *
- * Example client rule enabling soft sizehints:
- *    - RULE(.wintype = WTYPE "DIALOG", .isfloating = 1, .isfreesize = 1)
- *
- * https://dwm.suckless.org/patches/sizehints/
- */
-#define SIZEHINTS_ISFREESIZE_PATCH 0
-
-/* In a multi-head setup monitor 0 is by default the primary screen, with the left and right
- * screen being monitor 1 and 2 respectively. This patch sorts screens left to right (or
- * top to bottom in a vertical layout) which aims to address some inconsistencies when it
- * comes to focusmon, tagmon and similar functionality.
- * https://www.mail-archive.com/hackers@suckless.org/msg09400.html
- */
-#define SORTSCREENS_PATCH 0
-
-/* Spawns programs from currently focused client's working directory.
- * https://dwm.suckless.org/patches/spawn_cwd/
- */
-#define SPAWNCMD_PATCH 0
-
-/* This patch provides comprehensive utilities for managing the client stack, providing
- * keyboard shortcuts for focusing or placing a client at specific positions in the stack.
- * Note that the default keybindings for this patch have been changed in dwm-flexipatch
- * due to the many conflicts with other patches. As it provides similar functionality to the
- * swapfocus patch it also uses the MOD+s shortcut to focus the previously selected client,
- * thus note a conflict between these two patches.
- * https://dwm.suckless.org/patches/stacker/
- */
-#define STACKER_PATCH 1
-
-/* Steam, and steam windows (games), trigger a ConfigureNotify request every time the window
- * gets focus. More so, the configure event passed along from Steam tends to have the wrong
- * x and y co-ordinates which can make the window, if floating, jump around the screen.
- *
- * This patch works around this age-old issue by ignoring the x and y co-ordinates for
- * ConfigureNotify requests relating to Steam windows.
- *
- * https://github.com/bakkeby/patches/wiki/steam
- */
-#define STEAM_PATCH 0
-
-/* Adds toggleable keyboard shortcut to make a client 'sticky', i.e. visible on all tags.
- * https://dwm.suckless.org/patches/sticky/
- */
-#define STICKY_PATCH 0
-
-/* This patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio.
- * Clients marked with isterminal in config.h swallow a window opened by any child process,
- * e.g. running xclock in a terminal. Closing the xclock window restores the terminal window
- * in the current position.
- *
- * This patch depends on the following additional libraries:
- *    - libxcb
- *    - Xlib-libxcb
- *    - xcb-res
- *
- * You need to uncomment the corresponding line in config.mk to use the above libraries when
- * including this patch.
- *
- * https://dwm.suckless.org/patches/swallow/
- */
-#define SWALLOW_PATCH 0
-
-/* This patch depends on the pertag patch and makes it possible to switch focus with a single
- * shortcut (MOD+s) instead of having to think if you should use mod-j or mod-k for reaching
- * the previously used window.
- * https://dwm.suckless.org/patches/swapfocus/
- */
-#define SWAPFOCUS_PATCH 0
-
-/* This patch allows swapping the contents of the currently selected tag with another tag using
- * keyboard shortcuts.
- * https://dwm.suckless.org/patches/swaptags/
- */
-#define SWAPTAGS_PATCH 0
-
-/* Switch focus between the master and stack columns using a single keybinding.
- * https://dwm.suckless.org/patches/switchcol/
- */
-#define SWITCHCOL_PATCH 0
-
-/* By default dwm allow you to set application specific rules so that you can have your browser,
- * for example, start up on tag 9 optionally on a given monitor when you open your browser it is
- * then automatically moved to the configured tag, but you have to manually enable the tag to see
- * the newly opened application.
- * This patch adds an extra configuration option for individual rules where:
- *   0 is default behaviour
- *   1 automatically moves you to the tag of the newly opened application and
- *   2 enables the tag of the newly opened application in addition to your existing enabled tags
- *   3 as 1, but closing that window reverts the view back to what it was previously (*)
- *   4 as 2, but closing that window reverts the view back to what it was previously (*)
- *
- * (*) except if the client has been moved between tags or to another monitor
- *
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-switchtag-6.2.diff
- * Also see https://dwm.suckless.org/patches/switchtotag
- */
-#define SWITCHTAG_PATCH 0
-
-/* This patch transforms the monocle layout into a "tabbed" layout if more than one window is
- * present on the monocle view. This patch has been added for demonstration purposes only and has
- * limited compatibility with other patches. It will conflict space-wise with a second bar.
- * Note that fancybar, awesomebar, bartabgroups and similar patches make the tab patch redundant.
- * https://dwm.suckless.org/patches/tab/
- */
-#define TAB_PATCH 0
-
-/* Adds keyboard shortcuts to move all (or only floating) windows from one tag to another.
- * https://dwm.suckless.org/patches/tagall/
- */
-#define TAGALL_PATCH 0
-
-/* This patch allows you to move all visible windows on a monitor to an adjacent monitor.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagallmon-6.2.diff
- */
-#define TAGALLMON_PATCH 0
-
-/* This patch makes new clients attach into the stack area when you toggle a new tag into
- * view. This means your master area will remain unchanged when toggling views.
- * The allmaster patch will cause all clients in the master area to be left alone. This patch
- * takes precedence over the onemaster tagintostack patch.
- * https://dwm.suckless.org/patches/tagintostack/
- */
-#define TAGINTOSTACK_ALLMASTER_PATCH 0
-
-/* This patch makes new clients attach into the stack area when you toggle a new tag into
- * view. This means your master area will remain unchanged when toggling views.
- * The onemaster patch will cause the first client in the master area to be left alone.
- * https://dwm.suckless.org/patches/tagintostack/
- */
-#define TAGINTOSTACK_ONEMASTER_PATCH 0
-
-/* If you try to send a fullscreen window to an adjacent monitor using tagmon then
- * the window is moved behind the scenes, but it remains in fullscreen on the original
- * monitor until you exit fullscreen view (at which point it will appear on the adjacent
- * monitor). This patch allows a fullscreen window to be moved to an adjacent monitor
- * while remaining in fullscreen.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagmonfixfs-6.2.diff
- */
-#define TAGMONFIXFS_PATCH 1
-
-/* Add functions and keybindings to tag a window to a desired tag on the next (right)
- * or previous (left) monitor from the currently selected monitor.
- * https://dwm.suckless.org/patches/tagothermonitor/
- */
-#define TAGOTHERMONITOR_PATCH 0
-
-/* This patch allows you to swap all visible windows on one monitor with those of an
- * adjacent monitor.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagswapmon-6.2.diff
- */
-#define TAGSWAPMON_PATCH 0
-
-/* Sync tag actions across all monitors.
- * This is comparable to a sort of pseudo-desktop environment.
- * Also refer to the desktop patch:
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-desktop-6.3.diff
- */
-#define TAGSYNC_PATCH 0
-
-/* This patch can be useful to the touchpad users because it allows to
- * resize windows using Mod + two-finger scroll. It is useful when
- * two-finger scrolling is configured in libinput.
- * https://dwm.suckless.org/patches/tapresize/
- */
-#define TAPRESIZE_PATCH 0
-
-/* This patch allows you to toggle fullscreen on and off using a single shortcut key.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-togglefullscreen-6.2.diff
- */
-#define TOGGLEFULLSCREEN_PATCH 1
-
-/* This patch allows for the bar position (top or bottom) to be toggled during runtime.
- * https://dwm.suckless.org/patches/toggletopbar/
- */
-#define TOGGLETOPBAR_PATCH 0
-
-/* Minor patch that lets you use the same keyboard shortcut to toggle to the previous layout if the
- * designated layout is already active.
- *
- * This allows you to use e.g. MOD+m to change to the monocle layout and use the same keybinding to
- * toggle back to what it was previously. The default behaviour in dwm forces you to use either
- * MOD+space or MOD+t to change back to tiled layout.
- *
- * https://github.com/bakkeby/patches/wiki/togglelayout
- */
-
-#define TOGGLELAYOUT_PATCH 0
-
-/* Minor patch that lets you use the same keyboard shortcut to toggle to the previous tag if the
- * designated tag is already active.
- *
- * This allows you to use e.g. MOD+4 to quickly view the 4th tag and use the same keybinding to
- * toggle back to what it was previously. The default behaviour in dwm forces you to use either
- * MOD+tab or MOD+1 to change back to the previous tag.
- *
- * Idea ref.
- * https://www.reddit.com/r/suckless/comments/ik27vd/key_toggle_between_next_and_previous_tag_dwm/
- * https://github.com/bakkeby/patches/wiki/toggletag
- */
-#define TOGGLETAG_PATCH 0
-
-/* Lets you transfer the currently focused client between the master and stack area
- * while increasing or decreasing the master area (nmaster) accordingly.
- * https://dwm.suckless.org/patches/transfer/
- */
-#define TRANSFER_PATCH 0
-
-/* Lets you transfer all clients between the master and stack area
- * while increasing or decreasing the master area (nmaster) accordingly.
- * https://dwm.suckless.org/patches/transfer/
- */
-#define TRANSFER_ALL_PATCH 0
-
-/* This patch resets isfloating on any visible windows that have it set.
- * Optionally also applies a layout.
- * https://dwm.suckless.org/patches/unfloatvisible/
- */
-#define UNFLOATVISIBLE_PATCH 1
-
-/* This patch adds a client rule that allows for windows that do not specify the override-redirect
- * to not be managed by the window manager. This can be useful for external bars, widgets,
- * launchers, docks, desktop icons and more.
- * https://github.com/bakkeby/patches/wiki/unmanaged
- */
-#define UNMANAGED_PATCH 0
-
-/* This patch adds configurable gaps between windows differentiating between outer, inner,
- * horizontal and vertical gaps.
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-vanitygaps-6.2.diff
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-cfacts-vanitygaps-6.2.diff
- */
-#define VANITYGAPS_PATCH 0
-
-/* This patch adds outer gaps for the monocle layout.
- * Most gaps patches tries to avoid gaps on the monocle layout, as it is often used as a
- * fullscreen mode, hence this is enabled separately from the main vanitygaps patch.
- */
-#define VANITYGAPS_MONOCLE_PATCH 0
-
-/* By default MOD+Tab will take the user back to the previous tag only. If the user keeps
- * using MOD+Tab then the view will switch back and forth between the current and previous tag.
- * This patch allows dwm to keep a longer history of previous tag changes such that MOD+Tab can
- * be pressed multiple times to go further back to earlier tag selections.
- *
- * The number of history elements is defined by the NUMVIEWHIST macro in dwm.c and defaults to
- * the number of tags in the system.
- */
-#define VIEW_HISTORY_PATCH 0
-
-/* Follow a window to the tag it is being moved to.
- * https://dwm.suckless.org/patches/viewontag/
- */
-#define VIEWONTAG_PATCH 0
-
-/* This patch warps the mouse cursor to the center of the currently focused window or screen
- * when the mouse cursor is (a) on a different screen or (b) on top of a different window.
- * https://dwm.suckless.org/patches/warp/
- */
-#define WARP_PATCH 0
-
-/* Sometimes a single application opens different windows depending on the task
- * at hand and this is often reflected in the WM_WINDOW_ROLE(STRING) x property.
- * This patch adds the role field to the rule configuration so that one can
- * differentiate between, say, Firefox "browser" vs "Preferences" vs "Manager"
- * or Google-chrome "browser" vs "pop-up".
- * https://github.com/bakkeby/patches/blob/master/dwm/dwm-windowrolerule-6.2.diff
- */
-#define WINDOWROLERULE_PATCH 1
-
-/* The winview patch allows switching the view to that of a given client from the all-window
- * view (Mod-0) using a keyboard shortcut.
- * http://dwm.suckless.org/patches/winview/
- */
-#define WINVIEW_PATCH 0
-
-/* Remember keyboard layout per client.
- * It is recommended that you configure xkb before using this patch as described in
- * https://www.x.org/archive/X11R7.5/doc/input/XKB-Config.html
- * https://dwm.suckless.org/patches/xkb/
- */
-#define XKB_PATCH 0
-
-/* Allows dwm to read colors from xrdb (.Xresources) during runtime. Compatible with
- * the float border color, awesomebar, urgentborder and titlecolor patches.
- * https://dwm.suckless.org/patches/xrdb/
- */
-#define XRDB_PATCH 0
-
-/* Simple patch that allows floating windows to be zoomed into the master stack position.
- * https://www.reddit.com/r/suckless/comments/ie5fe3/zoomfloating_my_own_simple_original_patch/
- */
-#define ZOOMFLOATING_PATCH 0
-
-/* The zoomswap patch allows a master and a stack window to swap places
- * rather than every window on the screen changing position.
- * https://dwm.suckless.org/patches/zoomswap/
- */
-#define ZOOMSWAP_PATCH 0
-
-/**
- * Layouts
- */
-
-/* Bottomstack layout.
- * https://dwm.suckless.org/patches/bottomstack/
- */
-#define BSTACK_LAYOUT 1
-
-/* Bottomstack horizontal layout.
- * https://dwm.suckless.org/patches/bottomstack/
- */
-#define BSTACKHORIZ_LAYOUT 0
-
-/* Centered master layout.
- * https://dwm.suckless.org/patches/centeredmaster/
- */
-#define CENTEREDMASTER_LAYOUT 1
-
-/* Centered floating master layout.
- * https://dwm.suckless.org/patches/centeredmaster/
- */
-#define CENTEREDFLOATINGMASTER_LAYOUT 0
-
-/* Same as the default tile layout except clients in the master area are arranged in
- * columns (i.e. left to right).
- * https://dwm.suckless.org/patches/columns/
- */
-#define COLUMNS_LAYOUT 0
-
-/* Deck layout.
- * https://dwm.suckless.org/patches/deck/
- */
-#define DECK_LAYOUT 1
-
-/* Fibonacci dwindle layout.
- * https://dwm.suckless.org/patches/fibonacci/
- */
-#define FIBONACCI_DWINDLE_LAYOUT 0
-
-/* Fibonacci spiral layout.
- * https://dwm.suckless.org/patches/fibonacci/
- */
-#define FIBONACCI_SPIRAL_LAYOUT 0
-
-/* Flextile deluxe layout.
- * A revamped, more flexible, and over-the-top version of the original flextile layout.
- * https://dwm.suckless.org/patches/flextile/ (original)
- */
-#define FLEXTILE_DELUXE_LAYOUT 0
-
-/* Gappless grid layout.
- * https://dwm.suckless.org/patches/gaplessgrid/
- */
-#define GAPPLESSGRID_LAYOUT 1
-
-/* Gridmode (grid) layout.
- * https://dwm.suckless.org/patches/gridmode/
- */
-#define GRIDMODE_LAYOUT 0
-
-/* Horizontal grid (horizgrid) layout.
- * https://dwm.suckless.org/patches/horizgrid/
- */
-#define HORIZGRID_LAYOUT 0
-
-/* Grid layout where nmaster controls the number of rows.
- * https://dwm.suckless.org/patches/nrowgrid/
- */
-#define NROWGRID_LAYOUT 0
-
-/* The default tile layout.
- * This can be optionally disabled in favour of other layouts.
- */
-#define TILE_LAYOUT 1
-
-/* Monocle layout (default).
- * This can be optionally disabled in favour of other layouts.
- */
-#define MONOCLE_LAYOUT 1
diff --git a/config/patches/autostart_signal.diff b/config/patches/autostart_signal.diff
deleted file mode 100644
index 70b6119..0000000
--- a/config/patches/autostart_signal.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/dwm.c
-+++ b/dwm.c
-@@ -693,7 +693,7 @@ cleanup(void)
- 	/* kill child processes */
- 	for (i = 0; i < autostart_len; i++) {
- 		if (0 < autostart_pids[i]) {
--			kill(autostart_pids[i], SIGTERM);
-+			kill(autostart_pids[i], autostart_kill_signal);
- 			waitpid(autostart_pids[i], NULL, 0);
- 		}
- 	}
diff --git a/config/patches/stext_buffer_size.diff b/config/patches/stext_buffer_size.diff
deleted file mode 100644
index 723a8c4..0000000
--- a/config/patches/stext_buffer_size.diff
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/dwm.c
-+++ b/dwm.c
-@@ -393,8 +393,8 @@ static void zoom(const Arg *arg);
- 
- /* variables */
- static const char broken[] = "broken";
--static char stext[1024];
--static char rawstext[512];
-+static char stext[2048];
-+static char rawstext[1024];
- 
- static int screen;
- static int sw, sh;           /* X display screen geometry width, height */
diff --git a/config/patches/tagmon_scratchpad_floatrules.diff b/config/patches/tagmon_scratchpad_floatrules.diff
deleted file mode 100644
index 1678eb2..0000000
--- a/config/patches/tagmon_scratchpad_floatrules.diff
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/dwm.c
-+++ b/dwm.c
-@@ -2179,6 +2179,10 @@ tagmon(const Arg *arg)
- 		c->isfullscreen = 1;
- 		resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
- 		XRaiseWindow(dpy, c->win);
-+    } else if (c->isfloating && c->scratchkey != 0) {
-+ 		sendmon(c, dest);
-+ 		applyrules(c);
-+ 		XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
- 	} else
- 		sendmon(c, dest);
- }
diff --git a/drw.c b/drw.c
new file mode 100644
index 0000000..92f082e
--- /dev/null
+++ b/drw.c
@@ -0,0 +1,297 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+
+#include "drw.h"
+#include "util.h"
+
+Drw *
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
+{
+	Drw *drw = ecalloc(1, sizeof(Drw));
+
+	drw->dpy = dpy;
+	drw->screen = screen;
+	drw->root = root;
+	drw->w = w;
+	drw->h = h;
+
+	drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
+	drw->gc = XCreateGC(dpy, root, 0, NULL);
+	XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
+
+	return drw;
+}
+
+void
+drw_resize(Drw *drw, unsigned int w, unsigned int h)
+{
+	if (!drw)
+		return;
+
+	drw->w = w;
+	drw->h = h;
+	if (drw->drawable)
+		XFreePixmap(drw->dpy, drw->drawable);
+	drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
+}
+
+void
+drw_free(Drw *drw)
+{
+	XFreePixmap(drw->dpy, drw->drawable);
+	XFreeGC(drw->dpy, drw->gc);
+	drw_fontset_free(drw->fonts);
+	free(drw);
+}
+
+/* This function is an implementation detail. Library users should use
+ * drw_font_create instead.
+ */
+static Fnt *
+xfont_create(Drw *drw, const char *fontname)
+{
+	Fnt *font;
+	PangoFontMap *fontmap;
+	PangoContext *context;
+	PangoFontDescription *desc;
+	PangoFontMetrics *metrics;
+
+	if (!fontname) {
+		die("no font specified.");
+	}
+
+	font = ecalloc(1, sizeof(Fnt));
+	font->dpy = drw->dpy;
+
+	fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
+	context = pango_font_map_create_context(fontmap);
+	desc = pango_font_description_from_string(fontname);
+	font->layout = pango_layout_new(context);
+	pango_layout_set_font_description(font->layout, desc);
+
+	metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
+	font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
+
+	pango_font_metrics_unref(metrics);
+	g_object_unref(context);
+
+	return font;
+}
+
+static void
+xfont_free(Fnt *font)
+{
+	if (!font)
+		return;
+	if (font->layout)
+		g_object_unref(font->layout);
+	free(font);
+}
+
+Fnt*
+drw_font_create(Drw* drw, const char font[])
+{
+	Fnt *fnt = NULL;
+
+	if (!drw || !font)
+		return NULL;
+
+	fnt = xfont_create(drw, font);
+
+	return (drw->fonts = fnt);
+}
+
+void
+drw_fontset_free(Fnt *font)
+{
+	if (font) {
+		xfont_free(font);
+	}
+}
+
+void
+drw_clr_create(
+	Drw *drw,
+	Clr *dest,
+	const char *clrname
+) {
+	if (!drw || !dest || !clrname)
+		return;
+
+	if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
+	                       DefaultColormap(drw->dpy, drw->screen),
+	                       clrname, dest))
+		die("error, cannot allocate color '%s'", clrname);
+
+	dest->pixel |= 0xff << 24;
+}
+
+/* Wrapper to create color schemes. The caller has to call free(3) on the
+ * returned color scheme when done using it. */
+Clr *
+drw_scm_create(
+	Drw *drw,
+	char *clrnames[],
+	size_t clrcount
+) {
+	size_t i;
+	Clr *ret;
+
+	/* need at least two colors for a scheme */
+	if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
+		return NULL;
+
+	for (i = 0; i < clrcount; i++)
+		drw_clr_create(drw, &ret[i], clrnames[i]);
+	return ret;
+}
+
+void
+drw_setscheme(Drw *drw, Clr *scm)
+{
+	if (drw)
+		drw->scheme = scm;
+}
+
+void
+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
+{
+	if (!drw || !drw->scheme)
+		return;
+	XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
+	if (filled)
+		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+	else
+		XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
+}
+
+int
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
+{
+	char buf[1024];
+	int i, ty, th;
+	unsigned int ew, eh;
+	XftDraw *d = NULL;
+	size_t len;
+	int render = x || y || w || h;
+
+	if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
+		return 0;
+
+	if (!render) {
+		w = ~w;
+	} else {
+		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
+		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+		d = XftDrawCreate(drw->dpy, drw->drawable,
+		                  DefaultVisual(drw->dpy, drw->screen),
+		                  DefaultColormap(drw->dpy, drw->screen));
+		x += lpad;
+		w -= lpad;
+	}
+
+	len = strlen(text);
+
+	if (len) {
+		drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
+		th = eh;
+		/* shorten text if necessary */
+		for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
+			drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
+			if (eh > th)
+				th = eh;
+		}
+
+		if (len) {
+			memcpy(buf, text, len);
+			buf[len] = '\0';
+			if (len < strlen(text))
+				for (i = len; i && i > len - 3; buf[--i] = '.')
+					; /* NOP */
+
+			if (render) {
+				ty = y + (h - th) / 2;
+				if (markup)
+					pango_layout_set_markup(drw->fonts->layout, buf, len);
+				else
+					pango_layout_set_text(drw->fonts->layout, buf, len);
+				pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
+					drw->fonts->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
+				if (markup) /* clear markup attributes */
+					pango_layout_set_attributes(drw->fonts->layout, NULL);
+			}
+			x += ew;
+			w -= ew;
+		}
+	}
+	if (d)
+		XftDrawDestroy(d);
+
+	return x + (render ? w : 0);
+}
+
+void
+drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
+{
+	if (!drw)
+		return;
+
+	XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
+	XSync(drw->dpy, False);
+}
+
+unsigned int
+drw_fontset_getwidth(Drw *drw, const char *text, Bool markup)
+{
+	if (!drw || !drw->fonts || !text)
+		return 0;
+	return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
+}
+
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
+{
+	if (!font || !text)
+		return;
+
+	PangoRectangle r;
+	if (markup)
+		pango_layout_set_markup(font->layout, text, len);
+	else
+		pango_layout_set_text(font->layout, text, len);
+	pango_layout_get_extents(font->layout, 0, &r);
+	if (markup) /* clear markup attributes */
+		pango_layout_set_attributes(font->layout, NULL);
+	if (w)
+		*w = r.width / PANGO_SCALE;
+	if (h)
+		*h = r.height / PANGO_SCALE;
+}
+
+Cur *
+drw_cur_create(Drw *drw, int shape)
+{
+	Cur *cur;
+
+	if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
+		return NULL;
+
+	cur->cursor = XCreateFontCursor(drw->dpy, shape);
+
+	return cur;
+}
+
+void
+drw_cur_free(Drw *drw, Cur *cursor)
+{
+	if (!cursor)
+		return;
+
+	XFreeCursor(drw->dpy, cursor->cursor);
+	free(cursor);
+}
+
diff --git a/drw.h b/drw.h
new file mode 100644
index 0000000..701bed3
--- /dev/null
+++ b/drw.h
@@ -0,0 +1,66 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <pango/pango.h>
+#include <pango/pangoxft.h>
+
+typedef struct {
+	Cursor cursor;
+} Cur;
+
+typedef struct Fnt {
+	Display *dpy;
+	unsigned int h;
+	PangoLayout *layout;
+} Fnt;
+
+enum { ColFg, ColBg, ColBorder, ColFloat, ColCount }; /* Clr scheme index */
+typedef XftColor Clr;
+
+typedef struct {
+	unsigned int w, h;
+	Display *dpy;
+	int screen;
+	Window root;
+	Drawable drawable;
+	GC gc;
+	Clr *scheme;
+	Fnt *fonts;
+} Drw;
+
+/* Drawable abstraction */
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
+void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+void drw_free(Drw *drw);
+
+/* Fnt abstraction */
+Fnt *drw_font_create(Drw* drw, const char font[]);
+void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
+void drw_fontset_free(Fnt* set);
+unsigned int drw_fontset_getwidth(Drw *drw, const char *text, Bool markup);
+
+/* Colorscheme abstraction */
+void drw_clr_create(
+	Drw *drw,
+	Clr *dest,
+	const char *clrname
+);
+Clr *drw_scm_create(
+	Drw *drw,
+	char *clrnames[],
+	size_t clrcount
+);
+
+/* Cursor abstraction */
+Cur *drw_cur_create(Drw *drw, int shape);
+void drw_cur_free(Drw *drw, Cur *cursor);
+
+/* Drawing context manipulation */
+void drw_setscheme(Drw *drw, Clr *scm);
+
+/* Drawing functions */
+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup);
+
+/* Map functions */
+void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
+
diff --git a/dwm-flexipatch b/dwm-flexipatch
deleted file mode 160000
index 66770cf..0000000
--- a/dwm-flexipatch
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 66770cfbccceb562279ad7f8c700622b42776281
diff --git a/dwm.1 b/dwm.1
new file mode 100644
index 0000000..ddc8321
--- /dev/null
+++ b/dwm.1
@@ -0,0 +1,176 @@
+.TH DWM 1 dwm\-VERSION
+.SH NAME
+dwm \- dynamic window manager
+.SH SYNOPSIS
+.B dwm
+.RB [ \-v ]
+.SH DESCRIPTION
+dwm is a dynamic window manager for X. It manages windows in tiled, monocle
+and floating layouts. Either layout can be applied dynamically, optimising the
+environment for the application in use and the task performed.
+.P
+In tiled layouts windows are managed in a master and stacking area. The master
+area on the left contains one window by default, and the stacking area on the
+right contains all other windows. The number of master area windows can be
+adjusted from zero to an arbitrary number. In monocle layout all windows are
+maximised to the screen size. In floating layout windows can be resized and
+moved freely. Dialog windows are always managed floating, regardless of the
+layout applied.
+.P
+Windows are grouped by tags. Each window can be tagged with one or multiple
+tags. Selecting certain tags displays all windows with these tags.
+.P
+Each screen contains a small status bar which displays all available tags, the
+layout, the title of the focused window, and the text read from the root window
+name property, if the screen is focused. A floating window is indicated with an
+empty square and a maximised floating window is indicated with a filled square
+before the windows title.  The selected tags are indicated with a different
+color. The tags of the focused window are indicated with a filled square in the
+top left corner.  The tags which are applied to one or more windows are
+indicated with an empty square in the top left corner.
+.P
+dwm draws a small border around windows to indicate the focus state.
+.SH OPTIONS
+.TP
+.B \-v
+prints version information to stderr, then exits.
+.SH USAGE
+.SS Status bar
+.TP
+.B X root window name
+is read and displayed in the status text area. It can be set with the
+.BR xsetroot (1)
+command.
+.TP
+.B Button1
+click on a tag label to display all windows with that tag, click on the layout
+label toggles between tiled and floating layout.
+.TP
+.B Button3
+click on a tag label adds/removes all windows with that tag to/from the view.
+.TP
+.B Mod1\-Button1
+click on a tag label applies that tag to the focused window.
+.TP
+.B Mod1\-Button3
+click on a tag label adds/removes that tag to/from the focused window.
+.SS Keyboard commands
+.TP
+.B Mod1\-Shift\-Return
+Start
+.BR st(1).
+.TP
+.B Mod1\-p
+Spawn
+.BR dmenu(1)
+for launching other programs.
+.TP
+.B Mod1\-,
+Focus previous screen, if any.
+.TP
+.B Mod1\-.
+Focus next screen, if any.
+.TP
+.B Mod1\-Shift\-,
+Send focused window to previous screen, if any.
+.TP
+.B Mod1\-Shift\-.
+Send focused window to next screen, if any.
+.TP
+.B Mod1\-b
+Toggles bar on and off.
+.TP
+.B Mod1\-t
+Sets tiled layout.
+.TP
+.B Mod1\-f
+Sets floating layout.
+.TP
+.B Mod1\-m
+Sets monocle layout.
+.TP
+.B Mod1\-space
+Toggles between current and previous layout.
+.TP
+.B Mod1\-j
+Focus next window.
+.TP
+.B Mod1\-k
+Focus previous window.
+.TP
+.B Mod1\-i
+Increase number of windows in master area.
+.TP
+.B Mod1\-d
+Decrease number of windows in master area.
+.TP
+.B Mod1\-l
+Increase master area size.
+.TP
+.B Mod1\-h
+Decrease master area size.
+.TP
+.B Mod1\-Return
+Zooms/cycles focused window to/from master area (tiled layouts only).
+.TP
+.B Mod1\-Shift\-c
+Close focused window.
+.TP
+.B Mod1\-Shift\-space
+Toggle focused window between tiled and floating state.
+.TP
+.B Mod1\-Tab
+Toggles to the previously selected tags.
+.TP
+.B Mod1\-Shift\-[1..n]
+Apply nth tag to focused window.
+.TP
+.B Mod1\-Shift\-0
+Apply all tags to focused window.
+.TP
+.B Mod1\-Control\-Shift\-[1..n]
+Add/remove nth tag to/from focused window.
+.TP
+.B Mod1\-[1..n]
+View all windows with nth tag.
+.TP
+.B Mod1\-0
+View all windows with any tag.
+.TP
+.B Mod1\-Control\-[1..n]
+Add/remove all windows with nth tag to/from the view.
+.TP
+.B Mod1\-Shift\-q
+Quit dwm.
+.SS Mouse commands
+.TP
+.B Mod1\-Button1
+Move focused window while dragging. Tiled windows will be toggled to the floating state.
+.TP
+.B Mod1\-Button2
+Toggles focused window between floating and tiled state.
+.TP
+.B Mod1\-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
+code. This keeps it fast, secure and simple.
+.SH SEE ALSO
+.BR dmenu (1),
+.BR st (1)
+.SH ISSUES
+Java applications which use the XToolkit/XAWT backend may draw grey windows
+only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
+JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds
+are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the
+environment variable
+.BR AWT_TOOLKIT=MToolkit
+(to use the older Motif backend instead) or running
+.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D
+or
+.B wmname LG3D
+(to pretend that a non-reparenting window manager is running that the
+XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable
+.BR _JAVA_AWT_WM_NONREPARENTING=1 .
+.SH BUGS
+Send all bug reports with a patch to hackers@suckless.org.
diff --git a/dwm.c b/dwm.c
new file mode 100644
index 0000000..d734593
--- /dev/null
+++ b/dwm.c
@@ -0,0 +1,2702 @@
+/* See LICENSE file for copyright and license details.
+ *
+ * dynamic window manager is designed like any other X client as well. It is
+ * driven through handling X events. In contrast to other X clients, a window
+ * manager selects for SubstructureRedirectMask on the root window, to receive
+ * events about window (dis-)appearance. Only one X connection at a time is
+ * allowed to select for this event mask.
+ *
+ * The event handlers of dwm are organized in an array which is accessed
+ * whenever a new event has been fetched. This allows event dispatching
+ * in O(1) time.
+ *
+ * Each child of the root window is called a client, except windows which have
+ * set the override_redirect flag. Clients are organized in a linked client
+ * list on each monitor, the focus history is remembered through a stack list
+ * on each monitor. Each client contains a bit array to indicate the tags of a
+ * client.
+ *
+ * Keys and tagging rules are organized as arrays and defined in config.h.
+ *
+ * To understand everything else, start reading main().
+ */
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif /* XINERAMA */
+#include <X11/Xft/Xft.h>
+
+#include "drw.h"
+#include "util.h"
+
+#include <pango/pango.h>
+
+#include <poll.h>
+
+/* macros */
+#define Button6                 6
+#define Button7                 7
+#define Button8                 8
+#define Button9                 9
+#define NUMTAGS                 9
+#define NUMVIEWHIST             NUMTAGS
+#define BARRULES                20
+#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
+#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 LENGTH(X)               (sizeof X / sizeof X[0])
+#define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
+#define WIDTH(X)                ((X)->w + 2 * (X)->bw)
+#define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
+#define WTYPE                   "_NET_WM_WINDOW_TYPE_"
+#define TAGMASK                 ((1 << NUMTAGS) - 1)
+#define TEXTWM(X)               (drw_fontset_getwidth(drw, (X), True) + lrpad)
+#define TEXTW(X)                (drw_fontset_getwidth(drw, (X), False) + lrpad)
+#define HIDDEN(C)               ((getstate(C->win) == IconicState))
+
+/* enums */
+enum {
+	CurResizeBR,
+	CurResizeBL,
+	CurResizeTR,
+	CurResizeTL,
+	CurNormal,
+	CurResize,
+	CurMove,
+	CurLast
+}; /* cursor */
+
+enum {
+	SchemeNorm,
+	SchemeSel,
+	SchemeTitleNorm,
+	SchemeTitleSel,
+	SchemeTagsNorm,
+	SchemeTagsSel,
+	SchemeHidNorm,
+	SchemeHidSel,
+	SchemeUrg,
+	SchemeScratchSel,
+	SchemeScratchNorm,
+}; /* color schemes */
+
+enum {
+	NetSupported, NetWMName, NetWMState, NetWMCheck,
+	NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+	NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
+	NetClientList,
+	NetClientListStacking,
+	NetLast
+}; /* EWMH atoms */
+
+enum {
+	WMProtocols,
+	WMDelete,
+	WMState,
+	WMTakeFocus,
+	WMWindowRole,
+	WMLast
+}; /* default atoms */
+
+enum {
+	ClientFields,
+	ClientTags,
+	ClientLast
+}; /* dwm client atoms */
+
+enum {
+	ClkTagBar,
+	ClkLtSymbol,
+	ClkStatusText,
+	ClkWinTitle,
+	ClkClientWin,
+	ClkRootWin,
+	ClkLast
+}; /* clicks */
+
+enum {
+	BAR_ALIGN_LEFT,
+	BAR_ALIGN_CENTER,
+	BAR_ALIGN_RIGHT,
+	BAR_ALIGN_LEFT_LEFT,
+	BAR_ALIGN_LEFT_RIGHT,
+	BAR_ALIGN_LEFT_CENTER,
+	BAR_ALIGN_NONE,
+	BAR_ALIGN_RIGHT_LEFT,
+	BAR_ALIGN_RIGHT_RIGHT,
+	BAR_ALIGN_RIGHT_CENTER,
+	BAR_ALIGN_LAST
+}; /* bar alignment */
+
+typedef union {
+	int i;
+	unsigned int ui;
+	float f;
+	const void *v;
+} Arg;
+
+typedef struct Monitor Monitor;
+typedef struct Bar Bar;
+struct Bar {
+	Window win;
+	Monitor *mon;
+	Bar *next;
+	int idx;
+	int showbar;
+	int topbar;
+	int external;
+	int borderpx;
+	int borderscheme;
+	int bx, by, bw, bh; /* bar geometry */
+	int w[BARRULES]; // width, array length == barrules, then use r index for lookup purposes
+	int x[BARRULES]; // x position, array length == ^
+};
+
+typedef struct {
+	int x;
+	int y;
+	int h;
+	int w;
+} BarArg;
+
+typedef struct {
+	int monitor;
+	int bar;
+	int alignment; // see bar alignment enum
+	int (*widthfunc)(Bar *bar, BarArg *a);
+	int (*drawfunc)(Bar *bar, BarArg *a);
+	int (*clickfunc)(Bar *bar, Arg *arg, BarArg *a);
+	int (*hoverfunc)(Bar *bar, BarArg *a, XMotionEvent *ev);
+	char *name; // for debugging
+	int x, w; // position, width for internal use
+} BarRule;
+
+typedef struct {
+	unsigned int click;
+	unsigned int mask;
+	unsigned int button;
+	void (*func)(const Arg *arg);
+	const Arg arg;
+} Button;
+
+typedef struct Client Client;
+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 */
+	unsigned int idx;
+	int oldx, oldy, oldw, oldh;
+	int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+	int bw, oldbw;
+	unsigned int tags;
+	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+	int iscentered;
+	Client *next;
+	Client *snext;
+	Monitor *mon;
+	Window win;
+	char scratchkey;
+};
+
+typedef struct {
+	unsigned int mod;
+	KeySym keysym;
+	void (*func)(const Arg *);
+	const Arg arg;
+} Key;
+
+typedef struct {
+	const char *symbol;
+	void (*arrange)(Monitor *);
+} Layout;
+
+typedef struct Pertag Pertag;
+struct Monitor {
+	char ltsymbol[16];
+	float mfact;
+	int nmaster;
+	int num;
+	int mx, my, mw, mh;   /* screen size */
+	int wx, wy, ww, wh;   /* window area  */
+	unsigned int seltags;
+	unsigned int sellt;
+	unsigned int tagset[2];
+	int showbar;
+	Client *clients;
+	Client *sel;
+	Client *stack;
+	Monitor *next;
+	Bar *bar;
+	const Layout *lt[2];
+	Pertag *pertag;
+};
+
+typedef struct {
+	const char *class;
+	const char *role;
+	const char *instance;
+	const char *title;
+	const char *wintype;
+	unsigned int tags;
+	int iscentered;
+	int isfloating;
+	const char *floatpos;
+	int monitor;
+	const char scratchkey;
+} Rule;
+
+#define RULE(...) { .monitor = -1, __VA_ARGS__ },
+
+/* Cross patch compatibility rule macro helper macros */
+#define FLOATING , .isfloating = 1
+#define CENTERED , .iscentered = 1
+#define PERMANENT
+#define FAKEFULLSCREEN
+#define NOSWALLOW
+#define TERMINAL
+#define SWITCHTAG
+
+/* function declarations */
+static void applyrules(Client *c);
+static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+static void arrange(Monitor *m);
+static void arrangemon(Monitor *m);
+static void attach(Client *c);
+static void attachstack(Client *c);
+static void buttonpress(XEvent *e);
+static void checkotherwm(void);
+static void cleanup(void);
+static void cleanupmon(Monitor *mon);
+static void clientmessage(XEvent *e);
+static void configure(Client *c);
+static void configurenotify(XEvent *e);
+static void configurerequest(XEvent *e);
+static Monitor *createmon(void);
+static void destroynotify(XEvent *e);
+static void detach(Client *c);
+static void detachstack(Client *c);
+static Monitor *dirtomon(int dir);
+static void drawbar(Monitor *m);
+static void drawbars(void);
+static void drawbarwin(Bar *bar);
+static void expose(XEvent *e);
+static void focus(Client *c);
+static void focusin(XEvent *e);
+static void focusmon(const Arg *arg);
+static Atom getatomprop(Client *c, Atom prop, Atom req);
+static int getrootptr(int *x, int *y);
+static long getstate(Window w);
+static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
+static void grabbuttons(Client *c, int focused);
+static void grabkeys(void);
+static void incnmaster(const Arg *arg);
+static void keypress(XEvent *e);
+static void killclient(const Arg *arg);
+static void manage(Window w, XWindowAttributes *wa);
+static void mappingnotify(XEvent *e);
+static void maprequest(XEvent *e);
+static void motionnotify(XEvent *e);
+static void movemouse(const Arg *arg);
+static Client *nexttiled(Client *c);
+static void pop(Client *c);
+static void propertynotify(XEvent *e);
+static void quit(const Arg *arg);
+static Monitor *recttomon(int x, int y, int w, int h);
+static void resize(Client *c, int x, int y, int w, int h, int interact);
+static void resizeclient(Client *c, int x, int y, int w, int h);
+static void resizemouse(const Arg *arg);
+static void restack(Monitor *m);
+static void run(void);
+static void scan(void);
+static int sendevent(Client *c, Atom proto);
+static void sendmon(Client *c, Monitor *m);
+static void setclientstate(Client *c, long state);
+static void setfocus(Client *c);
+static void setfullscreen(Client *c, int fullscreen);
+static void setlayout(const Arg *arg);
+static void setmfact(const Arg *arg);
+static void setup(void);
+static void seturgent(Client *c, int urg);
+static void sigchld(int unused);
+static void showhide(Client *c);
+static void spawn(const Arg *arg);
+static void tag(const Arg *arg);
+static void tagmon(const Arg *arg);
+static void togglebar(const Arg *arg);
+static void togglefloating(const Arg *arg);
+static void toggletag(const Arg *arg);
+static void toggleview(const Arg *arg);
+static void unfocus(Client *c, int setfocus, Client *nextfocus);
+static void unmanage(Client *c, int destroyed);
+static void unmapnotify(XEvent *e);
+static void updatebarpos(Monitor *m);
+static void updatebars(void);
+static void updateclientlist(void);
+static int updategeom(void);
+static void updatenumlockmask(void);
+static void updatesizehints(Client *c);
+static void updatestatus(void);
+static void 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 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);
+
+/* bar functions */
+
+#include "patch/include.h"
+
+/* variables */
+static const char broken[] = "broken";
+static char stext[2048];
+static char rawstext[1024];
+
+static int screen;
+static int sw, sh;           /* X display screen geometry width, height */
+static int bh;               /* bar geometry */
+static int lrpad;            /* sum of left and right padding for text */
+/* Some clients (e.g. alacritty) helpfully send configure requests with a new size or position
+ * when they detect that they have been moved to another monitor. This can cause visual glitches
+ * when moving (or resizing) client windows from one monitor to another. This variable is used
+ * internally to ignore such configure requests while movemouse or resizemouse are being used. */
+static int ignoreconfigurerequests = 0;
+static int (*xerrorxlib)(Display *, XErrorEvent *);
+static unsigned int numlockmask = 0;
+static void (*handler[LASTEvent]) (XEvent *) = {
+	[ButtonPress] = buttonpress,
+	[ClientMessage] = clientmessage,
+	[ConfigureRequest] = configurerequest,
+	[ConfigureNotify] = configurenotify,
+	[DestroyNotify] = destroynotify,
+	[Expose] = expose,
+	[FocusIn] = focusin,
+	[KeyPress] = keypress,
+	[MappingNotify] = mappingnotify,
+	[MapRequest] = maprequest,
+	[MotionNotify] = motionnotify,
+	[PropertyNotify] = propertynotify,
+	[UnmapNotify] = unmapnotify
+};
+static Atom wmatom[WMLast], netatom[NetLast];
+static Atom clientatom[ClientLast];
+static volatile sig_atomic_t running = 1;
+static Cur *cursor[CurLast];
+static Clr **scheme;
+static Display *dpy;
+static Drw *drw;
+static Monitor *mons, *selmon;
+static Window root, wmcheckwin;
+
+/* configuration, allows nested code to access above variables */
+#include "config.h"
+
+#include "patch/include.c"
+
+/* compile-time check if all tags fit into an unsigned int bit array. */
+struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; };
+
+/* function implementations */
+void
+applyrules(Client *c)
+{
+	const char *class, *instance;
+	Atom wintype;
+	char role[64];
+	unsigned int i;
+	const Rule *r;
+	Monitor *m;
+	XClassHint ch = { NULL, NULL };
+
+	/* rule matching */
+	c->isfloating = 0;
+	c->tags = 0;
+	c->scratchkey = 0;
+	XGetClassHint(dpy, c->win, &ch);
+	class    = ch.res_class ? ch.res_class : broken;
+	instance = ch.res_name  ? ch.res_name  : broken;
+	wintype  = getatomprop(c, netatom[NetWMWindowType], XA_ATOM);
+	gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
+
+	for (i = 0; i < LENGTH(rules); i++) {
+		r = &rules[i];
+		if ((!r->title || strstr(c->name, r->title))
+		&& (!r->class || strstr(class, r->class))
+		&& (!r->role || strstr(role, r->role))
+		&& (!r->instance || strstr(instance, r->instance))
+		&& (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
+		{
+			c->iscentered = r->iscentered;
+			c->isfloating = r->isfloating;
+			c->tags |= r->tags;
+			c->scratchkey = r->scratchkey;
+			for (m = mons; m && m->num != r->monitor; m = m->next);
+			if (m)
+				c->mon = m;
+			if (c->isfloating && r->floatpos) {
+				c->iscentered = 0;
+				setfloatpos(c, r->floatpos);
+			}
+
+		}
+	}
+	if (ch.res_class)
+		XFree(ch.res_class);
+	if (ch.res_name)
+		XFree(ch.res_name);
+	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
+}
+
+int
+applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
+{
+	int baseismin;
+	Monitor *m = c->mon;
+
+	/* set minimum possible */
+	*w = MAX(1, *w);
+	*h = MAX(1, *h);
+	if (interact) {
+		if (*x > sw)
+			*x = sw - WIDTH(c);
+		if (*y > sh)
+			*y = sh - HEIGHT(c);
+		if (*x + *w + 2 * c->bw < 0)
+			*x = 0;
+		if (*y + *h + 2 * c->bw < 0)
+			*y = 0;
+	} else {
+		if (*x >= m->wx + m->ww)
+			*x = m->wx + m->ww - WIDTH(c);
+		if (*y >= m->wy + m->wh)
+			*y = m->wy + m->wh - HEIGHT(c);
+		if (*x + *w + 2 * c->bw <= m->wx)
+			*x = m->wx;
+		if (*y + *h + 2 * c->bw <= m->wy)
+			*y = m->wy;
+	}
+	if (*h < bh)
+		*h = bh;
+	if (*w < bh)
+		*w = bh;
+	if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+		if (!c->hintsvalid)
+			updatesizehints(c);
+		/* see last two sentences in ICCCM 4.1.2.3 */
+		baseismin = c->basew == c->minw && c->baseh == c->minh;
+		if (!baseismin) { /* temporarily remove base dimensions */
+			*w -= c->basew;
+			*h -= c->baseh;
+		}
+		/* adjust for aspect limits */
+		if (c->mina > 0 && c->maxa > 0) {
+			if (c->maxa < (float)*w / *h)
+				*w = *h * c->maxa + 0.5;
+			else if (c->mina < (float)*h / *w)
+				*h = *w * c->mina + 0.5;
+		}
+		if (baseismin) { /* increment calculation requires this */
+			*w -= c->basew;
+			*h -= c->baseh;
+		}
+		/* adjust for increment value */
+		if (c->incw)
+			*w -= *w % c->incw;
+		if (c->inch)
+			*h -= *h % c->inch;
+		/* restore base dimensions */
+		*w = MAX(*w + c->basew, c->minw);
+		*h = MAX(*h + c->baseh, c->minh);
+		if (c->maxw)
+			*w = MIN(*w, c->maxw);
+		if (c->maxh)
+			*h = MIN(*h, c->maxh);
+	}
+	return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
+}
+
+void
+arrange(Monitor *m)
+{
+	if (m)
+		showhide(m->stack);
+	else for (m = mons; m; m = m->next)
+		showhide(m->stack);
+	if (m) {
+		arrangemon(m);
+		restack(m);
+	} else for (m = mons; m; m = m->next)
+		arrangemon(m);
+}
+
+void
+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);
+}
+
+void
+attach(Client *c)
+{
+	c->next = c->mon->clients;
+	c->mon->clients = c;
+}
+
+void
+attachstack(Client *c)
+{
+	c->snext = c->mon->stack;
+	c->mon->stack = c;
+}
+
+void
+buttonpress(XEvent *e)
+{
+	int click, i, r;
+	Arg arg = {0};
+	Client *c;
+	Monitor *m;
+	Bar *bar;
+	XButtonPressedEvent *ev = &e->xbutton;
+	const BarRule *br;
+	BarArg carg = { 0, 0, 0, 0 };
+	click = ClkRootWin;
+
+	/* focus monitor if necessary */
+	if ((m = wintomon(ev->window)) && m != selmon
+		&& (focusonwheel || (ev->button != Button4 && ev->button != Button5))
+	) {
+		unfocus(selmon->sel, 1, NULL);
+		selmon = m;
+		focus(NULL);
+	}
+
+	for (bar = selmon->bar; bar; bar = bar->next) {
+		if (ev->window == bar->win) {
+			for (r = 0; r < LENGTH(barrules); r++) {
+				br = &barrules[r];
+				if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL)
+					continue;
+				if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
+					continue;
+				if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) {
+					carg.x = ev->x - bar->x[r];
+					carg.y = ev->y - bar->borderpx;
+					carg.w = bar->w[r];
+					carg.h = bar->bh - 2 * bar->borderpx;
+					click = br->clickfunc(bar, &arg, &carg);
+					if (click < 0)
+						return;
+					break;
+				}
+			}
+			break;
+		}
+	}
+
+	if (click == ClkRootWin && (c = wintoclient(ev->window))) {
+		if (focusonwheel || (ev->button != Button4 && ev->button != Button5))
+			focus(c);
+		XAllowEvents(dpy, ReplayPointer, CurrentTime);
+		click = ClkClientWin;
+	}
+
+	for (i = 0; i < LENGTH(buttons); i++) {
+		if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
+				&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
+			buttons[i].func(
+				(
+					click == ClkTagBar
+				) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg
+			);
+		}
+	}
+}
+
+void
+checkotherwm(void)
+{
+	xerrorxlib = XSetErrorHandler(xerrorstart);
+	/* this causes an error if some other window manager is running */
+	XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
+	XSync(dpy, False);
+	XSetErrorHandler(xerror);
+	XSync(dpy, False);
+}
+
+void
+cleanup(void)
+{
+	Monitor *m;
+	Layout foo = { "", NULL };
+	size_t i;
+
+	for (m = mons; m; m = m->next)
+		persistmonitorstate(m);
+
+	/* kill child processes */
+	for (i = 0; i < autostart_len; i++) {
+		if (0 < autostart_pids[i]) {
+			kill(autostart_pids[i], autostart_kill_signal);
+			waitpid(autostart_pids[i], NULL, 0);
+		}
+	}
+
+	selmon->lt[selmon->sellt] = &foo;
+	for (m = mons; m; m = m->next)
+		while (m->stack)
+			unmanage(m->stack, 0);
+	XUngrabKey(dpy, AnyKey, AnyModifier, root);
+	while (mons)
+		cleanupmon(mons);
+	for (i = 0; i < CurLast; i++)
+		drw_cur_free(drw, cursor[i]);
+	for (i = 0; i < LENGTH(colors); i++)
+		free(scheme[i]);
+	free(scheme);
+	XDestroyWindow(dpy, wmcheckwin);
+	drw_free(drw);
+	XSync(dpy, False);
+	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+	XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+
+}
+
+void
+cleanupmon(Monitor *mon)
+{
+	Monitor *m;
+	Bar *bar;
+
+	if (mon == mons)
+		mons = mons->next;
+	else {
+		for (m = mons; m && m->next != mon; m = m->next);
+		m->next = mon->next;
+	}
+	for (bar = mon->bar; bar; bar = mon->bar) {
+		if (!bar->external) {
+			XUnmapWindow(dpy, bar->win);
+			XDestroyWindow(dpy, bar->win);
+		}
+		mon->bar = bar->next;
+		free(bar);
+	}
+	free(mon->pertag);
+	free(mon);
+}
+
+void
+clientmessage(XEvent *e)
+{
+	XClientMessageEvent *cme = &e->xclient;
+	Client *c = wintoclient(cme->window);
+
+	if (!c)
+		return;
+	if (cme->message_type == netatom[NetWMState]) {
+		if (cme->data.l[1] == netatom[NetWMFullscreen]
+		|| cme->data.l[2] == netatom[NetWMFullscreen]) {
+			setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
+				|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */
+				&& !c->isfullscreen
+			)));
+		}
+	} else if (cme->message_type == netatom[NetActiveWindow]) {
+		if (c != selmon->sel && !c->isurgent)
+			seturgent(c, 1);
+	}
+}
+
+void
+configure(Client *c)
+{
+	XConfigureEvent ce;
+
+	ce.type = ConfigureNotify;
+	ce.display = dpy;
+	ce.event = c->win;
+	ce.window = c->win;
+	ce.x = c->x;
+	ce.y = c->y;
+	ce.width = c->w;
+	ce.height = c->h;
+	ce.border_width = c->bw;
+
+	ce.above = None;
+	ce.override_redirect = False;
+	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
+}
+
+void
+configurenotify(XEvent *e)
+{
+	Monitor *m;
+	Bar *bar;
+	Client *c;
+	XConfigureEvent *ev = &e->xconfigure;
+	int dirty;
+	/* TODO: updategeom handling sucks, needs to be simplified */
+	if (ev->window == root) {
+		dirty = (sw != ev->width || sh != ev->height);
+		sw = ev->width;
+		sh = ev->height;
+		if (updategeom() || dirty) {
+			drw_resize(drw, sw, sh);
+			updatebars();
+			for (m = mons; m; m = m->next) {
+				for (c = m->clients; c; c = c->next)
+					if (c->isfullscreen)
+						resizeclient(c, m->mx, m->my, m->mw, m->mh);
+				for (bar = m->bar; bar; bar = bar->next)
+					XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+			}
+			arrange(NULL);
+			focus(NULL);
+		}
+	}
+}
+
+void
+configurerequest(XEvent *e)
+{
+	Client *c;
+	Monitor *m;
+	XConfigureRequestEvent *ev = &e->xconfigurerequest;
+	XWindowChanges wc;
+
+	if (ignoreconfigurerequests)
+		return;
+
+	if ((c = wintoclient(ev->window))) {
+		if (ev->value_mask & CWBorderWidth)
+			c->bw = ev->border_width;
+		else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
+			m = c->mon;
+			if (ev->value_mask & CWX) {
+				c->oldx = c->x;
+				c->x = m->mx + ev->x;
+			}
+			if (ev->value_mask & CWY) {
+				c->oldy = c->y;
+				c->y = m->my + ev->y;
+			}
+			if (ev->value_mask & CWWidth) {
+				c->oldw = c->w;
+				c->w = ev->width;
+			}
+			if (ev->value_mask & CWHeight) {
+				c->oldh = c->h;
+				c->h = ev->height;
+			}
+			if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
+				c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2);  /* center in x direction */
+			if ((c->y + c->h) > m->my + m->mh && c->isfloating)
+				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))
+				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+		} else
+			configure(c);
+	} else {
+		wc.x = ev->x;
+		wc.y = ev->y;
+		wc.width = ev->width;
+		wc.height = ev->height;
+		wc.border_width = ev->border_width;
+		wc.sibling = ev->above;
+		wc.stack_mode = ev->detail;
+		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
+	}
+	XSync(dpy, False);
+}
+
+Monitor *
+createmon(void)
+{
+	Monitor *m, *mon;
+	int i, n, mi, max_bars = 2, istopbar = topbar;
+
+	const BarRule *br;
+	Bar *bar;
+
+	m = ecalloc(1, sizeof(Monitor));
+	m->tagset[0] = m->tagset[1] = 1;
+	m->mfact = mfact;
+	m->nmaster = nmaster;
+	m->showbar = showbar;
+	for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index
+	m->num = mi;
+	m->lt[0] = &layouts[0];
+	m->lt[1] = &layouts[1 % LENGTH(layouts)];
+	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+
+	/* Derive the number of bars for this monitor based on bar rules */
+	for (n = -1, i = 0; i < LENGTH(barrules); i++) {
+		br = &barrules[i];
+		if (br->monitor == 'A' || br->monitor == -1 || br->monitor == m->num)
+			n = MAX(br->bar, n);
+	}
+
+	m->bar = NULL;
+	for (i = 0; i <= n && i < max_bars; i++) {
+		bar = ecalloc(1, sizeof(Bar));
+		bar->mon = m;
+		bar->idx = i;
+		bar->next = m->bar;
+		bar->topbar = istopbar;
+		m->bar = bar;
+		istopbar = !istopbar;
+		bar->showbar = 1;
+		bar->external = 0;
+		bar->borderpx = 0;
+		bar->bh = bh + bar->borderpx * 2;
+		bar->borderscheme = SchemeNorm;
+	}
+
+	if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
+		die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+	m->pertag->curtag = 1;
+	for (i = 0; i <= NUMTAGS; 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;
+
+	}
+
+	restoremonitorstate(m);
+
+	return m;
+}
+
+void
+destroynotify(XEvent *e)
+{
+	Client *c;
+	XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+	if ((c = wintoclient(ev->window)))
+		unmanage(c, 1);
+}
+
+void
+detach(Client *c)
+{
+	Client **tc;
+	c->idx = 0;
+
+	for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
+	*tc = c->next;
+	c->next = NULL;
+}
+
+void
+detachstack(Client *c)
+{
+	Client **tc, *t;
+
+	for (tc = &c->mon->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);
+		c->mon->sel = t;
+	}
+	c->snext = NULL;
+}
+
+Monitor *
+dirtomon(int dir)
+{
+	Monitor *m = NULL;
+
+	if (dir > 0) {
+		if (!(m = selmon->next))
+			m = mons;
+	} else if (selmon == mons)
+		for (m = mons; m->next; m = m->next);
+	else
+		for (m = mons; m->next != selmon; m = m->next);
+	return m;
+}
+
+void
+drawbar(Monitor *m)
+{
+	Bar *bar;
+	
+	if (m->showbar)
+		for (bar = m->bar; bar; bar = bar->next)
+			drawbarwin(bar);
+}
+
+void
+drawbars(void)
+{
+	Monitor *m;
+	for (m = mons; m; m = m->next)
+		drawbar(m);
+}
+
+void
+drawbarwin(Bar *bar)
+{
+	if (!bar || !bar->win || bar->external)
+		return;
+	int r, w, total_drawn = 0;
+	int rx, lx, rw, lw; // bar size, split between left and right if a center module is added
+	const BarRule *br;
+
+	if (bar->borderpx) {
+		XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBorder].pixel);
+		XFillRectangle(drw->dpy, drw->drawable, drw->gc, 0, 0, bar->bw, bar->bh);
+	}
+
+	BarArg warg = { 0 };
+	BarArg darg  = { 0 };
+	warg.h = bar->bh - 2 * bar->borderpx;
+
+	rw = lw = bar->bw - 2 * bar->borderpx;
+	rx = lx = bar->borderpx;
+
+	drw_setscheme(drw, scheme[SchemeNorm]);
+	drw_rect(drw, lx, bar->borderpx, lw, bar->bh - 2 * bar->borderpx, 1, 1);
+	for (r = 0; r < LENGTH(barrules); r++) {
+		br = &barrules[r];
+		if (br->bar != bar->idx || !br->widthfunc || (br->monitor == 'A' && bar->mon != selmon))
+			continue;
+		if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
+			continue;
+		drw_setscheme(drw, scheme[SchemeNorm]);
+		warg.w = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw);
+
+		w = br->widthfunc(bar, &warg);
+		w = MIN(warg.w, w);
+
+		if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa
+			lw = rw;
+			lx = rx;
+		} else if (rw <= 0) {
+			rw = lw;
+			rx = lx;
+		}
+
+		switch(br->alignment) {
+		default:
+		case BAR_ALIGN_NONE:
+		case BAR_ALIGN_LEFT_LEFT:
+		case BAR_ALIGN_LEFT:
+			bar->x[r] = lx;
+			if (lx == rx) {
+				rx += w;
+				rw -= w;
+			}
+			lx += w;
+			lw -= w;
+			break;
+		case BAR_ALIGN_LEFT_RIGHT:
+		case BAR_ALIGN_RIGHT:
+			bar->x[r] = lx + lw - w;
+			if (lx == rx)
+				rw -= w;
+			lw -= w;
+			break;
+		case BAR_ALIGN_LEFT_CENTER:
+		case BAR_ALIGN_CENTER:
+			bar->x[r] = lx + lw / 2 - w / 2;
+			if (lx == rx) {
+				rw = rx + rw - bar->x[r] - w;
+				rx = bar->x[r] + w;
+			}
+			lw = bar->x[r] - lx;
+			break;
+		case BAR_ALIGN_RIGHT_LEFT:
+			bar->x[r] = rx;
+			if (lx == rx) {
+				lx += w;
+				lw -= w;
+			}
+			rx += w;
+			rw -= w;
+			break;
+		case BAR_ALIGN_RIGHT_RIGHT:
+			bar->x[r] = rx + rw - w;
+			if (lx == rx)
+				lw -= w;
+			rw -= w;
+			break;
+		case BAR_ALIGN_RIGHT_CENTER:
+			bar->x[r] = rx + rw / 2 - w / 2;
+			if (lx == rx) {
+				lw = lx + lw - bar->x[r] + w;
+				lx = bar->x[r] + w;
+			}
+			rw = bar->x[r] - rx;
+			break;
+		}
+		bar->w[r] = w;
+		darg.x = bar->x[r];
+		darg.y = bar->borderpx;
+		darg.h = bar->bh - 2 * bar->borderpx;
+		darg.w = bar->w[r];
+		if (br->drawfunc)
+			total_drawn += br->drawfunc(bar, &darg);
+	}
+
+	if (total_drawn == 0 && bar->showbar) {
+		bar->showbar = 0;
+		updatebarpos(bar->mon);
+		XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+		arrange(bar->mon);
+	}
+	else if (total_drawn > 0 && !bar->showbar) {
+		bar->showbar = 1;
+		updatebarpos(bar->mon);
+		XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+		drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
+		arrange(bar->mon);
+	} else
+		drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
+}
+
+void
+expose(XEvent *e)
+{
+	Monitor *m;
+	XExposeEvent *ev = &e->xexpose;
+
+	if (ev->count == 0 && (m = wintomon(ev->window))) {
+		drawbar(m);
+	}
+}
+
+void
+focus(Client *c)
+{
+	if (!c || !ISVISIBLE(c))
+		for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
+	if (selmon->sel && selmon->sel != c)
+		unfocus(selmon->sel, 0, c);
+	if (c) {
+		if (c->mon != selmon)
+			selmon = c->mon;
+		if (c->isurgent)
+			seturgent(c, 0);
+		detachstack(c);
+		attachstack(c);
+		grabbuttons(c, 1);
+		if (c->scratchkey != 0 && c->isfloating)
+			XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColFloat].pixel);
+		else if (c->scratchkey != 0)
+			XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
+		else if (c->isfloating)
+			XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
+		else
+			XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+		setfocus(c);
+	} else {
+		XSetInputFocus(dpy, selmon->bar && selmon->bar->win ? selmon->bar->win : root, RevertToPointerRoot, CurrentTime);
+		XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+	}
+	selmon->sel = c;
+	drawbars();
+
+}
+
+/* there are some broken focus acquiring clients needing extra handling */
+void
+focusin(XEvent *e)
+{
+	XFocusChangeEvent *ev = &e->xfocus;
+
+	if (selmon->sel && ev->window != selmon->sel->win)
+		setfocus(selmon->sel);
+}
+
+void
+focusmon(const Arg *arg)
+{
+	Monitor *m;
+	Client *sel;
+
+	if (!mons->next)
+		return;
+	if ((m = dirtomon(arg->i)) == selmon)
+		return;
+	sel = selmon->sel;
+	selmon = m;
+	unfocus(sel, 0, NULL);
+	focus(NULL);
+}
+
+Atom
+getatomprop(Client *c, Atom prop, Atom req)
+{
+	int di;
+	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 */
+	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
+		&da, &di, &dl, &dl, &p) == Success && p) {
+		atom = *(Atom *)p;
+		XFree(p);
+	}
+	return atom;
+}
+
+int
+getrootptr(int *x, int *y)
+{
+	int di;
+	unsigned int dui;
+	Window dummy;
+
+	return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
+}
+
+long
+getstate(Window w)
+{
+	int format;
+	long result = -1;
+	unsigned char *p = NULL;
+	unsigned long n, extra;
+	Atom real;
+
+	if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
+		&real, &format, &n, &extra, (unsigned char **)&p) != Success)
+		return -1;
+	if (n != 0)
+		result = *p;
+	XFree(p);
+	return result;
+}
+
+int
+gettextprop(Window w, Atom atom, char *text, unsigned int size)
+{
+	char **list = NULL;
+	int n;
+	XTextProperty name;
+
+	if (!text || size == 0)
+		return 0;
+	text[0] = '\0';
+	if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
+		return 0;
+	if (name.encoding == XA_STRING) {
+		strncpy(text, (char *)name.value, size - 1);
+	} else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
+		strncpy(text, *list, size - 1);
+		XFreeStringList(list);
+	}
+	text[size - 1] = '\0';
+	XFree(name.value);
+	return 1;
+}
+
+void
+grabbuttons(Client *c, int focused)
+{
+	updatenumlockmask();
+	{
+		unsigned int i, j;
+		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+		XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+		if (!focused)
+			XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
+				BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
+		for (i = 0; i < LENGTH(buttons); i++)
+			if (buttons[i].click == ClkClientWin
+			)
+				for (j = 0; j < LENGTH(modifiers); j++)
+					XGrabButton(dpy, buttons[i].button,
+						buttons[i].mask | modifiers[j],
+						c->win, False, BUTTONMASK,
+						GrabModeAsync, GrabModeSync, None, None);
+	}
+}
+
+void
+grabkeys(void)
+{
+	updatenumlockmask();
+	{
+		unsigned int i, j, k;
+		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+		int start, end, skip;
+		KeySym *syms;
+
+		XUngrabKey(dpy, AnyKey, AnyModifier, root);
+		XDisplayKeycodes(dpy, &start, &end);
+		syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+		if (!syms)
+			return;
+		for (k = start; k <= end; k++)
+			for (i = 0; i < LENGTH(keys); i++)
+				/* skip modifier codes, we do that ourselves */
+				if (keys[i].keysym == syms[(k - start) * skip])
+					for (j = 0; j < LENGTH(modifiers); j++)
+						XGrabKey(dpy, k,
+							 keys[i].mod | modifiers[j],
+							 root, True,
+							 GrabModeAsync, GrabModeAsync);
+		XFree(syms);
+	}
+}
+
+void
+incnmaster(const Arg *arg)
+{
+	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
+	arrange(selmon);
+}
+
+#ifdef XINERAMA
+static int
+isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
+{
+	while (n--)
+		if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
+		&& unique[n].width == info->width && unique[n].height == info->height)
+			return 0;
+	return 1;
+}
+#endif /* XINERAMA */
+
+void
+keypress(XEvent *e)
+{
+	unsigned int i;
+	int keysyms_return;
+	KeySym* keysym;
+	XKeyEvent *ev;
+
+	ev = &e->xkey;
+	keysym = XGetKeyboardMapping(dpy, (KeyCode)ev->keycode, 1, &keysyms_return);
+	for (i = 0; i < LENGTH(keys); i++)
+		if (*keysym == keys[i].keysym
+				&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+				&& keys[i].func)
+			keys[i].func(&(keys[i].arg));
+	XFree(keysym);
+}
+
+void
+killclient(const Arg *arg)
+{
+	if (!selmon->sel)
+		return;
+	if (!sendevent(selmon->sel, wmatom[WMDelete]))
+	{
+		XGrabServer(dpy);
+		XSetErrorHandler(xerrordummy);
+		XSetCloseDownMode(dpy, DestroyAll);
+		XKillClient(dpy, selmon->sel->win);
+		XSync(dpy, False);
+		XSetErrorHandler(xerror);
+		XUngrabServer(dpy);
+	}
+}
+
+void
+manage(Window w, XWindowAttributes *wa)
+{
+	Client *c, *t = NULL;
+	int settings_restored;
+	Window trans = None;
+	XWindowChanges wc;
+
+	c = ecalloc(1, sizeof(Client));
+	c->win = w;
+	/* geometry */
+	c->sfx = c->sfy = c->sfw = c->sfh = -9999;
+	c->x = c->oldx = wa->x;
+	c->y = c->oldy = wa->y;
+	c->w = c->oldw = wa->width;
+	c->h = c->oldh = wa->height;
+	c->oldbw = wa->border_width;
+	settings_restored = restoreclientstate(c);
+	updatetitle(c);
+
+	if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+		c->mon = t->mon;
+		c->tags = t->tags;
+		c->bw = borderpx;
+		c->x = t->x + WIDTH(t) / 2 - WIDTH(c) / 2;
+		c->y = t->y + HEIGHT(t) / 2 - HEIGHT(c) / 2;
+	} else {
+		if (!settings_restored || c->mon == NULL) {
+			c->mon = selmon;
+			settings_restored = 0;
+		}
+		if (c->x == c->mon->wx && c->y == c->mon->wy)
+			c->iscentered = 1;
+		c->bw = borderpx;
+		if (!settings_restored)
+			applyrules(c);
+	}
+
+	if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+		c->x = c->mon->wx + c->mon->ww - WIDTH(c);
+	if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
+		c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
+	c->x = MAX(c->x, c->mon->wx);
+	c->y = MAX(c->y, c->mon->wy);
+
+	wc.border_width = c->bw;
+	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+	if (c->isfloating)
+		XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
+	else
+		XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+	configure(c); /* propagates border_width, if size doesn't change */
+	updatesizehints(c);
+	updatewmhints(c);
+
+	if (c->iscentered) {
+		c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
+		c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
+	}
+	if (c->sfw == -9999) {
+		c->sfw = c->w;
+		c->sfh = c->h;
+	}
+
+	if (getatomprop(c, netatom[NetWMState], XA_ATOM) == netatom[NetWMFullscreen])
+		setfullscreen(c, 1);
+
+	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+	grabbuttons(c, 0);
+
+	if (!c->isfloating)
+		c->isfloating = c->oldstate = trans != None || c->isfixed;
+	if (c->isfloating) {
+		XRaiseWindow(dpy, c->win);
+		XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
+	}
+	attachx(c);
+	attachstack(c);
+	XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+		(unsigned char *) &(c->win), 1);
+	XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend,
+		(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)
+		unfocus(selmon->sel, 0, c);
+	c->mon->sel = c;
+	arrange(c->mon);
+	XMapWindow(dpy, c->win);
+	focus(NULL);
+
+	setfloatinghint(c);
+}
+
+void
+mappingnotify(XEvent *e)
+{
+	XMappingEvent *ev = &e->xmapping;
+
+	XRefreshKeyboardMapping(ev);
+	if (ev->request == MappingKeyboard)
+		grabkeys();
+}
+
+void
+maprequest(XEvent *e)
+{
+	static XWindowAttributes wa;
+	XMapRequestEvent *ev = &e->xmaprequest;
+
+	if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
+		return;
+	if (!wintoclient(ev->window))
+		manage(ev->window, &wa);
+}
+
+void
+motionnotify(XEvent *e)
+{
+	Bar *bar;
+	XMotionEvent *ev = &e->xmotion;
+
+	if ((bar = wintobar(ev->window))) {
+		barhover(e, bar);
+		return;
+	}
+
+}
+
+void
+movemouse(const Arg *arg)
+{
+	int x, y, ocx, ocy, nx, ny;
+	Client *c;
+	Monitor *m;
+	XEvent ev;
+	Time lasttime = 0;
+
+	if (!(c = selmon->sel))
+		return;
+	if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
+		return;
+	restack(selmon);
+	nx = ocx = c->x;
+	ny = ocy = c->y;
+	if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+		None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+		return;
+	if (!getrootptr(&x, &y))
+		return;
+	ignoreconfigurerequests = 1;
+	do {
+		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+		switch(ev.type) {
+		case ConfigureRequest:
+		case Expose:
+		case MapRequest:
+			handler[ev.type](&ev);
+			break;
+		case MotionNotify:
+			if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+				continue;
+			lasttime = ev.xmotion.time;
+
+			nx = ocx + (ev.xmotion.x - x);
+			ny = ocy + (ev.xmotion.y - y);
+			if (abs(selmon->wx - nx) < snap)
+				nx = selmon->wx;
+			else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
+				nx = selmon->wx + selmon->ww - WIDTH(c);
+			if (abs(selmon->wy - ny) < snap)
+				ny = selmon->wy;
+			else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
+				ny = selmon->wy + selmon->wh - HEIGHT(c);
+			if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+			&& (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) {
+				c->sfx = -9999; // disable savefloats when using movemouse
+				togglefloating(NULL);
+			}
+			if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
+				resize(c, nx, ny, c->w, c->h, 1);
+			}
+			break;
+		}
+	} while (ev.type != ButtonRelease);
+
+	XUngrabPointer(dpy, CurrentTime);
+	if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+		sendmon(c, m);
+		selmon = m;
+		focus(NULL);
+	}
+	/* save last known float coordinates */
+	if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
+		c->sfx = nx;
+		c->sfy = ny;
+	}
+	ignoreconfigurerequests = 0;
+}
+
+Client *
+nexttiled(Client *c)
+{
+	for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
+	return c;
+}
+
+void
+pop(Client *c)
+{
+	detach(c);
+	attach(c);
+	focus(c);
+	arrange(c->mon);
+}
+
+void
+propertynotify(XEvent *e)
+{
+	Client *c;
+	Window trans;
+	XPropertyEvent *ev = &e->xproperty;
+
+	if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
+		updatestatus();
+	} else if (ev->state == PropertyDelete) {
+		return; /* ignore */
+	} else if ((c = wintoclient(ev->window))) {
+		switch(ev->atom) {
+		default: break;
+		case XA_WM_TRANSIENT_FOR:
+			if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
+				(c->isfloating = (wintoclient(trans)) != NULL))
+				arrange(c->mon);
+			break;
+		case XA_WM_NORMAL_HINTS:
+			c->hintsvalid = 0;
+			break;
+		case XA_WM_HINTS:
+			updatewmhints(c);
+			if (c->isurgent)
+				drawbars();
+			break;
+		}
+		if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
+			updatetitle(c);
+			if (c == c->mon->sel)
+				drawbar(c->mon);
+		}
+	}
+}
+
+void
+quit(const Arg *arg)
+{
+	restart = arg->i;
+	running = 0;
+}
+
+Monitor *
+recttomon(int x, int y, int w, int h)
+{
+	Monitor *m, *r = selmon;
+	int a, area = 0;
+
+	for (m = mons; m; m = m->next)
+		if ((a = INTERSECT(x, y, w, h, m)) > area) {
+			area = a;
+			r = m;
+		}
+	return r;
+}
+
+void
+resize(Client *c, int x, int y, int w, int h, int interact)
+{
+	if (applysizehints(c, &x, &y, &w, &h, interact))
+		resizeclient(c, x, y, w, h);
+}
+
+void
+resizeclient(Client *c, int x, int y, int w, int h)
+{
+	XWindowChanges wc;
+
+	c->oldx = c->x; c->x = wc.x = x;
+	c->oldy = c->y; c->y = wc.y = y;
+	c->oldw = c->w; c->w = wc.width = w;
+	c->oldh = c->h; c->h = wc.height = h;
+	wc.border_width = c->bw;
+	XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+	configure(c);
+	XSync(dpy, False);
+}
+
+void
+resizemouse(const Arg *arg)
+{
+	int ocx, ocy, nw, nh, nx, ny;
+	int opx, opy, och, ocw;
+	int horizcorner, vertcorner;
+	unsigned int dui;
+	Window dummy;
+	Client *c;
+	Monitor *m;
+	XEvent ev;
+	Time lasttime = 0;
+
+	if (!(c = selmon->sel))
+		return;
+	if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+		return;
+	restack(selmon);
+	nx = ocx = c->x;
+	ny = ocy = c->y;
+	nh = c->h;
+	nw = c->w;
+	och = c->h;
+	ocw = c->w;
+	if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui))
+		return;
+	horizcorner = nx < c->w / 2;
+	vertcorner  = ny < c->h / 2;
+	if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+		None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess)
+		return;
+	ignoreconfigurerequests = 1;
+	do {
+		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+		switch(ev.type) {
+		case ConfigureRequest:
+		case Expose:
+		case MapRequest:
+			handler[ev.type](&ev);
+			break;
+		case MotionNotify:
+			if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+				continue;
+			lasttime = ev.xmotion.time;
+
+			nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x;
+			ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y;
+			nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1);
+			nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1);
+			if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
+			&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
+			{
+				if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) {
+					c->sfx = -9999; // disable savefloats when using resizemouse
+					togglefloating(NULL);
+				}
+			}
+			if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
+				resize(c, nx, ny, nw, nh, 1);
+			}
+			break;
+		}
+	} while (ev.type != ButtonRelease);
+
+	XUngrabPointer(dpy, CurrentTime);
+	while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+	if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+		sendmon(c, m);
+		selmon = m;
+		focus(NULL);
+	}
+	/* save last known float dimensions */
+	if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
+		c->sfx = nx;
+		c->sfy = ny;
+		c->sfw = nw;
+		c->sfh = nh;
+	}
+	ignoreconfigurerequests = 0;
+}
+
+void
+restack(Monitor *m)
+{
+	Client *c, *f = NULL;
+	XEvent ev;
+	XWindowChanges wc;
+
+	drawbar(m);
+	if (!m->sel)
+		return;
+	if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
+		XRaiseWindow(dpy, m->sel->win);
+	if (m->lt[m->sellt]->arrange) {
+		wc.stack_mode = Below;
+		if (m->bar) {
+			wc.sibling = m->bar->win;
+		} else {
+			for (f = m->stack; f && (f->isfloating || !ISVISIBLE(f)); f = f->snext); // find first tiled stack client
+			if (f)
+				wc.sibling = f->win;
+		}
+		for (c = m->stack; c; c = c->snext)
+			if (!c->isfloating && ISVISIBLE(c) && c != f) {
+				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+				wc.sibling = c->win;
+			}
+	}
+	XSync(dpy, False);
+	while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+void
+run(void)
+{
+	XEvent ev;
+	XSync(dpy, False);
+	/* main event loop */
+	while (running) {
+		struct pollfd pfd = {
+			.fd = ConnectionNumber(dpy),
+			.events = POLLIN,
+		};
+		int pending = XPending(dpy) > 0 || poll(&pfd, 1, -1) > 0;
+
+		if (!running)
+			break;
+		if (!pending)
+			continue;
+
+		XNextEvent(dpy, &ev);
+		if (handler[ev.type])
+			handler[ev.type](&ev); /* call handler */
+	}
+}
+
+void
+scan(void)
+{
+	unsigned int i, num;
+	Window d1, d2, *wins = NULL;
+	XWindowAttributes wa;
+
+	if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+		for (i = 0; i < num; i++) {
+			if (!XGetWindowAttributes(dpy, wins[i], &wa)
+			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
+				continue;
+			if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+				manage(wins[i], &wa);
+		}
+		for (i = 0; i < num; i++) { /* now the transients */
+			if (!XGetWindowAttributes(dpy, wins[i], &wa))
+				continue;
+			if (XGetTransientForHint(dpy, wins[i], &d1)
+			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
+				manage(wins[i], &wa);
+		}
+		XFree(wins);
+	}
+}
+
+void
+sendmon(Client *c, Monitor *m)
+{
+	if (c->mon == m)
+		return;
+	int hadfocus = (c == selmon->sel);
+	unfocus(c, 1, NULL);
+	detach(c);
+	detachstack(c);
+	arrange(c->mon);
+	c->mon = m;
+	c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+	attachx(c);
+	attachstack(c);
+	arrange(m);
+	if (hadfocus) {
+		focus(c);
+		restack(m);
+	} else {
+		focus(NULL);
+	}
+}
+
+void
+setclientstate(Client *c, long state)
+{
+	long data[] = { state, None };
+
+	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
+		PropModeReplace, (unsigned char *)data, 2);
+}
+
+int
+sendevent(Client *c, Atom proto)
+{
+	int n;
+	Atom *protocols;
+	int exists = 0;
+	XEvent ev;
+
+	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+		while (!exists && n--)
+			exists = protocols[n] == proto;
+		XFree(protocols);
+	}
+
+	if (exists) {
+		ev.type = ClientMessage;
+		ev.xclient.window = c->win;
+		ev.xclient.message_type = wmatom[WMProtocols];
+		ev.xclient.format = 32;
+		ev.xclient.data.l[0] = proto;
+		ev.xclient.data.l[1] = CurrentTime;
+		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+	}
+	return exists;
+}
+
+void
+setfocus(Client *c)
+{
+	if (!c->neverfocus) {
+		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+		XChangeProperty(dpy, root, netatom[NetActiveWindow],
+			XA_WINDOW, 32, PropModeReplace,
+			(unsigned char *) &(c->win), 1);
+	}
+	sendevent(c, wmatom[WMTakeFocus]);
+}
+
+void
+setfullscreen(Client *c, int fullscreen)
+{
+	if (fullscreen && !c->isfullscreen) {
+		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+			PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+		c->isfullscreen = 1;
+		c->oldbw = c->bw;
+		c->oldstate = c->isfloating;
+		c->bw = 0;
+		c->isfloating = 1;
+		resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+		XRaiseWindow(dpy, c->win);
+	} else if (!fullscreen && c->isfullscreen){
+		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+			PropModeReplace, (unsigned char*)0, 0);
+		c->isfullscreen = 0;
+		c->bw = c->oldbw;
+		c->isfloating = c->oldstate;
+		c->x = c->oldx;
+		c->y = c->oldy;
+		c->w = c->oldw;
+		c->h = c->oldh;
+		resizeclient(c, c->x, c->y, c->w, c->h);
+		arrange(c->mon);
+	}
+}
+
+void
+setlayout(const Arg *arg)
+{
+	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->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);
+	else
+		drawbar(selmon);
+}
+
+/* arg > 1.0 will set mfact absolutely */
+void
+setmfact(const Arg *arg)
+{
+	float f;
+
+	if (!arg || !selmon->lt[selmon->sellt]->arrange)
+		return;
+	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+	if (f < 0.05 || f > 0.95)
+		return;
+	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
+	arrange(selmon);
+}
+
+void
+setup(void)
+{
+	int i;
+	XSetWindowAttributes wa;
+	Atom utf8string;
+	/* clean up any zombies immediately */
+	sigchld(0);
+
+	signal(SIGHUP, sighup);
+	signal(SIGTERM, sigterm);
+
+	/* the one line of bloat that would have saved a lot of time for a lot of people */
+	putenv("_JAVA_AWT_WM_NONREPARENTING=1");
+
+	/* init screen */
+	screen = DefaultScreen(dpy);
+	sw = DisplayWidth(dpy, screen);
+	sh = DisplayHeight(dpy, screen);
+	root = RootWindow(dpy, screen);
+	drw = drw_create(dpy, screen, root, sw, sh);
+	if (!drw_font_create(drw, font))
+		die("no fonts could be loaded.");
+	lrpad = drw->fonts->h;
+	bh = drw->fonts->h + 2;
+	updategeom();
+	/* init atoms */
+	utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
+	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+	wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
+	clientatom[ClientFields] = XInternAtom(dpy, "_DWM_CLIENT_FIELDS", False);
+	clientatom[ClientTags] = XInternAtom(dpy, "_DWM_CLIENT_TAGS", False);
+	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
+	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+	netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
+	netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
+	netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
+	netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
+	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+	netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
+	/* init cursors */
+	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+	cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner);
+	cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner);
+	cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner);
+	cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner);
+	cursor[CurMove] = drw_cur_create(drw, XC_fleur);
+	/* init appearance */
+	scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+	for (i = 0; i < LENGTH(colors); i++)
+		scheme[i] = drw_scm_create(drw, colors[i], ColCount);
+
+	updatebars();
+	updatestatus();
+
+	/* supporting window for NetWMCheck */
+	wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
+	XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
+		PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+	XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
+		PropModeReplace, (unsigned char *) "dwm", 3);
+	XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
+		PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+	/* EWMH support per view */
+	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+		PropModeReplace, (unsigned char *) netatom, NetLast);
+	setnumdesktops();
+	setcurrentdesktop();
+	setdesktopnames();
+	setviewport();
+	XDeleteProperty(dpy, root, netatom[NetClientList]);
+	XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
+	/* select events */
+	wa.cursor = cursor[CurNormal]->cursor;
+	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
+		|ButtonPressMask|PointerMotionMask|EnterWindowMask
+		|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
+	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
+	XSelectInput(dpy, root, wa.event_mask);
+
+	grabkeys();
+	focus(NULL);
+}
+
+void
+seturgent(Client *c, int urg)
+{
+	XWMHints *wmh;
+
+	c->isurgent = urg;
+	if (!(wmh = XGetWMHints(dpy, c->win)))
+		return;
+	wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
+	XSetWMHints(dpy, c->win, wmh);
+	XFree(wmh);
+}
+
+void
+showhide(Client *c)
+{
+	if (!c)
+		return;
+	if (ISVISIBLE(c)) {
+		/* show clients top down */
+		if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) {
+			XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh);
+			resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
+			showhide(c->snext);
+			return;
+		}
+		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, 0);
+		showhide(c->snext);
+	} else {
+		/* hide clients bottom up */
+		showhide(c->snext);
+		XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
+	}
+}
+
+void
+sigchld(int unused)
+{
+	pid_t pid;
+
+	if (signal(SIGCHLD, sigchld) == SIG_ERR)
+		die("can't install SIGCHLD handler:");
+
+	while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
+		pid_t *p, *lim;
+
+		if (!(p = autostart_pids))
+			continue;
+		lim = &p[autostart_len];
+
+		for (; p < lim; p++) {
+			if (*p == pid) {
+				*p = -1;
+				break;
+			}
+		}
+	}
+}
+
+void
+spawn(const Arg *arg)
+{
+	struct sigaction sa;
+
+	if (fork() == 0)
+	{
+		if (dpy)
+			close(ConnectionNumber(dpy));
+
+		setsid();
+
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = 0;
+		sa.sa_handler = SIG_DFL;
+		sigaction(SIGCHLD, &sa, NULL);
+
+		execvp(((char **)arg->v)[0], (char **)arg->v);
+		die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
+	}
+}
+
+void
+tag(const Arg *arg)
+{
+
+	if (selmon->sel && arg->ui & TAGMASK) {
+		selmon->sel->tags = arg->ui & TAGMASK;
+		arrange(selmon);
+		focus(NULL);
+	}
+}
+
+void
+tagmon(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	Monitor *dest;
+	int restored;
+	if (!c || !mons->next)
+		return;
+	dest = dirtomon(arg->i);
+	savewindowfloatposition(c, c->mon);
+	restored = restorewindowfloatposition(c, dest);
+	if (restored && (!dest->lt[dest->sellt]->arrange || c->isfloating)) {
+		XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh);
+		resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 1);
+	}
+	if (c->isfullscreen) {
+		c->isfullscreen = 0;
+		sendmon(c, dest);
+		c->isfullscreen = 1;
+		resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+		XRaiseWindow(dpy, c->win);
+    } else if (c->isfloating && c->scratchkey != 0) {
+ 		sendmon(c, dest);
+ 		applyrules(c);
+ 		XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+	} else
+		sendmon(c, dest);
+}
+
+void
+togglebar(const Arg *arg)
+{
+	Bar *bar;
+	selmon->showbar = !selmon->showbar;
+	updatebarpos(selmon);
+	for (bar = selmon->bar; bar; bar = bar->next)
+		XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+	arrange(selmon);
+}
+
+void
+togglefloating(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	if (arg && arg->v)
+		c = (Client*)arg->v;
+	if (!c)
+		return;
+	if (c->isfullscreen) /* no support for fullscreen windows */
+		return;
+	c->isfloating = !c->isfloating || c->isfixed;
+	if (c->isfloating)
+		XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
+	else
+		XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+	if (c->isfloating) {
+		if (c->sfx != -9999) {
+			/* restore last known float dimensions */
+			resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
+		} else
+		resize(c, c->x, c->y, c->w, c->h, 0);
+	} else {
+		/* save last known float dimensions */
+		c->sfx = c->x;
+		c->sfy = c->y;
+		c->sfw = c->w;
+		c->sfh = c->h;
+	}
+	arrange(c->mon);
+
+	setfloatinghint(c);
+}
+
+void
+toggletag(const Arg *arg)
+{
+	unsigned int newtags;
+
+	if (!selmon->sel)
+		return;
+	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+	if (newtags) {
+		selmon->sel->tags = newtags;
+		arrange(selmon);
+		focus(NULL);
+	}
+	updatecurrentdesktop();
+}
+
+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->curtag = 0;
+		}
+		/* test if the user did not select the same tag */
+		if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+			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];
+		arrange(selmon);
+		focus(NULL);
+	}
+	updatecurrentdesktop();
+}
+
+void
+unfocus(Client *c, int setfocus, Client *nextfocus)
+{
+	if (!c)
+		return;
+	if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating) {
+		setfullscreen(c, 0);
+	}
+	grabbuttons(c, 0);
+	if (c->scratchkey != 0 && c->isfloating)
+		XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColFloat].pixel);
+	else if (c->scratchkey != 0)
+		XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
+	else if (c->isfloating)
+		XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
+	else
+		XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+	if (setfocus) {
+		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+		XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+	}
+}
+
+void
+unmanage(Client *c, int destroyed)
+{
+	Monitor *m;
+	XWindowChanges wc;
+
+	m = c->mon;
+
+	detach(c);
+	detachstack(c);
+	if (!destroyed) {
+		wc.border_width = c->oldbw;
+		XGrabServer(dpy); /* avoid race conditions */
+		XSetErrorHandler(xerrordummy);
+		XSelectInput(dpy, c->win, NoEventMask);
+		XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
+		XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+		setclientstate(c, WithdrawnState);
+		XSync(dpy, False);
+		XSetErrorHandler(xerror);
+		XUngrabServer(dpy);
+	}
+
+	free(c);
+	arrange(m);
+	focus(NULL);
+	updateclientlist();
+}
+
+void
+unmapnotify(XEvent *e)
+{
+	Client *c;
+	XUnmapEvent *ev = &e->xunmap;
+
+	if ((c = wintoclient(ev->window))) {
+		if (ev->send_event)
+			setclientstate(c, WithdrawnState);
+		else
+			unmanage(c, 0);
+	}
+}
+
+void
+updatebars(void)
+{
+	Bar *bar;
+	Monitor *m;
+	XSetWindowAttributes wa = {
+		.override_redirect = True,
+		.background_pixmap = ParentRelative,
+		.event_mask = ButtonPressMask|ExposureMask
+	};
+	XClassHint ch = {"dwm", "dwm"};
+	for (m = mons; m; m = m->next) {
+		for (bar = m->bar; bar; bar = bar->next) {
+			if (bar->external)
+				continue;
+			if (!bar->win) {
+				bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen),
+						CopyFromParent, DefaultVisual(dpy, screen),
+						CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+				XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor);
+				XMapRaised(dpy, bar->win);
+				XSetClassHint(dpy, bar->win, &ch);
+			}
+		}
+	}
+}
+
+void
+updatebarpos(Monitor *m)
+{
+
+	m->wx = m->mx;
+	m->wy = m->my;
+	m->ww = m->mw;
+	m->wh = m->mh;
+	Bar *bar;
+	int y_pad = 0;
+	int x_pad = 0;
+
+	for (bar = m->bar; bar; bar = bar->next) {
+		bar->bx = m->wx + x_pad;
+		bar->bw = m->ww - 2 * x_pad;
+	}
+
+	for (bar = m->bar; bar; bar = bar->next)
+		if (!m->showbar || !bar->showbar)
+			bar->by = -bar->bh - y_pad;
+
+	if (!m->showbar)
+		return;
+	for (bar = m->bar; bar; bar = bar->next) {
+		if (!bar->showbar)
+			continue;
+		if (bar->topbar)
+			m->wy = m->wy + bar->bh + y_pad;
+		m->wh -= y_pad + bar->bh;
+		bar->by = (bar->topbar ? m->wy - bar->bh : m->wy + m->wh);
+	}
+}
+
+void
+updateclientlist()
+{
+	Client *c;
+	Monitor *m;
+
+	XDeleteProperty(dpy, root, netatom[NetClientList]);
+	for (m = mons; m; m = m->next)
+		for (c = m->clients; c; c = c->next)
+			XChangeProperty(dpy, root, netatom[NetClientList],
+				XA_WINDOW, 32, PropModeAppend,
+				(unsigned char *) &(c->win), 1);
+
+	XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
+	for (m = mons; m; m = m->next)
+		for (c = m->stack; c; c = c->snext)
+			XChangeProperty(dpy, root, netatom[NetClientListStacking],
+				XA_WINDOW, 32, PropModeAppend,
+				(unsigned char *) &(c->win), 1);
+}
+
+int
+updategeom(void)
+{
+	int dirty = 0;
+
+#ifdef XINERAMA
+	if (XineramaIsActive(dpy)) {
+		int i, j, n, nn;
+		Client *c;
+		Monitor *m;
+		XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+		XineramaScreenInfo *unique = NULL;
+
+		for (n = 0, m = mons; m; m = m->next, n++);
+		/* only consider unique geometries as separate screens */
+		unique = ecalloc(nn, sizeof(XineramaScreenInfo));
+		for (i = 0, j = 0; i < nn; i++)
+			if (isuniquegeom(unique, j, &info[i]))
+				memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
+		XFree(info);
+		nn = j;
+		/* new monitors if nn > n */
+		for (i = n; i < nn; i++) {
+			for (m = mons; m && m->next; m = m->next);
+			if (m)
+				m->next = createmon();
+			else
+				mons = createmon();
+		}
+		for (i = 0, m = mons; i < nn && m; m = m->next, i++)
+			if (i >= n
+			|| unique[i].x_org != m->mx || unique[i].y_org != m->my
+			|| unique[i].width != m->mw || unique[i].height != m->mh)
+			{
+				dirty = 1;
+				m->num = i;
+				m->mx = m->wx = unique[i].x_org;
+				m->my = m->wy = unique[i].y_org;
+				m->mw = m->ww = unique[i].width;
+				m->mh = m->wh = unique[i].height;
+				updatebarpos(m);
+			}
+		/* removed monitors if n > nn */
+		for (i = nn; i < n; i++) {
+			for (m = mons; m && m->next; m = m->next);
+			while ((c = m->clients)) {
+				dirty = 1;
+				m->clients = c->next;
+				detachstack(c);
+				c->mon = mons;
+				attach(c);
+				attachstack(c);
+			}
+			if (m == selmon)
+				selmon = mons;
+			cleanupmon(m);
+		}
+		free(unique);
+	} else
+#endif /* XINERAMA */
+	{ /* default monitor setup */
+		if (!mons)
+			mons = createmon();
+		if (mons->mw != sw || mons->mh != sh) {
+			dirty = 1;
+			mons->mw = mons->ww = sw;
+			mons->mh = mons->wh = sh;
+			updatebarpos(mons);
+		}
+	}
+	if (dirty) {
+		selmon = mons;
+		selmon = wintomon(root);
+	}
+	return dirty;
+}
+
+void
+updatenumlockmask(void)
+{
+	unsigned int i, j;
+	XModifierKeymap *modmap;
+
+	numlockmask = 0;
+	modmap = XGetModifierMapping(dpy);
+	for (i = 0; i < 8; i++)
+		for (j = 0; j < modmap->max_keypermod; j++)
+			if (modmap->modifiermap[i * modmap->max_keypermod + j]
+				== XKeysymToKeycode(dpy, XK_Num_Lock))
+				numlockmask = (1 << i);
+	XFreeModifiermap(modmap);
+}
+
+void
+updatesizehints(Client *c)
+{
+	long msize;
+	XSizeHints size;
+
+	if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
+		/* size is uninitialized, ensure that size.flags aren't used */
+		size.flags = 0;
+	if (size.flags & PBaseSize) {
+		c->basew = size.base_width;
+		c->baseh = size.base_height;
+	} else if (size.flags & PMinSize) {
+		c->basew = size.min_width;
+		c->baseh = size.min_height;
+	} else
+		c->basew = c->baseh = 0;
+	if (size.flags & PResizeInc) {
+		c->incw = size.width_inc;
+		c->inch = size.height_inc;
+	} else
+		c->incw = c->inch = 0;
+	if (size.flags & PMaxSize) {
+		c->maxw = size.max_width;
+		c->maxh = size.max_height;
+	} else
+		c->maxw = c->maxh = 0;
+	if (size.flags & PMinSize) {
+		c->minw = size.min_width;
+		c->minh = size.min_height;
+	} else if (size.flags & PBaseSize) {
+		c->minw = size.base_width;
+		c->minh = size.base_height;
+	} else
+		c->minw = c->minh = 0;
+	if (size.flags & PAspect) {
+		c->mina = (float)size.min_aspect.y / size.min_aspect.x;
+		c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
+	} else
+		c->maxa = c->mina = 0.0;
+	if (size.flags & PSize)
+	{
+		c->basew = size.base_width;
+		c->baseh = size.base_height;
+		c->isfloating = 1;
+	}
+	checkfloatingrules(c);
+	c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+	c->hintsvalid = 1;
+}
+
+void
+updatestatus(void)
+{
+	Monitor *m;
+	if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
+		strcpy(stext, "dwm-"VERSION);
+	else
+		copyvalidchars(stext, rawstext);
+	for (m = mons; m; m = m->next)
+		drawbar(m);
+}
+
+void
+updatetitle(Client *c)
+{
+
+	if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
+		gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
+	if (c->name[0] == '\0') /* hack to mark broken clients */
+		strcpy(c->name, broken);
+
+}
+
+void
+updatewmhints(Client *c)
+{
+	XWMHints *wmh;
+
+	if ((wmh = XGetWMHints(dpy, c->win))) {
+		if (c == selmon->sel && wmh->flags & XUrgencyHint) {
+			wmh->flags &= ~XUrgencyHint;
+			XSetWMHints(dpy, c->win, wmh);
+		} else
+			c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
+		if (c->isurgent) {
+			if (c->isfloating)
+				XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel);
+			else
+				XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel);
+		}
+		if (wmh->flags & InputHint)
+			c->neverfocus = !wmh->input;
+		else
+			c->neverfocus = 0;
+		XFree(wmh);
+	}
+}
+
+void
+view(const Arg *arg)
+{
+	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+	{
+		return;
+	}
+	selmon->seltags ^= 1; /* toggle sel tagset */
+	if (arg->ui & TAGMASK)
+		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+	pertagview(arg);
+	arrange(selmon);
+	focus(NULL);
+	updatecurrentdesktop();
+}
+
+Client *
+wintoclient(Window w)
+{
+	Client *c;
+	Monitor *m;
+
+	for (m = mons; m; m = m->next)
+		for (c = m->clients; c; c = c->next)
+			if (c->win == w)
+				return c;
+	return NULL;
+}
+
+Monitor *
+wintomon(Window w)
+{
+	int x, y;
+	Client *c;
+	Monitor *m;
+	Bar *bar;
+
+	if (w == root && getrootptr(&x, &y))
+		return recttomon(x, y, 1, 1);
+	for (m = mons; m; m = m->next)
+		for (bar = m->bar; bar; bar = bar->next)
+			if (w == bar->win)
+				return m;
+	if ((c = wintoclient(w)))
+		return c->mon;
+	return selmon;
+}
+
+/* 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. */
+int
+xerror(Display *dpy, XErrorEvent *ee)
+{
+	if (ee->error_code == BadWindow
+	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
+	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
+	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
+	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
+	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
+	|| (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
+	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
+	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
+		return 0;
+	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
+		ee->request_code, ee->error_code);
+	return xerrorxlib(dpy, ee); /* may call exit */
+}
+
+int
+xerrordummy(Display *dpy, XErrorEvent *ee)
+{
+	return 0;
+}
+
+/* Startup Error handler to check if another window manager
+ * is already running. */
+int
+xerrorstart(Display *dpy, XErrorEvent *ee)
+{
+	die("dwm: another window manager is already running");
+	return -1;
+}
+
+void
+zoom(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	if (arg && arg->v)
+		c = (Client*)arg->v;
+	if (!c)
+		return;
+
+	if (!c->mon->lt[c->mon->sellt]->arrange || !c || c->isfloating)
+		return;
+
+	if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
+		return;
+	pop(c);
+}
+
+int
+main(int argc, char *argv[])
+{
+	if (argc == 2 && !strcmp("-v", argv[1]))
+		die("dwm-"VERSION);
+	else if (argc != 1)
+		die("usage: dwm [-v]");
+	if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
+		fputs("warning: no locale support\n", stderr);
+	if (!(dpy = XOpenDisplay(NULL)))
+		die("dwm: cannot open display");
+	checkotherwm();
+	autostart_exec();
+	setup();
+#ifdef __OpenBSD__
+	if (pledge("stdio rpath proc exec", NULL) == -1)
+		die("pledge");
+#endif /* __OpenBSD__ */
+	scan();
+	run();
+	cleanup();
+	XCloseDisplay(dpy);
+	if (restart)
+		execvp(argv[0], argv);
+	return EXIT_SUCCESS;
+}
+
diff --git a/dwm.desktop b/dwm.desktop
new file mode 100644
index 0000000..b0c3354
--- /dev/null
+++ b/dwm.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Dwm
+Comment=Dynamic window manager
+Exec=dwm
+Icon=dwm
+Type=XSession
diff --git a/dwm.png b/dwm.png
new file mode 100644
index 0000000..b1f9ba7
Binary files /dev/null and b/dwm.png differ
diff --git a/flexipatch-finalizer b/flexipatch-finalizer
deleted file mode 160000
index 37e8cb6..0000000
--- a/flexipatch-finalizer
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 37e8cb6145f189b805aa58c7d560b1adf51377a7
diff --git a/patch/attachx.c b/patch/attachx.c
new file mode 100644
index 0000000..bdd99aa
--- /dev/null
+++ b/patch/attachx.c
@@ -0,0 +1,28 @@
+void
+attachx(Client *c)
+{
+	Client *at;
+
+	if (c->idx > 0) { /* then the client has a designated position in the client list */
+		for (at = c->mon->clients; at; at = at->next) {
+			if (c->idx < at->idx) {
+				c->next = at;
+				c->mon->clients = c;
+				return;
+			} else if (at->idx <= c->idx && (!at->next || c->idx <= at->next->idx)) {
+				c->next = at->next;
+				at->next = c;
+				return;
+			}
+		}
+	}
+
+	for (at = c->mon->clients; at && at->next; at = at->next);
+	if (at) {
+		at->next = c;
+		c->next = NULL;
+		return;
+	}
+	attach(c); // master (default)
+}
+
diff --git a/patch/attachx.h b/patch/attachx.h
new file mode 100644
index 0000000..e522d27
--- /dev/null
+++ b/patch/attachx.h
@@ -0,0 +1,2 @@
+static void attachx(Client *c);
+
diff --git a/patch/bar.c b/patch/bar.c
new file mode 100644
index 0000000..65e1a69
--- /dev/null
+++ b/patch/bar.c
@@ -0,0 +1,39 @@
+void
+barhover(XEvent *e, Bar *bar)
+{
+	const BarRule *br;
+	Monitor *m = bar->mon;
+	XMotionEvent *ev = &e->xmotion;
+	BarArg barg = { 0, 0, 0, 0 };
+	int r;
+
+	for (r = 0; r < LENGTH(barrules); r++) {
+		br = &barrules[r];
+		if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->hoverfunc == NULL)
+			continue;
+		if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
+			continue;
+		if (bar->x[r] > ev->x || ev->x > bar->x[r] + bar->w[r])
+			continue;
+
+		barg.x = ev->x - bar->x[r];
+		barg.y = ev->y - bar->borderpx;
+		barg.w = bar->w[r];
+		barg.h = bar->bh - 2 * bar->borderpx;
+
+		br->hoverfunc(bar, &barg, ev);
+		break;
+	}
+}
+
+Bar *
+wintobar(Window win)
+{
+	Monitor *m;
+	Bar *bar;
+	for (m = mons; m; m = m->next)
+		for (bar = m->bar; bar; bar = bar->next)
+			if (bar->win == win)
+				return bar;
+	return NULL;
+}
diff --git a/patch/bar.h b/patch/bar.h
new file mode 100644
index 0000000..3e006dc
--- /dev/null
+++ b/patch/bar.h
@@ -0,0 +1,2 @@
+static void barhover(XEvent *e, Bar *bar);
+static Bar *wintobar(Window win);
diff --git a/patch/bar_dwmblocks.c b/patch/bar_dwmblocks.c
new file mode 100644
index 0000000..0a4b097
--- /dev/null
+++ b/patch/bar_dwmblocks.c
@@ -0,0 +1,41 @@
+static int statussig;
+pid_t statuspid = -1;
+
+pid_t
+getstatusbarpid()
+{
+	char buf[32], *str = buf, *c;
+	FILE *fp;
+
+	if (statuspid > 0) {
+		snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid);
+		if ((fp = fopen(buf, "r"))) {
+			fgets(buf, sizeof(buf), fp);
+			while ((c = strchr(str, '/')))
+				str = c + 1;
+			fclose(fp);
+			if (!strcmp(str, STATUSBAR))
+				return statuspid;
+		}
+	}
+	if (!(fp = popen("pgrep -o "STATUSBAR, "r")))
+		return -1;
+	fgets(buf, sizeof(buf), fp);
+	pclose(fp);
+	return strtol(buf, NULL, 10);
+}
+
+void
+sigstatusbar(const Arg *arg)
+{
+	union sigval sv;
+
+	if (!statussig)
+		return;
+	if ((statuspid = getstatusbarpid()) <= 0)
+		return;
+
+	sv.sival_int = arg->i;
+	sigqueue(statuspid, SIGRTMIN+statussig, sv);
+}
+
diff --git a/patch/bar_dwmblocks.h b/patch/bar_dwmblocks.h
new file mode 100644
index 0000000..4db9467
--- /dev/null
+++ b/patch/bar_dwmblocks.h
@@ -0,0 +1,3 @@
+static int getstatusbarpid();
+static void sigstatusbar(const Arg *arg);
+
diff --git a/patch/bar_ewmhtags.c b/patch/bar_ewmhtags.c
new file mode 100644
index 0000000..46ee5e4
--- /dev/null
+++ b/patch/bar_ewmhtags.c
@@ -0,0 +1,52 @@
+void
+setcurrentdesktop(void)
+{
+	long data[] = { 0 };
+	XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+void
+setdesktopnames(void)
+{
+	int i;
+	XTextProperty text;
+	char *tags[NUMTAGS];
+	for (i = 0; i < NUMTAGS; i++)
+		tags[i] = tagicon(selmon, i);
+	Xutf8TextListToTextProperty(dpy, tags, NUMTAGS, XUTF8StringStyle, &text);
+	XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
+}
+
+void
+setfloatinghint(Client *c)
+{
+	Atom target = XInternAtom(dpy, "_IS_FLOATING", 0);
+	unsigned int floating[1] = {c->isfloating};
+	XChangeProperty(dpy, c->win, target, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)floating, 1);
+}
+
+void
+setnumdesktops(void)
+{
+	long data[] = { NUMTAGS };
+	XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+void
+setviewport(void)
+{
+	long data[] = { 0, 0 };
+	XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2);
+}
+
+void
+updatecurrentdesktop(void)
+{
+	long rawdata[] = { selmon->tagset[selmon->seltags] };
+	int i = 0;
+	while (*rawdata >> (i + 1)) {
+		i++;
+	}
+	long data[] = { i };
+	XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
diff --git a/patch/bar_ewmhtags.h b/patch/bar_ewmhtags.h
new file mode 100644
index 0000000..4d6a74b
--- /dev/null
+++ b/patch/bar_ewmhtags.h
@@ -0,0 +1,7 @@
+static void setcurrentdesktop(void);
+static void setdesktopnames(void);
+static void setfloatinghint(Client *c);
+static void setnumdesktops(void);
+static void setviewport(void);
+static void updatecurrentdesktop(void);
+
diff --git a/patch/bar_indicators.c b/patch/bar_indicators.c
new file mode 100644
index 0000000..b003fc8
--- /dev/null
+++ b/patch/bar_indicators.c
@@ -0,0 +1,104 @@
+/* Indicator properties, you can override these in your config.h if you want. */
+#ifndef TAGSINDICATOR
+#define TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
+#endif
+#ifndef TAGSPX
+#define TAGSPX 5        // # pixels for tag grid boxes
+#endif
+#ifndef TAGSROWS
+#define TAGSROWS 3      // # rows in tag grid (9 tags, e.g. 3x3)
+#endif
+
+void
+drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type)
+{
+	int i, boxw, boxs, indn = 0;
+	if (!(occ & 1 << tag) || type == INDICATOR_NONE)
+		return;
+
+	boxs = drw->fonts->h / 9;
+	boxw = drw->fonts->h / 6 + 2;
+	if (filled == -1)
+		filled = m == selmon && m->sel && m->sel->tags & 1 << tag;
+
+	switch (type) {
+	default:
+	case INDICATOR_TOP_LEFT_SQUARE:
+		drw_rect(drw, x + boxs, y + boxs, boxw, boxw, filled, invert);
+		break;
+	case INDICATOR_TOP_LEFT_LARGER_SQUARE:
+		drw_rect(drw, x + boxs + 2, y + boxs+1, boxw+1, boxw+1, filled, invert);
+		break;
+	case INDICATOR_TOP_BAR:
+		drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), boxw/2, filled, invert);
+		break;
+	case INDICATOR_TOP_BAR_SLIM:
+		drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), 1, 0, invert);
+		break;
+	case INDICATOR_BOTTOM_BAR:
+		drw_rect(drw, x + boxw, y + h - boxw/2, w - ( 2 * boxw + 1), boxw/2, filled, invert);
+		break;
+	case INDICATOR_BOTTOM_BAR_SLIM:
+		drw_rect(drw, x + boxw, y + h - 1, w - ( 2 * boxw + 1), 1, 0, invert);
+		break;
+	case INDICATOR_BOX:
+		drw_rect(drw, x + boxw, y, w - 2 * boxw, h, 0, invert);
+		break;
+	case INDICATOR_BOX_WIDER:
+		drw_rect(drw, x + boxw/2, y, w - boxw, h, 0, invert);
+		break;
+	case INDICATOR_BOX_FULL:
+		drw_rect(drw, x, y, w - 2, h, 0, invert);
+		break;
+	case INDICATOR_CLIENT_DOTS:
+		for (c = m->clients; c; c = c->next) {
+			if (c->tags & (1 << tag)) {
+				drw_rect(drw, x, 1 + (indn * 2), m->sel == c ? 6 : 1, 1, 1, invert);
+				indn++;
+			}
+			if (h <= 1 + (indn * 2)) {
+				indn = 0;
+				x += 2;
+			}
+		}
+		break;
+	case INDICATOR_RIGHT_TAGS:
+		if (!c)
+			break;
+		for (i = 0; i < NUMTAGS; i++) {
+			drw_rect(drw,
+				( x + w - 2 - ((NUMTAGS / TAGSROWS) * TAGSPX)
+					- (i % (NUMTAGS/TAGSROWS)) + ((i % (NUMTAGS / TAGSROWS)) * TAGSPX)
+				),
+				( y + 2 + ((i / (NUMTAGS/TAGSROWS)) * TAGSPX)
+					- ((i / (NUMTAGS/TAGSROWS)))
+				),
+				TAGSPX, TAGSPX, (c->tags >> i) & 1, 0
+			);
+		}
+		break;
+	case INDICATOR_PLUS_AND_LARGER_SQUARE:
+		boxs += 2;
+		boxw += 2;
+		/* falls through */
+	case INDICATOR_PLUS_AND_SQUARE:
+		drw_rect(drw, x + boxs, y + boxs, boxw % 2 ? boxw : boxw + 1, boxw % 2 ? boxw : boxw + 1, filled, invert);
+		/* falls through */
+	case INDICATOR_PLUS:
+		if (!(boxw % 2))
+			boxw += 1;
+		drw_rect(drw, x + boxs + boxw / 2, y + boxs, 1, boxw, filled, invert); // |
+		drw_rect(drw, x + boxs, y + boxs + boxw / 2, boxw + 1, 1, filled, invert); // ‒
+		break;
+	}
+}
+
+void
+drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert)
+{
+	if (c->isfloating)
+		drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatindicatortype);
+	else
+		drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, tiledindicatortype);
+}
+
diff --git a/patch/bar_indicators.h b/patch/bar_indicators.h
new file mode 100644
index 0000000..c66e4f0
--- /dev/null
+++ b/patch/bar_indicators.h
@@ -0,0 +1,21 @@
+enum {
+	INDICATOR_NONE,
+	INDICATOR_TOP_LEFT_SQUARE,
+	INDICATOR_TOP_LEFT_LARGER_SQUARE,
+	INDICATOR_TOP_BAR,
+	INDICATOR_TOP_BAR_SLIM,
+	INDICATOR_BOTTOM_BAR,
+	INDICATOR_BOTTOM_BAR_SLIM,
+	INDICATOR_BOX,
+	INDICATOR_BOX_WIDER,
+	INDICATOR_BOX_FULL,
+	INDICATOR_CLIENT_DOTS,
+	INDICATOR_RIGHT_TAGS,
+	INDICATOR_PLUS,
+	INDICATOR_PLUS_AND_SQUARE,
+	INDICATOR_PLUS_AND_LARGER_SQUARE,
+};
+
+static void drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type);
+static void drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert);
+
diff --git a/patch/bar_ltsymbol.c b/patch/bar_ltsymbol.c
new file mode 100644
index 0000000..1fbd1b8
--- /dev/null
+++ b/patch/bar_ltsymbol.c
@@ -0,0 +1,18 @@
+int
+width_ltsymbol(Bar *bar, BarArg *a)
+{
+	return TEXTW(bar->mon->ltsymbol);
+}
+
+int
+draw_ltsymbol(Bar *bar, BarArg *a)
+{
+	return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, bar->mon->ltsymbol, 0, False);
+}
+
+int
+click_ltsymbol(Bar *bar, Arg *arg, BarArg *a)
+{
+	return ClkLtSymbol;
+}
+
diff --git a/patch/bar_ltsymbol.h b/patch/bar_ltsymbol.h
new file mode 100644
index 0000000..4de5720
--- /dev/null
+++ b/patch/bar_ltsymbol.h
@@ -0,0 +1,4 @@
+static int width_ltsymbol(Bar *bar, BarArg *a);
+static int draw_ltsymbol(Bar *bar, BarArg *a);
+static int click_ltsymbol(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_status.c b/patch/bar_status.c
new file mode 100644
index 0000000..19ff219
--- /dev/null
+++ b/patch/bar_status.c
@@ -0,0 +1,18 @@
+int
+width_status(Bar *bar, BarArg *a)
+{
+	return TEXTWM(stext);
+}
+
+int
+draw_status(Bar *bar, BarArg *a)
+{
+	return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, stext, 0, True);
+}
+
+int
+click_status(Bar *bar, Arg *arg, BarArg *a)
+{
+	return ClkStatusText;
+}
+
diff --git a/patch/bar_status.h b/patch/bar_status.h
new file mode 100644
index 0000000..c580597
--- /dev/null
+++ b/patch/bar_status.h
@@ -0,0 +1,4 @@
+static int width_status(Bar *bar, BarArg *a);
+static int draw_status(Bar *bar, BarArg *a);
+static int click_status(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_statuscmd.c b/patch/bar_statuscmd.c
new file mode 100644
index 0000000..2e74f9f
--- /dev/null
+++ b/patch/bar_statuscmd.c
@@ -0,0 +1,44 @@
+int
+click_statuscmd(Bar *bar, Arg *arg, BarArg *a)
+{
+	return click_statuscmd_text(arg, a->x, rawstext);
+}
+
+int
+click_statuscmd_text(Arg *arg, int rel_x, char *text)
+{
+	int i = -1;
+	int x = 0;
+	char ch;
+	statussig = -1;
+	while (text[++i]) {
+		if ((unsigned char)text[i] < ' ') {
+			ch = text[i];
+			text[i] = '\0';
+			x += TEXTWM(text) - lrpad;
+			text[i] = ch;
+			text += i+1;
+			i = -1;
+			if (x >= rel_x && statussig != -1)
+				break;
+			statussig = ch;
+		}
+	}
+	if (statussig == -1)
+		statussig = 0;
+	return ClkStatusText;
+}
+
+void
+copyvalidchars(char *text, char *rawtext)
+{
+	int i = -1, j = 0;
+
+	while (rawtext[++i]) {
+		if ((unsigned char)rawtext[i] >= ' ') {
+			text[j++] = rawtext[i];
+		}
+	}
+	text[j] = '\0';
+}
+
diff --git a/patch/bar_statuscmd.h b/patch/bar_statuscmd.h
new file mode 100644
index 0000000..1ec24a6
--- /dev/null
+++ b/patch/bar_statuscmd.h
@@ -0,0 +1,9 @@
+static int click_statuscmd(Bar *bar, Arg *arg, BarArg *a);
+static int click_statuscmd_text(Arg *arg, int rel_x, char *text);
+static void copyvalidchars(char *text, char *rawtext);
+
+typedef struct {
+	const char *cmd;
+	int id;
+} StatusCmd;
+
diff --git a/patch/bar_tagicons.c b/patch/bar_tagicons.c
new file mode 100644
index 0000000..57d1629
--- /dev/null
+++ b/patch/bar_tagicons.c
@@ -0,0 +1,9 @@
+char *
+tagicon(Monitor *m, int tag)
+{
+	int tagindex = tag + NUMTAGS * m->num;
+	if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS]))
+		tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]);
+	return tagicons[DEFAULT_TAGS][tagindex];
+}
+
diff --git a/patch/bar_tagicons.h b/patch/bar_tagicons.h
new file mode 100644
index 0000000..16fad2a
--- /dev/null
+++ b/patch/bar_tagicons.h
@@ -0,0 +1,8 @@
+enum {
+	DEFAULT_TAGS,
+	ALTERNATIVE_TAGS,
+	ALT_TAGS_DECORATION,
+};
+
+static char * tagicon(Monitor *m, int tag);
+
diff --git a/patch/bar_tags.c b/patch/bar_tags.c
new file mode 100644
index 0000000..8aa37b2
--- /dev/null
+++ b/patch/bar_tags.c
@@ -0,0 +1,81 @@
+int
+width_tags(Bar *bar, BarArg *a)
+{
+	int w, i;
+	Client *c;
+	unsigned int occ = 0;
+	for (c = bar->mon->clients; c; c = c->next)
+		occ |= c->tags == 255 ? 0 : c->tags;
+
+	for (w = 0, i = 0; i < NUMTAGS; i++) {
+		if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+			continue;
+		w += TEXTW(tagicon(bar->mon, i));
+	}
+	return w;
+}
+
+int
+draw_tags(Bar *bar, BarArg *a)
+{
+	int invert;
+	int w, x = a->x;
+	unsigned int i, occ = 0, urg = 0;
+	char *icon;
+	Client *c;
+	Monitor *m = bar->mon;
+
+	for (c = m->clients; c; c = c->next) {
+		occ |= c->tags == 255 ? 0 : c->tags;
+		if (c->isurgent)
+			urg |= c->tags;
+	}
+	for (i = 0; i < NUMTAGS; i++) {
+		/* do not draw vacant tags */
+		if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+			continue;
+
+		icon = tagicon(bar->mon, i);
+		invert = 0;
+		w = TEXTW(icon);
+		drw_setscheme(drw, scheme[
+			m->tagset[m->seltags] & 1 << i
+			? SchemeTagsSel
+			: urg & 1 << i
+			? SchemeUrg
+			: SchemeTagsNorm
+		]);
+		drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False);
+		drawindicator(m, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype);
+		x += w;
+	}
+
+	return 1;
+}
+
+int
+click_tags(Bar *bar, Arg *arg, BarArg *a)
+{
+	int i = 0, x = 0;
+	Client *c;
+	unsigned int occ = 0;
+	for (c = bar->mon->clients; c; c = c->next)
+		occ |= c->tags == 255 ? 0 : c->tags;
+
+	do {
+		if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+			continue;
+		x += TEXTW(tagicon(bar->mon, i));
+	} while (a->x >= x && ++i < NUMTAGS);
+	if (i < NUMTAGS) {
+		arg->ui = 1 << i;
+	}
+	return ClkTagBar;
+}
+
+int
+hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev)
+{
+
+	return 1;
+}
diff --git a/patch/bar_tags.h b/patch/bar_tags.h
new file mode 100644
index 0000000..70040d2
--- /dev/null
+++ b/patch/bar_tags.h
@@ -0,0 +1,4 @@
+static int width_tags(Bar *bar, BarArg *a);
+static int draw_tags(Bar *bar, BarArg *a);
+static int click_tags(Bar *bar, Arg *arg, BarArg *a);
+static int hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev);
diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c
new file mode 100644
index 0000000..4468f93
--- /dev/null
+++ b/patch/bar_wintitle.c
@@ -0,0 +1,49 @@
+int
+width_wintitle(Bar *bar, BarArg *a)
+{
+	return a->w;
+}
+
+int
+draw_wintitle(Bar *bar, BarArg *a)
+{
+	int x = a->x, w = a->w;
+	Monitor *m = bar->mon;
+	Client *c = m->sel;
+
+	if (!c) {
+		drw_setscheme(drw, scheme[SchemeTitleNorm]);
+		drw_rect(drw, x, a->y, w, a->h, 1, 1);
+		return 0;
+	}
+
+	int tpad = lrpad / 2;
+	int tx = x;
+	int tw = w;
+
+	drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]);
+	XSetErrorHandler(xerrordummy);
+
+	if (w <= TEXTW("A") - lrpad + tpad) // reduce text padding if wintitle is too small
+		tpad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2);
+
+	XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
+	XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, a->y, w, a->h);
+
+	tx += tpad;
+	tw -= lrpad;
+
+	drw_text(drw, tx, a->y, tw, a->h, 0, c->name, 0, False);
+
+	XSync(dpy, False);
+	XSetErrorHandler(xerror);
+	drawstateindicator(m, c, 1, x, a->y, w, a->h, 0, 0, c->isfixed);
+	return 1;
+}
+
+int
+click_wintitle(Bar *bar, Arg *arg, BarArg *a)
+{
+	return ClkWinTitle;
+}
+
diff --git a/patch/bar_wintitle.h b/patch/bar_wintitle.h
new file mode 100644
index 0000000..7e8cce5
--- /dev/null
+++ b/patch/bar_wintitle.h
@@ -0,0 +1,4 @@
+static int width_wintitle(Bar *bar, BarArg *a);
+static int draw_wintitle(Bar *bar, BarArg *a);
+static int click_wintitle(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/cool_autostart.c b/patch/cool_autostart.c
new file mode 100644
index 0000000..848f5ab
--- /dev/null
+++ b/patch/cool_autostart.c
@@ -0,0 +1,37 @@
+/* dwm will keep pid's of processes from autostart array and kill them at quit */
+static pid_t *autostart_pids;
+static size_t autostart_len;
+
+/* execute command from autostart array */
+static void
+autostart_exec()
+{
+	const char *const *p;
+	struct sigaction sa;
+	size_t i = 0;
+
+	/* count entries */
+	for (p = autostart; *p; autostart_len++, p++)
+		while (*++p);
+
+	autostart_pids = malloc(autostart_len * sizeof(pid_t));
+	for (p = autostart; *p; i++, p++) {
+		if ((autostart_pids[i] = fork()) == 0) {
+			setsid();
+
+			/* Restore SIGCHLD sighandler to default before spawning a program */
+			sigemptyset(&sa.sa_mask);
+			sa.sa_flags = 0;
+			sa.sa_handler = SIG_DFL;
+			sigaction(SIGCHLD, &sa, NULL);
+
+			execvp(*p, (char *const *)p);
+			fprintf(stderr, "dwm: execvp %s\n", *p);
+			perror(" failed");
+			_exit(EXIT_FAILURE);
+		}
+		/* skip arguments */
+		while (*++p);
+	}
+}
+
diff --git a/patch/cool_autostart.h b/patch/cool_autostart.h
new file mode 100644
index 0000000..5534d99
--- /dev/null
+++ b/patch/cool_autostart.h
@@ -0,0 +1,2 @@
+static void autostart_exec(void);
+
diff --git a/patch/floatpos.c b/patch/floatpos.c
new file mode 100644
index 0000000..d935d23
--- /dev/null
+++ b/patch/floatpos.c
@@ -0,0 +1,179 @@
+void
+floatpos(const Arg *arg)
+{
+	Client *c = selmon->sel;
+
+	if (!c || (selmon->lt[selmon->sellt]->arrange && !c->isfloating))
+		return;
+
+	setfloatpos(c, (char *)arg->v);
+	resizeclient(c, c->x, c->y, c->w, c->h);
+
+}
+
+void
+setfloatpos(Client *c, const char *floatpos)
+{
+	char xCh, yCh, wCh, hCh;
+	int x, y, w, h, wx, ww, wy, wh;
+
+	if (!c || !floatpos)
+		return;
+	if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+		return;
+
+	switch(sscanf(floatpos, "%d%c %d%c %d%c %d%c", &x, &xCh, &y, &yCh, &w, &wCh, &h, &hCh)) {
+		case 4:
+			if (xCh == 'w' || xCh == 'W') {
+				w = x; wCh = xCh;
+				h = y; hCh = yCh;
+				x = -1; xCh = 'C';
+				y = -1; yCh = 'C';
+			} else if (xCh == 'p' || xCh == 'P') {
+				w = x; wCh = xCh;
+				h = y; hCh = yCh;
+				x = 0; xCh = 'G';
+				y = 0; yCh = 'G';
+			} else if (xCh == 'm' || xCh == 'M') {
+				getrootptr(&x, &y);
+			} else {
+				w = 0; wCh = 0;
+				h = 0; hCh = 0;
+			}
+			break;
+		case 8:
+			if (xCh == 'm' || xCh == 'M')
+				getrootptr(&x, &y);
+			break;
+		default:
+			return;
+	}
+
+	wx = c->mon->wx;
+	wy = c->mon->wy;
+	ww = c->mon->ww;
+	wh = c->mon->wh;
+
+	getfloatpos(x, xCh, w, wCh, wx, ww, c->x, c->w, c->bw, floatposgrid_x, &c->x, &c->w);
+	getfloatpos(y, yCh, h, hCh, wy, wh, c->y, c->h, c->bw, floatposgrid_y, &c->y, &c->h);
+}
+
+/* p - position, s - size, cp and cs represents current position and size */
+void
+getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s)
+{
+	int abs_p, abs_s, i, delta, rest;
+
+	abs_p = pCh == 'A' || pCh == 'a';
+	abs_s = sCh == 'A' || sCh == 'a';
+
+	cs += 2*cbw;
+
+	switch(pCh) {
+	case 'A': // absolute position
+		cp = pos;
+		break;
+	case 'a': // absolute relative position
+		cp += pos;
+		break;
+	case 'y':
+	case 'x': // client relative position
+		cp = MIN(cp + pos, min_p + max_s);
+		break;
+	case 'Y':
+	case 'X': // client position relative to monitor
+		cp = min_p + MIN(pos, max_s);
+		break;
+	case 'S': // fixed client position (sticky)
+	case 'C': // fixed client position (center)
+	case 'Z': // fixed client right-hand position (position + size)
+		if (pos == -1)
+			break;
+		pos = MAX(MIN(pos, max_s), 0);
+		if (pCh == 'Z')
+			cs = abs((cp + cs) - (min_p + pos));
+		else if (pCh == 'C')
+			cs = abs((cp + cs / 2) - (min_p + pos));
+		else
+			cs = abs(cp - (min_p + pos));
+		cp = min_p + pos;
+		sCh = 0; // size determined by position, override defined size
+		break;
+	case 'G': // grid
+		if (pos <= 0)
+			pos = defgrid; // default configurable
+		if (size == 0 || pos < 2 || (sCh != 'p' && sCh != 'P'))
+			break;
+		delta = (max_s - cs) / (pos - 1);
+		rest = max_s - cs - delta * (pos - 1);
+		if (sCh == 'P') {
+			if (size < 1 || size > pos)
+				break;
+			cp = min_p + delta * (size - 1);
+		} else {
+			for (i = 0; i < pos && cp >= min_p + delta * i + (i > pos - rest ? i + rest - pos + 1 : 0); i++);
+			cp = min_p + delta * (MAX(MIN(i + size, pos), 1) - 1) + (i > pos - rest ? i + rest - pos + 1 : 0);
+		}
+		break;
+	}
+
+	switch(sCh) {
+	case 'A': // absolute size
+		cs = size;
+		break;
+	case 'a': // absolute relative size
+		cs = MAX(1, cs + size);
+		break;
+	case '%': // client size percentage in relation to monitor window area size
+		if (size <= 0)
+			break;
+		size = max_s * MIN(size, 100) / 100;
+		/* falls through */
+	case 'h':
+	case 'w': // size relative to client
+		if (sCh == 'w' || sCh == 'h') {
+			if (size == 0)
+				break;
+			size += cs;
+		}
+		/* falls through */
+	case 'H':
+	case 'W': // normal size, position takes precedence
+		if (pCh == 'S' && cp + size > min_p + max_s)
+			size = min_p + max_s - cp;
+		else if (size > max_s)
+			size = max_s;
+
+		if (pCh == 'C') { // fixed client center, expand or contract client
+			delta = size - cs;
+			if (delta < 0 || (cp - delta / 2 + size <= min_p + max_s))
+				cp -= delta / 2;
+			else if (cp - delta / 2 < min_p)
+				cp = min_p;
+			else if (delta)
+				cp = min_p + max_s;
+		} else if (pCh == 'Z')
+			cp -= size - cs;
+
+		cs = size;
+		break;
+	}
+
+	if (pCh == '%') // client mid-point position in relation to monitor window area size
+		cp = min_p + max_s * MAX(MIN(pos, 100), 0) / 100 - (cs) / 2;
+	if (pCh == 'm' || pCh == 'M')
+		cp = pos - cs / 2;
+
+	if (!abs_p && cp < min_p)
+		cp = min_p;
+	if (cp + cs > min_p + max_s && !(abs_p && abs_s)) {
+		if (abs_p || cp == min_p)
+			cs = min_p + max_s - cp;
+		else
+			cp = min_p + max_s - cs;
+	}
+
+	*out_p = cp;
+	*out_s = MAX(cs - 2*cbw, 1);
+}
+
diff --git a/patch/floatpos.h b/patch/floatpos.h
new file mode 100644
index 0000000..ecdcf0b
--- /dev/null
+++ b/patch/floatpos.h
@@ -0,0 +1,4 @@
+static void floatpos(const Arg *arg);
+static void setfloatpos(Client *c, const char *floatpos);
+static void getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s);
+
diff --git a/patch/focusdir.c b/patch/focusdir.c
new file mode 100644
index 0000000..65798c5
--- /dev/null
+++ b/patch/focusdir.c
@@ -0,0 +1,66 @@
+void
+focusdir(const Arg *arg)
+{
+	Client *s = selmon->sel, *f = NULL, *c, *next;
+
+	if (!s)
+		return;
+
+	unsigned int score = -1;
+	unsigned int client_score;
+	int dist;
+	int dirweight = 20;
+	int isfloating = s->isfloating;
+
+	next = s->next;
+	if (!next)
+		next = s->mon->clients;
+	for (c = next; c != s; c = next) {
+
+		next = c->next;
+		if (!next)
+			next = s->mon->clients;
+
+		if (!ISVISIBLE(c) || c->isfloating != isfloating) // || HIDDEN(c)
+			continue;
+
+		switch (arg->i) {
+		case 0: // left
+			dist = s->x - c->x - c->w;
+			client_score =
+				dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
+				abs(s->y - c->y);
+			break;
+		case 1: // right
+			dist = c->x - s->x - s->w;
+			client_score =
+				dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
+				abs(c->y - s->y);
+			break;
+		case 2: // up
+			dist = s->y - c->y - c->h;
+			client_score =
+				dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
+				abs(s->x - c->x);
+			break;
+		default:
+		case 3: // down
+			dist = c->y - s->y - s->h;
+			client_score =
+				dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
+				abs(c->x - s->x);
+			break;
+		}
+
+		if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
+			score = client_score;
+			f = c;
+		}
+	}
+
+	if (f && f != s) {
+		focus(f);
+		restack(f->mon);
+	}
+}
+
diff --git a/patch/focusdir.h b/patch/focusdir.h
new file mode 100644
index 0000000..0d82ebf
--- /dev/null
+++ b/patch/focusdir.h
@@ -0,0 +1,2 @@
+static void focusdir(const Arg *arg);
+
diff --git a/patch/include.c b/patch/include.c
new file mode 100644
index 0000000..2676bd0
--- /dev/null
+++ b/patch/include.c
@@ -0,0 +1,35 @@
+/* Bar functionality */
+#include "bar_indicators.c"
+#include "bar_tagicons.c"
+#include "bar.c"
+
+#include "bar_dwmblocks.c"
+#include "bar_ewmhtags.c"
+#include "bar_ltsymbol.c"
+#include "bar_status.c"
+#include "bar_statuscmd.c"
+#include "bar_tags.c"
+#include "bar_wintitle.c"
+
+/* Other patches */
+#include "attachx.c"
+#include "cool_autostart.c"
+#include "floatpos.c"
+#include "focusdir.c"
+#include "pertag.c"
+#include "restartsig.c"
+#include "renamed_scratchpads.c"
+#include "sizehints_ruled.c"
+#include "stacker.c"
+#include "togglefullscreen.c"
+#include "unfloatvisible.c"
+#include "seamless_restart.c"
+/* Layouts */
+#include "layout_facts.c"
+#include "layout_bstack.c"
+#include "layout_centeredmaster.c"
+#include "layout_deck.c"
+#include "layout_gapplessgrid.c"
+#include "layout_monocle.c"
+#include "layout_tile.c"
+
diff --git a/patch/include.h b/patch/include.h
new file mode 100644
index 0000000..d7cde24
--- /dev/null
+++ b/patch/include.h
@@ -0,0 +1,34 @@
+/* Bar functionality */
+#include "bar_indicators.h"
+#include "bar_tagicons.h"
+#include "bar.h"
+
+#include "bar_dwmblocks.h"
+#include "bar_ewmhtags.h"
+#include "bar_ltsymbol.h"
+#include "bar_status.h"
+#include "bar_statuscmd.h"
+#include "bar_tags.h"
+#include "bar_wintitle.h"
+
+/* Other patches */
+#include "attachx.h"
+#include "cool_autostart.h"
+#include "floatpos.h"
+#include "focusdir.h"
+#include "pertag.h"
+#include "restartsig.h"
+#include "renamed_scratchpads.h"
+#include "seamless_restart.h"
+#include "sizehints_ruled.h"
+#include "stacker.h"
+#include "togglefullscreen.h"
+#include "unfloatvisible.h"
+/* Layouts */
+#include "layout_bstack.h"
+#include "layout_centeredmaster.h"
+#include "layout_deck.h"
+#include "layout_gapplessgrid.h"
+#include "layout_monocle.h"
+#include "layout_tile.h"
+
diff --git a/patch/ipc/IPCClient.h b/patch/ipc/IPCClient.h
new file mode 100644
index 0000000..ee93030
--- /dev/null
+++ b/patch/ipc/IPCClient.h
@@ -0,0 +1,62 @@
+#ifndef IPC_CLIENT_H_
+#define IPC_CLIENT_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/epoll.h>
+
+typedef struct IPCClient IPCClient;
+/**
+ * This structure contains the details of an IPC Client and pointers for a
+ * linked list
+ */
+struct IPCClient {
+  int fd;
+  int subscriptions;
+
+  char *buffer;
+  uint32_t buffer_size;
+
+  struct epoll_event event;
+  IPCClient *next;
+  IPCClient *prev;
+};
+
+typedef IPCClient *IPCClientList;
+
+/**
+ * Allocate memory for new IPCClient with the specified file descriptor and
+ * initialize struct.
+ *
+ * @param fd File descriptor of IPC client
+ *
+ * @return Address to allocated IPCClient struct
+ */
+IPCClient *ipc_client_new(int fd);
+
+/**
+ * Add an IPC Client to the specified list
+ *
+ * @param list Address of the list to add the client to
+ * @param nc Address of the IPCClient
+ */
+void ipc_list_add_client(IPCClientList *list, IPCClient *nc);
+
+/**
+ * Remove an IPCClient from the specified list
+ *
+ * @param list Address of the list to remove the client from
+ * @param c Address of the IPCClient
+ */
+void ipc_list_remove_client(IPCClientList *list, IPCClient *c);
+
+/**
+ * Get an IPCClient from the specified IPCClient list
+ *
+ * @param list List to remove the client from
+ * @param fd File descriptor of the IPCClient
+ */
+IPCClient *ipc_list_get_client(IPCClientList list, int fd);
+
+#endif  // IPC_CLIENT_H_
+
diff --git a/patch/ipc/dwm-msg.c b/patch/ipc/dwm-msg.c
new file mode 100644
index 0000000..ca1e1a4
--- /dev/null
+++ b/patch/ipc/dwm-msg.c
@@ -0,0 +1,549 @@
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <yajl/yajl_gen.h>
+
+#define IPC_MAGIC "DWM-IPC"
+// clang-format off
+#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C' }
+// clang-format on
+#define IPC_MAGIC_LEN 7  // Not including null char
+
+#define IPC_EVENT_TAG_CHANGE "tag_change_event"
+#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event"
+#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event"
+#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event"
+#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event"
+#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event"
+
+#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
+#define YINT(num) yajl_gen_integer(gen, num)
+#define YDOUBLE(num) yajl_gen_double(gen, num)
+#define YBOOL(v) yajl_gen_bool(gen, v)
+#define YNULL() yajl_gen_null(gen)
+#define YARR(body)                                                             \
+  {                                                                            \
+    yajl_gen_array_open(gen);                                                  \
+    body;                                                                      \
+    yajl_gen_array_close(gen);                                                 \
+  }
+#define YMAP(body)                                                             \
+  {                                                                            \
+    yajl_gen_map_open(gen);                                                    \
+    body;                                                                      \
+    yajl_gen_map_close(gen);                                                   \
+  }
+
+typedef unsigned long Window;
+
+const char *DEFAULT_SOCKET_PATH = "/tmp/dwm.sock";
+static int sock_fd = -1;
+static unsigned int ignore_reply = 0;
+
+typedef enum IPCMessageType {
+  IPC_TYPE_RUN_COMMAND = 0,
+  IPC_TYPE_GET_MONITORS = 1,
+  IPC_TYPE_GET_TAGS = 2,
+  IPC_TYPE_GET_LAYOUTS = 3,
+  IPC_TYPE_GET_DWM_CLIENT = 4,
+  IPC_TYPE_SUBSCRIBE = 5,
+  IPC_TYPE_EVENT = 6
+} IPCMessageType;
+
+// Every IPC message must begin with this
+typedef struct dwm_ipc_header {
+  uint8_t magic[IPC_MAGIC_LEN];
+  uint32_t size;
+  uint8_t type;
+} __attribute((packed)) dwm_ipc_header_t;
+
+static int
+recv_message(uint8_t *msg_type, uint32_t *reply_size, uint8_t **reply)
+{
+  uint32_t read_bytes = 0;
+  const int32_t to_read = sizeof(dwm_ipc_header_t);
+  char header[to_read];
+  char *walk = header;
+
+  // Try to read header
+  while (read_bytes < to_read) {
+    ssize_t n = read(sock_fd, header + read_bytes, to_read - read_bytes);
+
+    if (n == 0) {
+      if (read_bytes == 0) {
+        fprintf(stderr, "Unexpectedly reached EOF while reading header.");
+        fprintf(stderr,
+                "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
+                read_bytes, to_read);
+        return -2;
+      } else {
+        fprintf(stderr, "Unexpectedly reached EOF while reading header.");
+        fprintf(stderr,
+                "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
+                read_bytes, to_read);
+        return -3;
+      }
+    } else if (n == -1) {
+      return -1;
+    }
+
+    read_bytes += n;
+  }
+
+  // Check if magic string in header matches
+  if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) {
+    fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n",
+            IPC_MAGIC_LEN, walk, IPC_MAGIC);
+    return -3;
+  }
+
+  walk += IPC_MAGIC_LEN;
+
+  // Extract reply size
+  memcpy(reply_size, walk, sizeof(uint32_t));
+  walk += sizeof(uint32_t);
+
+  // Extract message type
+  memcpy(msg_type, walk, sizeof(uint8_t));
+  walk += sizeof(uint8_t);
+
+  (*reply) = malloc(*reply_size);
+
+  // Extract payload
+  read_bytes = 0;
+  while (read_bytes < *reply_size) {
+    ssize_t n = read(sock_fd, *reply + read_bytes, *reply_size - read_bytes);
+
+    if (n == 0) {
+      fprintf(stderr, "Unexpectedly reached EOF while reading payload.");
+      fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n",
+              read_bytes, *reply_size);
+      free(*reply);
+      return -2;
+    } else if (n == -1) {
+      if (errno == EINTR || errno == EAGAIN) continue;
+      free(*reply);
+      return -1;
+    }
+
+    read_bytes += n;
+  }
+
+  return 0;
+}
+
+static int
+read_socket(IPCMessageType *msg_type, uint32_t *msg_size, char **msg)
+{
+  int ret = -1;
+
+  while (ret != 0) {
+    ret = recv_message((uint8_t *)msg_type, msg_size, (uint8_t **)msg);
+
+    if (ret < 0) {
+      // Try again (non-fatal error)
+      if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue;
+
+      fprintf(stderr, "Error receiving response from socket. ");
+      fprintf(stderr, "The connection might have been lost.\n");
+      exit(2);
+    }
+  }
+
+  return 0;
+}
+
+static ssize_t
+write_socket(const void *buf, size_t count)
+{
+  size_t written = 0;
+
+  while (written < count) {
+    const ssize_t n =
+        write(sock_fd, ((uint8_t *)buf) + written, count - written);
+
+    if (n == -1) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+        continue;
+      else
+        return n;
+    }
+    written += n;
+  }
+  return written;
+}
+
+static void
+connect_to_socket()
+{
+  struct sockaddr_un addr;
+
+  int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+  // Initialize struct to 0
+  memset(&addr, 0, sizeof(struct sockaddr_un));
+
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, DEFAULT_SOCKET_PATH);
+
+  connect(sock, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un));
+
+  sock_fd = sock;
+}
+
+static int
+send_message(IPCMessageType msg_type, uint32_t msg_size, uint8_t *msg)
+{
+  dwm_ipc_header_t header = {
+      .magic = IPC_MAGIC_ARR, .size = msg_size, .type = msg_type};
+
+  size_t header_size = sizeof(dwm_ipc_header_t);
+  size_t total_size = header_size + msg_size;
+
+  uint8_t buffer[total_size];
+
+  // Copy header to buffer
+  memcpy(buffer, &header, header_size);
+  // Copy message to buffer
+  memcpy(buffer + header_size, msg, header.size);
+
+  write_socket(buffer, total_size);
+
+  return 0;
+}
+
+static int
+is_float(const char *s)
+{
+  size_t len = strlen(s);
+  int is_dot_used = 0;
+  int is_minus_used = 0;
+
+  // Floats can only have one decimal point in between or digits
+  // Optionally, floats can also be below zero (negative)
+  for (int i = 0; i < len; i++) {
+    if (isdigit(s[i]))
+      continue;
+    else if (!is_dot_used && s[i] == '.' && i != 0 && i != len - 1) {
+      is_dot_used = 1;
+      continue;
+    } else if (!is_minus_used && s[i] == '-' && i == 0) {
+      is_minus_used = 1;
+      continue;
+    } else
+      return 0;
+  }
+
+  return 1;
+}
+
+static int
+is_unsigned_int(const char *s)
+{
+  size_t len = strlen(s);
+
+  // Unsigned int can only have digits
+  for (int i = 0; i < len; i++) {
+    if (isdigit(s[i]))
+      continue;
+    else
+      return 0;
+  }
+
+  return 1;
+}
+
+static int
+is_signed_int(const char *s)
+{
+  size_t len = strlen(s);
+
+  // Signed int can only have digits and a negative sign at the start
+  for (int i = 0; i < len; i++) {
+    if (isdigit(s[i]))
+      continue;
+    else if (i == 0 && s[i] == '-') {
+      continue;
+    } else
+      return 0;
+  }
+
+  return 1;
+}
+
+static void
+flush_socket_reply()
+{
+  IPCMessageType reply_type;
+  uint32_t reply_size;
+  char *reply;
+
+  read_socket(&reply_type, &reply_size, &reply);
+
+  free(reply);
+}
+
+static void
+print_socket_reply()
+{
+  IPCMessageType reply_type;
+  uint32_t reply_size;
+  char *reply;
+
+  read_socket(&reply_type, &reply_size, &reply);
+
+  printf("%.*s\n", reply_size, reply);
+  fflush(stdout);
+  free(reply);
+}
+
+static int
+run_command(const char *name, char *args[], int argc)
+{
+  const unsigned char *msg;
+  size_t msg_size;
+
+  yajl_gen gen = yajl_gen_alloc(NULL);
+
+  // Message format:
+  // {
+  //   "command": "<name>",
+  //   "args": [ ... ]
+  // }
+  // clang-format off
+  YMAP(
+    YSTR("command"); YSTR(name);
+    YSTR("args"); YARR(
+      for (int i = 0; i < argc; i++) {
+        if (is_signed_int(args[i])) {
+          long long num = atoll(args[i]);
+          YINT(num);
+        } else if (is_float(args[i])) {
+          float num = atof(args[i]);
+          YDOUBLE(num);
+        } else {
+          YSTR(args[i]);
+        }
+      }
+    )
+  )
+  // clang-format on
+
+  yajl_gen_get_buf(gen, &msg, &msg_size);
+
+  send_message(IPC_TYPE_RUN_COMMAND, msg_size, (uint8_t *)msg);
+
+  if (!ignore_reply)
+    print_socket_reply();
+  else
+    flush_socket_reply();
+
+  yajl_gen_free(gen);
+
+  return 0;
+}
+
+static int
+get_monitors()
+{
+  send_message(IPC_TYPE_GET_MONITORS, 1, (uint8_t *)"");
+  print_socket_reply();
+  return 0;
+}
+
+static int
+get_tags()
+{
+  send_message(IPC_TYPE_GET_TAGS, 1, (uint8_t *)"");
+  print_socket_reply();
+
+  return 0;
+}
+
+static int
+get_layouts()
+{
+  send_message(IPC_TYPE_GET_LAYOUTS, 1, (uint8_t *)"");
+  print_socket_reply();
+
+  return 0;
+}
+
+static int
+get_dwm_client(Window win)
+{
+  const unsigned char *msg;
+  size_t msg_size;
+
+  yajl_gen gen = yajl_gen_alloc(NULL);
+
+  // Message format:
+  // {
+  //   "client_window_id": "<win>"
+  // }
+  // clang-format off
+  YMAP(
+    YSTR("client_window_id"); YINT(win);
+  )
+  // clang-format on
+
+  yajl_gen_get_buf(gen, &msg, &msg_size);
+
+  send_message(IPC_TYPE_GET_DWM_CLIENT, msg_size, (uint8_t *)msg);
+
+  print_socket_reply();
+
+  yajl_gen_free(gen);
+
+  return 0;
+}
+
+static int
+subscribe(const char *event)
+{
+  const unsigned char *msg;
+  size_t msg_size;
+
+  yajl_gen gen = yajl_gen_alloc(NULL);
+
+  // Message format:
+  // {
+  //   "event": "<event>",
+  //   "action": "subscribe"
+  // }
+  // clang-format off
+  YMAP(
+    YSTR("event"); YSTR(event);
+    YSTR("action"); YSTR("subscribe");
+  )
+  // clang-format on
+
+  yajl_gen_get_buf(gen, &msg, &msg_size);
+
+  send_message(IPC_TYPE_SUBSCRIBE, msg_size, (uint8_t *)msg);
+
+  if (!ignore_reply)
+    print_socket_reply();
+  else
+    flush_socket_reply();
+
+  yajl_gen_free(gen);
+
+  return 0;
+}
+
+static void
+usage_error(const char *prog_name, const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+
+  fprintf(stderr, "Error: ");
+  vfprintf(stderr, format, args);
+  fprintf(stderr, "\nusage: %s <command> [...]\n", prog_name);
+  fprintf(stderr, "Try '%s help'\n", prog_name);
+
+  va_end(args);
+  exit(1);
+}
+
+static void
+print_usage(const char *name)
+{
+  printf("usage: %s [options] <command> [...]\n", name);
+  puts("");
+  puts("Commands:");
+  puts("  run_command <name> [args...]    Run an IPC command");
+  puts("");
+  puts("  get_monitors                    Get monitor properties");
+  puts("");
+  puts("  get_tags                        Get list of tags");
+  puts("");
+  puts("  get_layouts                     Get list of layouts");
+  puts("");
+  puts("  get_dwm_client <window_id>      Get dwm client proprties");
+  puts("");
+  puts("  subscribe [events...]           Subscribe to specified events");
+  puts("                                  Options: " IPC_EVENT_TAG_CHANGE ",");
+  puts("                                  " IPC_EVENT_LAYOUT_CHANGE ",");
+  puts("                                  " IPC_EVENT_CLIENT_FOCUS_CHANGE ",");
+  puts("                                  " IPC_EVENT_MONITOR_FOCUS_CHANGE ",");
+  puts("                                  " IPC_EVENT_FOCUSED_TITLE_CHANGE ",");
+  puts("                                  " IPC_EVENT_FOCUSED_STATE_CHANGE);
+  puts("");
+  puts("  help                            Display this message");
+  puts("");
+  puts("Options:");
+  puts("  --ignore-reply                  Don't print reply messages from");
+  puts("                                  run_command and subscribe.");
+  puts("");
+}
+
+int
+main(int argc, char *argv[])
+{
+  const char *prog_name = argv[0];
+
+  connect_to_socket();
+  if (sock_fd == -1) {
+    fprintf(stderr, "Failed to connect to socket\n");
+    return 1;
+  }
+
+  int i = 1;
+  if (i < argc && strcmp(argv[i], "--ignore-reply") == 0) {
+    ignore_reply = 1;
+    i++;
+  }
+
+  if (i >= argc) usage_error(prog_name, "Expected an argument, got none");
+
+  if (!argc || strcmp(argv[i], "help") == 0)
+    print_usage(prog_name);
+  else if (strcmp(argv[i], "run_command") == 0) {
+    if (++i >= argc) usage_error(prog_name, "No command specified");
+    // Command name
+    char *command = argv[i];
+    // Command arguments are everything after command name
+    char **command_args = argv + ++i;
+    // Number of command arguments
+    int command_argc = argc - i;
+    run_command(command, command_args, command_argc);
+  } else if (strcmp(argv[i], "get_monitors") == 0) {
+    get_monitors();
+  } else if (strcmp(argv[i], "get_tags") == 0) {
+    get_tags();
+  } else if (strcmp(argv[i], "get_layouts") == 0) {
+    get_layouts();
+  } else if (strcmp(argv[i], "get_dwm_client") == 0) {
+    if (++i < argc) {
+      if (is_unsigned_int(argv[i])) {
+        Window win = atol(argv[i]);
+        get_dwm_client(win);
+      } else
+        usage_error(prog_name, "Expected unsigned integer argument");
+    } else
+      usage_error(prog_name, "Expected the window id");
+  } else if (strcmp(argv[i], "subscribe") == 0) {
+    if (++i < argc) {
+      for (int j = i; j < argc; j++) subscribe(argv[j]);
+    } else
+      usage_error(prog_name, "Expected event name");
+    // Keep listening for events forever
+    while (1) {
+      print_socket_reply();
+    }
+  } else
+    usage_error(prog_name, "Invalid argument '%s'", argv[i]);
+
+  return 0;
+}
+
diff --git a/patch/ipc/yajl_dumps.h b/patch/ipc/yajl_dumps.h
new file mode 100644
index 0000000..bb57a17
--- /dev/null
+++ b/patch/ipc/yajl_dumps.h
@@ -0,0 +1,66 @@
+#ifndef YAJL_DUMPS_H_
+#define YAJL_DUMPS_H_
+
+#include <string.h>
+#include <yajl/yajl_gen.h>
+
+#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
+#define YINT(num) yajl_gen_integer(gen, num)
+#define YDOUBLE(num) yajl_gen_double(gen, num)
+#define YBOOL(v) yajl_gen_bool(gen, v)
+#define YNULL() yajl_gen_null(gen)
+#define YARR(body)                                                             \
+  {                                                                            \
+    yajl_gen_array_open(gen);                                                  \
+    body;                                                                      \
+    yajl_gen_array_close(gen);                                                 \
+  }
+#define YMAP(body)                                                             \
+  {                                                                            \
+    yajl_gen_map_open(gen);                                                    \
+    body;                                                                      \
+    yajl_gen_map_close(gen);                                                   \
+  }
+
+int dump_tag(yajl_gen gen, const char *name, const int tag_mask);
+
+int dump_tags(yajl_gen gen, int tags_len);
+
+int dump_client(yajl_gen gen, Client *c);
+
+int dump_monitor(yajl_gen gen, Monitor *mon, int is_selected);
+
+int dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon);
+
+int dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len);
+
+int dump_tag_state(yajl_gen gen, TagState state);
+
+int dump_tag_event(yajl_gen gen, int mon_num, TagState old_state,
+                   TagState new_state);
+
+int dump_client_focus_change_event(yajl_gen gen, Client *old_client,
+                                   Client *new_client, int mon_num);
+
+int dump_layout_change_event(yajl_gen gen, const int mon_num,
+                             const char *old_symbol, const Layout *old_layout,
+                             const char *new_symbol, const Layout *new_layout);
+
+int dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num,
+                                    const int new_mon_num);
+
+int dump_focused_title_change_event(yajl_gen gen, const int mon_num,
+                                    const Window client_id,
+                                    const char *old_name, const char *new_name);
+
+int dump_client_state(yajl_gen gen, const ClientState *state);
+
+int dump_focused_state_change_event(yajl_gen gen, const int mon_num,
+                                    const Window client_id,
+                                    const ClientState *old_state,
+                                    const ClientState *new_state);
+
+int dump_error_message(yajl_gen gen, const char *reason);
+
+#endif  // YAJL_DUMPS_H_
+
diff --git a/patch/layout_bstack.c b/patch/layout_bstack.c
new file mode 100644
index 0000000..e72c57c
--- /dev/null
+++ b/patch/layout_bstack.c
@@ -0,0 +1,39 @@
+static void
+bstack(Monitor *m)
+{
+	unsigned int i, n;
+	int mx = 0, my = 0, mh = 0, mw = 0;
+	int sx = 0, sy = 0, sh = 0, sw = 0;
+	float mfacts, sfacts;
+	int mrest, srest;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+	if (n == 0)
+		return;
+
+	sx = mx = m->wx;
+	sy = my = m->wy;
+	sh = mh = m->wh;
+	sw = mw = m->ww;
+
+	if (m->nmaster && n > m->nmaster) {
+		sh = mh * (1 - m->mfact);
+		mh = mh * m->mfact;
+		sy = my + mh;
+	}
+
+	getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
+
+	for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+		if (i < m->nmaster) {
+			resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+			mx += WIDTH(c);
+		} else {
+			resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+			sx += WIDTH(c);
+		}
+	}
+}
+
diff --git a/patch/layout_bstack.h b/patch/layout_bstack.h
new file mode 100644
index 0000000..07e8c0a
--- /dev/null
+++ b/patch/layout_bstack.h
@@ -0,0 +1,2 @@
+static void bstack(Monitor *m);
+
diff --git a/patch/layout_centeredmaster.c b/patch/layout_centeredmaster.c
new file mode 100644
index 0000000..07e9d43
--- /dev/null
+++ b/patch/layout_centeredmaster.c
@@ -0,0 +1,84 @@
+void
+centeredmaster(Monitor *m)
+{
+	unsigned int i, n;
+	int mx = 0, my = 0, mh = 0, mw = 0;
+	int lx = 0, ly = 0, lw = 0, lh = 0;
+	int rx = 0, ry = 0, rw = 0, rh = 0;
+	float mfacts = 0, lfacts = 0, rfacts = 0;
+	int mtotal = 0, ltotal = 0, rtotal = 0;
+	int mrest = 0, lrest = 0, rrest = 0;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+	if (n == 0)
+		return;
+
+	/* initialize areas */
+	mx = m->wx;
+	my = m->wy;
+	mh = m->wh;
+	mw = m->ww;
+	lh = m->wh;
+	rh = m->wh;
+
+	if (m->nmaster && n > m->nmaster) {
+		/* go mfact box in the center if more than nmaster clients */
+		if (n - m->nmaster > 1) {
+			/* ||<-S->|<---M--->|<-S->|| */
+			mw = m->ww * m->mfact;
+			lw = (m->ww - mw) / 2;
+			mx += lw;
+		} else {
+			/* ||<---M--->|<-S->|| */
+			mw = mw * m->mfact;
+			lw = m->ww - mw;
+		}
+		rw = lw;
+		lx = m->wx;
+		ly = m->wy;
+		rx = mx + mw;
+		ry = m->wy;
+	}
+
+	/* calculate facts */
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
+		if (!m->nmaster || n < m->nmaster)
+			mfacts += 1;
+		else if ((n - m->nmaster) % 2)
+			lfacts += 1; // total factor of left hand stack area
+		else
+			rfacts += 1; // total factor of right hand stack area
+	}
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+		if (!m->nmaster || n < m->nmaster)
+			mtotal += mh / mfacts;
+		else if ((n - m->nmaster) % 2)
+			ltotal += lh / lfacts;
+		else
+			rtotal += rh / rfacts;
+
+	mrest = mh - mtotal;
+	lrest = lh - ltotal;
+	rrest = rh - rtotal;
+
+	for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+		if (!m->nmaster || i < m->nmaster) {
+			/* nmaster clients are stacked vertically, in the center of the screen */
+			resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+			my += HEIGHT(c);
+		} else {
+			/* stack clients are stacked vertically */
+			if ((i - m->nmaster) % 2 ) {
+				resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
+				ly += HEIGHT(c);
+			} else {
+				resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
+				ry += HEIGHT(c);
+			}
+		}
+	}
+}
+
diff --git a/patch/layout_centeredmaster.h b/patch/layout_centeredmaster.h
new file mode 100644
index 0000000..703f8b8
--- /dev/null
+++ b/patch/layout_centeredmaster.h
@@ -0,0 +1,2 @@
+static void centeredmaster(Monitor *m);
+
diff --git a/patch/layout_deck.c b/patch/layout_deck.c
new file mode 100644
index 0000000..c5b4842
--- /dev/null
+++ b/patch/layout_deck.c
@@ -0,0 +1,40 @@
+static void
+deck(Monitor *m)
+{
+	unsigned int i, n;
+	int mx = 0, my = 0, mh = 0, mw = 0;
+	int sx = 0, sy = 0, sh = 0, sw = 0;
+	float mfacts, sfacts;
+	int mrest, srest;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+	if (n == 0)
+		return;
+
+	sx = mx = m->wx;
+	sy = my = m->wy;
+	sh = mh = m->wh;
+	sw = mw = m->ww;
+
+	if (m->nmaster && n > m->nmaster) {
+		sw = mw * (1 - m->mfact);
+		mw = mw * m->mfact;
+		sx = mx + mw;
+	}
+
+	getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
+
+	if (n - m->nmaster > 0) /* override layout symbol */
+		snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
+
+	for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+		if (i < m->nmaster) {
+			resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+			my += HEIGHT(c);
+		} else {
+			resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
+		}
+}
+
diff --git a/patch/layout_deck.h b/patch/layout_deck.h
new file mode 100644
index 0000000..b6e3c41
--- /dev/null
+++ b/patch/layout_deck.h
@@ -0,0 +1,2 @@
+static void deck(Monitor *m);
+
diff --git a/patch/layout_facts.c b/patch/layout_facts.c
new file mode 100644
index 0000000..241d344
--- /dev/null
+++ b/patch/layout_facts.c
@@ -0,0 +1,24 @@
+void
+getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
+{
+	unsigned int n;
+	float mfacts, sfacts;
+	int mtotal = 0, stotal = 0;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+	mfacts = MIN(n, m->nmaster);
+	sfacts = n - m->nmaster;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+		if (n < m->nmaster)
+			mtotal += msize / mfacts;
+		else
+			stotal += ssize / sfacts;
+
+	*mf = mfacts; // total factor of master area
+	*sf = sfacts; // total factor of stack area
+	*mr = msize - mtotal; // the remainder (rest) of pixels after an even master split
+	*sr = ssize - stotal; // the remainder (rest) of pixels after an even stack split
+}
+
diff --git a/patch/layout_gapplessgrid.c b/patch/layout_gapplessgrid.c
new file mode 100644
index 0000000..ce23d5a
--- /dev/null
+++ b/patch/layout_gapplessgrid.c
@@ -0,0 +1,48 @@
+void
+gaplessgrid(Monitor *m)
+{
+	unsigned int i, n;
+	int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+	if (n == 0)
+		return;
+
+	/* grid dimensions */
+	for (cols = 0; cols <= n/2; cols++)
+		if (cols*cols >= n)
+			break;
+	if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
+		cols = 2;
+	rows = n/cols;
+	cn = rn = 0; // reset column no, row no, client count
+
+	ch = m->wh / rows;
+	cw = m->ww / cols;
+	rrest = m->wh - ch * rows;
+	crest = m->ww - cw * cols;
+	x = m->wx;
+	y = m->wy;
+
+	for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
+		if (i/rows + 1 > cols - n%cols) {
+			rows = n/cols + 1;
+			ch = m->wh / rows;
+			rrest = m->wh - ch * rows;
+		}
+		resize(c,
+			x,
+			y + rn*ch + MIN(rn, rrest),
+			cw + (cn < crest ? 1 : 0) - 2*c->bw,
+			ch + (rn < rrest ? 1 : 0) - 2*c->bw,
+			0);
+		rn++;
+		if (rn >= rows) {
+			rn = 0;
+			x += cw + (cn < crest ? 1 : 0);
+			cn++;
+		}
+	}
+}
+
diff --git a/patch/layout_gapplessgrid.h b/patch/layout_gapplessgrid.h
new file mode 100644
index 0000000..1a4ffc2
--- /dev/null
+++ b/patch/layout_gapplessgrid.h
@@ -0,0 +1,2 @@
+static void gaplessgrid(Monitor *m);
+
diff --git a/patch/layout_monocle.c b/patch/layout_monocle.c
new file mode 100644
index 0000000..4b3516c
--- /dev/null
+++ b/patch/layout_monocle.c
@@ -0,0 +1,15 @@
+void
+monocle(Monitor *m)
+{
+	unsigned int n = 0;
+	Client *c;
+
+	for (c = m->clients; c; c = c->next)
+		if (ISVISIBLE(c))
+			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, 0);
+}
+
diff --git a/patch/layout_monocle.h b/patch/layout_monocle.h
new file mode 100644
index 0000000..f32e49f
--- /dev/null
+++ b/patch/layout_monocle.h
@@ -0,0 +1,2 @@
+static void monocle(Monitor *m);
+
diff --git a/patch/layout_tile.c b/patch/layout_tile.c
new file mode 100644
index 0000000..76b0078
--- /dev/null
+++ b/patch/layout_tile.c
@@ -0,0 +1,38 @@
+static void
+tile(Monitor *m)
+{
+	unsigned int i, n;
+	int mx = 0, my = 0, mh = 0, mw = 0;
+	int sx = 0, sy = 0, sh = 0, sw = 0;
+	float mfacts, sfacts;
+	int mrest, srest;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+	if (n == 0)
+		return;
+
+	sx = mx = m->wx;
+	sy = my = m->wy;
+	sh = mh = m->wh;
+	sw = mw = m->ww;
+
+	if (m->nmaster && n > m->nmaster) {
+		sw = mw * (1 - m->mfact);
+		mw = mw * m->mfact;
+		sx = mx + mw;
+	}
+
+	getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
+
+	for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+		if (i < m->nmaster) {
+			resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+			my += HEIGHT(c);
+		} else {
+			resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+			sy += HEIGHT(c);
+		}
+}
+
diff --git a/patch/layout_tile.h b/patch/layout_tile.h
new file mode 100644
index 0000000..4aff634
--- /dev/null
+++ b/patch/layout_tile.h
@@ -0,0 +1,2 @@
+static void tile(Monitor *m);
+
diff --git a/patch/pertag.c b/patch/pertag.c
new file mode 100644
index 0000000..c5f7f92
--- /dev/null
+++ b/patch/pertag.c
@@ -0,0 +1,28 @@
+struct Pertag {
+	unsigned int curtag; /* current tag index */
+	int nmasters[NUMTAGS + 1]; /* number of windows in master area */
+	const Layout *ltidxs[NUMTAGS + 1][2]; /* matrix of tags and layouts indexes  */
+	float mfacts[NUMTAGS + 1]; /* mfacts per tag */
+	unsigned int sellts[NUMTAGS + 1]; /* selected layouts */
+};
+
+void
+pertagview(const Arg *arg)
+{
+	int i;
+
+	if (arg->ui == ~0)
+		selmon->pertag->curtag = 0;
+	else {
+		for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
+		selmon->pertag->curtag = i + 1;
+	}
+
+	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];
+
+}
+
diff --git a/patch/pertag.h b/patch/pertag.h
new file mode 100644
index 0000000..5c53ac9
--- /dev/null
+++ b/patch/pertag.h
@@ -0,0 +1,2 @@
+static void pertagview(const Arg *arg);
+
diff --git a/patch/renamed_scratchpads.c b/patch/renamed_scratchpads.c
new file mode 100644
index 0000000..1a41e22
--- /dev/null
+++ b/patch/renamed_scratchpads.c
@@ -0,0 +1,144 @@
+void
+removescratch(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	if (!c)
+		return;
+	c->scratchkey = 0;
+}
+
+void
+setscratch(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	if (!c)
+		return;
+
+	c->scratchkey = ((char**)arg->v)[0][0];
+}
+
+void spawnscratch(const Arg *arg)
+{
+	if (fork() == 0) {
+		if (dpy)
+			close(ConnectionNumber(dpy));
+		setsid();
+		execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
+		fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
+		perror(" failed");
+		exit(EXIT_SUCCESS);
+	}
+}
+
+void
+togglescratch(const Arg *arg)
+{
+	Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
+	Monitor *mon;
+	int scratchvisible = 0; // whether the scratchpads are currently visible or not
+	int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
+	int scratchmon = -1; // the monitor where the scratchpads exist
+	int numscratchpads = 0; // count of scratchpads
+
+	/* Looping through monitors and client's twice, the first time to work out whether we need
+	   to move clients across from one monitor to another or not */
+	for (mon = mons; mon; mon = mon->next)
+		for (c = mon->clients; c; c = c->next) {
+			if (c->scratchkey != ((char**)arg->v)[0][0])
+				continue;
+			if (scratchmon != -1 && scratchmon != mon->num)
+				multimonscratch = 1;
+			if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
+				++scratchvisible;
+			scratchmon = mon->num;
+			++numscratchpads;
+		}
+
+	/* Now for the real deal. The logic should go like:
+	    - hidden scratchpads will be shown
+	    - shown scratchpads will be hidden, unless they are being moved to the current monitor
+	    - the scratchpads will be moved to the current monitor if they all reside on the same monitor
+	    - multiple scratchpads residing on separate monitors will be left in place
+	 */
+	for (mon = mons; mon; mon = mon->next) {
+		for (c = mon->stack; c; c = next) {
+			next = c->snext;
+			if (c->scratchkey != ((char**)arg->v)[0][0])
+				continue;
+
+			/* Record the first found scratchpad client for focus purposes, but prioritise the
+			   scratchpad on the current monitor if one exists */
+			if (!found || (mon == selmon && found->mon != selmon))
+				found = c;
+
+			/* If scratchpad clients reside on another monitor and we are moving them across then
+			   as we are looping through monitors we could be moving a client to a monitor that has
+			   not been processed yet, hence we could be processing a scratchpad twice. To avoid
+			   this we detach them and add them to a temporary list (monclients) which is to be
+			   processed later. */
+			if (!multimonscratch && c->mon != selmon) {
+				detach(c);
+				detachstack(c);
+				c->next = NULL;
+				/* Note that we are adding clients at the end of the list, this is to preserve the
+				   order of clients as they were on the adjacent monitor (relevant when tiled) */
+				if (last)
+					last = last->next = c;
+				else
+					last = monclients = c;
+			} else if (scratchvisible == numscratchpads) {
+				c->tags = 0;
+			} else {
+				XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
+				c->tags = c->mon->tagset[c->mon->seltags];
+				if (c->isfloating)
+					XRaiseWindow(dpy, c->win);
+			}
+		}
+	}
+
+	/* Attach moved scratchpad clients on the selected monitor */
+	for (c = monclients; c; c = next) {
+		next = c->next;
+		mon = c->mon;
+		c->mon = selmon;
+		c->tags = selmon->tagset[selmon->seltags];
+		/* Attach scratchpad clients from other monitors at the bottom of the stack */
+		if (selmon->clients) {
+			for (last = selmon->clients; last && last->next; last = last->next);
+			last->next = c;
+		} else
+			selmon->clients = c;
+		c->next = NULL;
+		attachstack(c);
+
+		/* Center floating scratchpad windows when moved from one monitor to another */
+		if (c->isfloating) {
+			if (c->w > selmon->ww)
+				c->w = selmon->ww - c->bw * 2;
+			if (c->h > selmon->wh)
+				c->h = selmon->wh - c->bw * 2;
+
+			if (numscratchpads > 1) {
+				c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
+				c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
+			} else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
+			           c->y < c->mon->my || c->y > c->mon->my + c->mon->mh)	{
+				c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
+				c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
+			}
+			resizeclient(c, c->x, c->y, c->w, c->h);
+			XRaiseWindow(dpy, c->win);
+		}
+	}
+
+	if (found) {
+		focus(ISVISIBLE(found) ? found : NULL);
+		arrange(NULL);
+		if (found->isfloating)
+			XRaiseWindow(dpy, found->win);
+	} else {
+		spawnscratch(arg);
+	}
+}
+
diff --git a/patch/renamed_scratchpads.h b/patch/renamed_scratchpads.h
new file mode 100644
index 0000000..3260462
--- /dev/null
+++ b/patch/renamed_scratchpads.h
@@ -0,0 +1,4 @@
+static void removescratch(const Arg *arg);
+static void setscratch(const Arg *arg);
+static void spawnscratch(const Arg *arg);
+static void togglescratch(const Arg *arg);
diff --git a/patch/restartsig.c b/patch/restartsig.c
new file mode 100644
index 0000000..adb61b5
--- /dev/null
+++ b/patch/restartsig.c
@@ -0,0 +1,16 @@
+static int restart = 0;
+
+void
+sighup(int unused)
+{
+	Arg a = {.i = 1};
+	quit(&a);
+}
+
+void
+sigterm(int unused)
+{
+	Arg a = {.i = 0};
+	quit(&a);
+}
+
diff --git a/patch/restartsig.h b/patch/restartsig.h
new file mode 100644
index 0000000..b16975b
--- /dev/null
+++ b/patch/restartsig.h
@@ -0,0 +1,3 @@
+static void sighup(int unused);
+static void sigterm(int unused);
+
diff --git a/patch/seamless_restart.c b/patch/seamless_restart.c
new file mode 100644
index 0000000..dd3c157
--- /dev/null
+++ b/patch/seamless_restart.c
@@ -0,0 +1,314 @@
+void
+persistmonitorstate(Monitor *m)
+{
+	Client *c;
+	unsigned int i;
+
+	setmonitortags(m);
+	setmonitorfields(m);
+
+	/* Set client atoms */
+	for (i = 1, c = m->clients; c; c = c->next, ++i) {
+		c->idx = i;
+		persistclientstate(c);
+	}
+}
+
+int
+restoremonitorstate(Monitor *m)
+{
+	return getmonitortags(m) | getmonitorfields(m);
+}
+
+void
+persistclientstate(Client *c)
+{
+	setclienttags(c);
+	setclientfields(c);
+	savewindowfloatposition(c, c->mon);
+}
+
+int
+restoreclientstate(Client *c)
+{
+	int restored = getclientfields(c);
+	getclienttags(c);
+	restorewindowfloatposition(c, c->mon ? c->mon : selmon);
+	return restored;
+}
+
+void setmonitorfields(Monitor *m)
+{
+	unsigned int i;
+	char atom[22] = {0};
+	Atom monitor_fields;
+
+	sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
+	monitor_fields = XInternAtom(dpy, atom, False);
+
+	/* Perists workspace information in 32 bits laid out like this:
+	 *
+	 * |0|0000|0|0000|0000|0000|0000|0000|000|000
+	 * | |    | |    |    |    |    |    |   |-- nmaster
+	 * | |    | |    |    |    |    |    |-- nstack
+	 * | |    | |    |    |    |    |-- layout
+	 * | |    | |    |    |    |-- flextile LAYOUT (split)
+	 * | |    | |    |    |-- flextile MASTER
+	 * | |    | |    |-- flextile STACK1
+	 * | |    | |-- flextile STACK2
+	 * | |    |-- flextile mirror layout (indicated by negative layout)
+	 * | |
+	 * | |-- reserved
+	 * |-- showbar
+	 */
+	for (i = 0; i <= NUMTAGS; i++) {
+		uint32_t data[] = {
+			(m->pertag->nmasters[i] & 0x7) |
+			(getlayoutindex(m->pertag->ltidxs[i][m->pertag->sellts[i]]) & 0xF) << 6 |
+			m->showbar << 31
+		};
+
+		XChangeProperty(dpy, root, monitor_fields, XA_CARDINAL, 32,
+			i ? PropModeAppend : PropModeReplace, (unsigned char *)data, 1);
+	}
+}
+
+int
+getlayoutindex(const Layout *layout)
+{
+	int i;
+
+	for (i = 0; i < LENGTH(layouts) && &layouts[i] != layout; i++);
+	if (i == LENGTH(layouts))
+		i = 0;
+	return i;
+}
+
+int
+getmonitorfields(Monitor *m)
+{
+	int di, layout_index;
+	unsigned int i, restored = 0;
+	unsigned int tags = m->tagset[m->seltags] << 1;
+	unsigned long dl, nitems;
+	unsigned char *p = NULL;
+	char atom[22] = {0};
+	Atom da, state = None;
+
+	sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
+	Atom dwm_monitor = XInternAtom(dpy, atom, False);
+	if (!dwm_monitor)
+		return 0;
+
+	for (i = 0; i <= NUMTAGS; i++) {
+		if (!(XGetWindowProperty(dpy, root, dwm_monitor, i, (NUMTAGS + 1) * sizeof dl,
+				False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
+			break;
+		}
+
+		if (!nitems) {
+			XFree(p);
+			break;
+		}
+
+		/* See bit layout in the persistmonitorstate function */
+		state = *(Atom *)p;
+
+		m->pertag->nmasters[i] = state & 0x7;
+		layout_index = (state >> 6) & 0xF;
+		if (layout_index < LENGTH(layouts))
+			m->pertag->ltidxs[i][m->pertag->sellts[i]] = &layouts[layout_index];
+
+		if (!restored && i && (tags & (1 << i))) {
+			m->nmaster = m->pertag->nmasters[i];
+			m->sellt = m->pertag->sellts[i];
+			m->lt[m->sellt] = m->pertag->ltidxs[i][m->sellt];
+			m->showbar = (state >> 31) & 0x1;
+			restored = 1;
+		}
+
+		XFree(p);
+	}
+
+	return restored;
+}
+
+void
+setmonitortags(Monitor *m)
+{
+	char atom[22] = {0};
+	Atom monitor_tags;
+
+	sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
+	monitor_tags = XInternAtom(dpy, atom, False);
+
+	uint32_t data[] = { m->tagset[m->seltags] };
+	XChangeProperty(dpy, root, monitor_tags, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+int
+getmonitortags(Monitor *m)
+{
+	int di;
+	unsigned long dl, nitems;
+	unsigned char *p = NULL;
+	char atom[22] = {0};
+	Atom da, monitor_tags = None, tags;
+
+	sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
+	monitor_tags = XInternAtom(dpy, atom, False);
+
+	if (!(XGetWindowProperty(dpy, root, monitor_tags, 0L, sizeof dl,
+			False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
+		return 0;
+	}
+
+	if (nitems) {
+		tags = *(Atom *)p;
+		m->tagset[m->seltags] = tags & TAGMASK;
+	}
+
+	XFree(p);
+	return 1;
+}
+
+void
+setclientfields(Client *c)
+{
+	/* Perists client information in 32 bits laid out like this:
+	 *
+	 * |00000000|00000|0|0|0|0|0|0|0|0|00000000|000
+	 * |        |     | | | | | | | | |        |-- monitor index
+	 * |        |     | | | | | | | | |-- client index
+	 * |        |     | | | | | | | |-- isfloating
+	 * |        |     | | | | | | |-- ispermanent
+	 * |        |     | | | | | |-- isterminal
+	 * |        |     | | | | |-- noswallow
+	 * |        |     | | | |-- issteam
+	 * |        |     | | |-- issticky
+	 * |        |     | |-- fakefullscreen
+	 * |        |     |-- isfreesize
+	 * |        |
+	 * |        |-- reserved
+	 * |-- scratchkey (for scratchpads)
+	 */
+	uint32_t data[] = {
+		(c->mon->num & 0x7)
+		| (c->idx & 0xFF) << 3
+		| (c->isfloating & 0x1) << 11
+		| (c->scratchkey & 0xFF) << 24
+	};
+	XChangeProperty(dpy, c->win, clientatom[ClientFields], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+int
+getclientfields(Client *c)
+{
+	Monitor *m;
+	Atom fields = getatomprop(c, clientatom[ClientFields], AnyPropertyType);
+	if (fields == None)
+		return 0;
+
+	/* See bit layout in the setclientfields function */
+	for (m = mons; m; m = m->next)
+		if (m->num == (fields & 0x7)) {
+			c->mon = m;
+			break;
+		}
+	c->idx = (fields >> 3) & 0xFF;
+	c->isfloating = (fields >> 11) & 0x1;
+	c->scratchkey = (fields >> 24) & 0xFF;
+	return 1;
+}
+
+void
+setclienttags(Client *c)
+{
+	uint32_t data[] = { c->tags };
+	XChangeProperty(dpy, c->win, clientatom[ClientTags], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+int
+getclienttags(Client *c)
+{
+	Atom tags = getatomprop(c, clientatom[ClientTags], AnyPropertyType);
+	if (tags == None)
+		return 0;
+
+	c->tags = tags & TAGMASK;
+	return 1;
+}
+
+void
+savewindowfloatposition(Client *c, Monitor *m)
+{
+	char atom[22] = {0};
+	if (c->sfx == -9999)
+		return;
+
+	sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
+	uint32_t pos[] = { (MAX(c->sfx - m->mx, 0) & 0xffff) | ((MAX(c->sfy - m->my, 0) & 0xffff) << 16) };
+	XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pos, 1);
+
+	sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
+	uint32_t size[] = { (c->sfw & 0xffff) | ((c->sfh & 0xffff) << 16) };
+	XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)size, 1);
+
+	XSync(dpy, False);
+}
+
+int
+restorewindowfloatposition(Client *c, Monitor *m)
+{
+	char atom[22] = {0};
+	Atom key, value;
+	int x, y, w, h;
+
+	if (m == NULL)
+		return 0;
+
+	sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
+
+	key = XInternAtom(dpy, atom, False);
+	if (!key)
+		return 0;
+
+	value = getatomprop(c, key, AnyPropertyType);
+	if (!value)
+		return 0;
+
+	x = value & 0xffff;
+	y = value >> 16;
+
+	sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
+
+	key = XInternAtom(dpy, atom, False);
+	if (!key)
+		return 0;
+
+	value = getatomprop(c, key, AnyPropertyType);
+	if (!value)
+		return 0;
+
+	w = value & 0xffff;
+	h = value >> 16;
+
+	if (w <= 0 || h <= 0) {
+		fprintf(stderr, "restorewindowfloatposition: bad float values x = %d, y = %d, w = %d, h = %d for client = %s\n", x, y, w, h, c->name);
+		return 0;
+	}
+
+	c->sfx = m->mx + x;
+	c->sfy = m->my + y;
+	c->sfw = w;
+	c->sfh = h;
+
+	if (c->isfloating) {
+		c->x = c->sfx;
+		c->y = c->sfy;
+		c->w = c->sfw;
+		c->h = c->sfh;
+	}
+
+	return 1;
+}
diff --git a/patch/seamless_restart.h b/patch/seamless_restart.h
new file mode 100644
index 0000000..4d95b6a
--- /dev/null
+++ b/patch/seamless_restart.h
@@ -0,0 +1,17 @@
+#include <stdint.h>
+
+static void persistmonitorstate(Monitor *m);
+static int restoremonitorstate(Monitor *m);
+static void persistclientstate(Client *c);
+static int restoreclientstate(Client *c);
+static void setmonitorfields(Monitor *m);
+static int getmonitorfields(Monitor *m);
+static void setmonitortags(Monitor *m);
+static int getmonitortags(Monitor *m);
+static void setclientfields(Client *c);
+static int getclientfields(Client *c);
+static void setclienttags(Client *c);
+static int getclienttags(Client *c);
+static int getlayoutindex(const Layout *layout);
+static void savewindowfloatposition(Client *c, Monitor *m);
+static int restorewindowfloatposition(Client *c, Monitor *m);
diff --git a/patch/sizehints_ruled.c b/patch/sizehints_ruled.c
new file mode 100644
index 0000000..32de43b
--- /dev/null
+++ b/patch/sizehints_ruled.c
@@ -0,0 +1,33 @@
+void
+checkfloatingrules(Client *c)
+{
+	const char *class, *instance;
+	Atom wintype;
+	char role[64];
+	unsigned int i;
+	const Rule *r;
+	XClassHint ch = { NULL, NULL };
+
+	XGetClassHint(dpy, c->win, &ch);
+	class    = ch.res_class ? ch.res_class : broken;
+	instance = ch.res_name  ? ch.res_name  : broken;
+	wintype  = getatomprop(c, netatom[NetWMWindowType], XA_ATOM);
+	gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
+
+	for (i = 0; i < LENGTH(rules); i++) {
+		r = &rules[i];
+		if ((!r->title || strstr(c->name, r->title))
+		&& (!r->class || strstr(class, r->class))
+		&& (!r->role || strstr(role, r->role))
+		&& (!r->instance || strstr(instance, r->instance))
+		&& (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
+		{
+			c->isfloating = r->isfloating;
+		}
+	}
+	if (ch.res_class)
+		XFree(ch.res_class);
+	if (ch.res_name)
+		XFree(ch.res_name);
+}
+
diff --git a/patch/sizehints_ruled.h b/patch/sizehints_ruled.h
new file mode 100644
index 0000000..14c6719
--- /dev/null
+++ b/patch/sizehints_ruled.h
@@ -0,0 +1,2 @@
+static void checkfloatingrules(Client *c);
+
diff --git a/patch/stacker.c b/patch/stacker.c
new file mode 100644
index 0000000..0ed1344
--- /dev/null
+++ b/patch/stacker.c
@@ -0,0 +1,73 @@
+void
+focusstack(const Arg *arg)
+{
+	int i = stackpos(arg);
+	Client *c, *p;
+
+	if (i < 0)
+ 		return;
+
+	if (!selmon->sel)
+		return;
+
+	for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c));
+		i -= (ISVISIBLE(c) ? 1 : 0), p = c, c = c->next);
+	focus(c ? c : p);
+	restack(selmon);
+}
+
+void
+pushstack(const Arg *arg)
+{
+	int i = stackpos(arg);
+	Client *sel = selmon->sel, *c, *p;
+
+	if (i < 0)
+		return;
+	else if (i == 0) {
+		detach(sel);
+		attach(sel);
+	}
+	else {
+		for (p = NULL, c = selmon->clients; c; p = c, c = c->next)
+			if (!(i -= (ISVISIBLE(c) && c != sel)))
+				break;
+		c = c ? c : p;
+		detach(sel);
+		sel->next = c->next;
+		c->next = sel;
+	}
+	arrange(selmon);
+}
+
+int
+stackpos(const Arg *arg)
+{
+	int n, i;
+	Client *c, *l;
+
+	if (!selmon->clients)
+		return -1;
+
+	if (arg->i == PREVSEL) {
+		for (l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext);
+		if (!l)
+			return -1;
+		for (i = 0, c = selmon->clients; c != l; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
+		return i;
+	}
+	else if (ISINC(arg->i)) {
+		if (!selmon->sel)
+			return -1;
+		for (i = 0, c = selmon->clients; c != selmon->sel; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
+		for (n = i; c; n += (ISVISIBLE(c) ? 1 : 0), c = c->next);
+		return MOD(i + GETINC(arg->i), n);
+	}
+	else if (arg->i < 0) {
+		for (i = 0, c = selmon->clients; c; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
+		return MAX(i + arg->i, 0);
+	}
+	else
+		return arg->i;
+}
+
diff --git a/patch/stacker.h b/patch/stacker.h
new file mode 100644
index 0000000..ee420bd
--- /dev/null
+++ b/patch/stacker.h
@@ -0,0 +1,11 @@
+#define GETINC(X)               ((X) - 2000)
+#define INC(X)                  ((X) + 2000)
+#define ISINC(X)                ((X) > 1000 && (X) < 3000)
+#define PREVSEL                 3000
+#define MOD(N,M)                ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M))
+#define TRUNC(X,A,B)            (MAX((A), MIN((X), (B))))
+
+static void focusstack(const Arg *arg);
+static void pushstack(const Arg *arg);
+static int stackpos(const Arg *arg);
+
diff --git a/patch/togglefullscreen.c b/patch/togglefullscreen.c
new file mode 100644
index 0000000..a62edef
--- /dev/null
+++ b/patch/togglefullscreen.c
@@ -0,0 +1,10 @@
+void
+togglefullscreen(const Arg *arg)
+{
+	Client *c = selmon->sel;
+	if (!c)
+		return;
+
+	setfullscreen(c, !c->isfullscreen);
+}
+
diff --git a/patch/togglefullscreen.h b/patch/togglefullscreen.h
new file mode 100644
index 0000000..96a6770
--- /dev/null
+++ b/patch/togglefullscreen.h
@@ -0,0 +1,2 @@
+static void togglefullscreen(const Arg *arg);
+
diff --git a/patch/unfloatvisible.c b/patch/unfloatvisible.c
new file mode 100644
index 0000000..fb8888f
--- /dev/null
+++ b/patch/unfloatvisible.c
@@ -0,0 +1,15 @@
+void
+unfloatvisible(const Arg *arg)
+{
+    Client *c;
+
+    for (c = selmon->clients; c; c = c->next)
+        if (ISVISIBLE(c) && c->isfloating)
+            c->isfloating = c->isfixed;
+
+    if (arg && arg->v)
+        setlayout(arg);
+    else
+        arrange(selmon);
+}
+
diff --git a/patch/unfloatvisible.h b/patch/unfloatvisible.h
new file mode 100644
index 0000000..f15bc66
--- /dev/null
+++ b/patch/unfloatvisible.h
@@ -0,0 +1,2 @@
+static void unfloatvisible(const Arg *arg);
+
diff --git a/transient.c b/transient.c
new file mode 100644
index 0000000..158460f
--- /dev/null
+++ b/transient.c
@@ -0,0 +1,43 @@
+/* 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/util.c b/util.c
new file mode 100644
index 0000000..96b82c9
--- /dev/null
+++ b/util.c
@@ -0,0 +1,36 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+void
+die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+
+	if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+		fputc(' ', stderr);
+		perror(NULL);
+	} else {
+		fputc('\n', stderr);
+	}
+
+	exit(1);
+}
+
+void *
+ecalloc(size_t nmemb, size_t size)
+{
+	void *p;
+
+	if (!(p = calloc(nmemb, size)))
+		die("calloc:");
+	return p;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..1e3cf9a
--- /dev/null
+++ b/util.h
@@ -0,0 +1,19 @@
+/* See LICENSE file for copyright and license details. */
+
+#ifndef MAX
+#define MAX(A, B)               ((A) > (B) ? (A) : (B))
+#endif
+#ifndef MIN
+#define MIN(A, B)               ((A) < (B) ? (A) : (B))
+#endif
+#define BETWEEN(X, A, B)        ((A) <= (X) && (X) <= (B))
+
+#ifdef _DEBUG
+#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
+
+void die(const char *fmt, ...);
+void *ecalloc(size_t nmemb, size_t size);
+