diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/LICENSE /tmp/b/LICENSE
--- /tmp/a/LICENSE	2026-01-30 11:19:28.650266350 +0100
+++ /tmp/b/LICENSE	2025-11-04 22:30:12.081593914 +0100
@@ -1,6 +1,5 @@
 MIT/X Consortium License
 
-© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
 © 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>
@@ -12,6 +11,7 @@
 © 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>
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/Makefile /tmp/b/Makefile
--- /tmp/a/Makefile	2026-01-30 11:19:28.650266350 +0100
+++ /tmp/b/Makefile	2026-02-16 18:19:32.186849188 +0100
@@ -25,7 +25,7 @@
 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}
+		dwm.1 drw.h util.h ${SRC} tcl.c dwm.png transient.c dwm-${VERSION}
 	tar -cf dwm-${VERSION}.tar dwm-${VERSION}
 	gzip dwm-${VERSION}.tar
 	rm -rf dwm-${VERSION}
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/config.def.h /tmp/b/config.def.h
--- /tmp/a/config.def.h	2026-01-30 11:19:28.660280483 +0100
+++ /tmp/b/config.def.h	2026-02-16 18:23:31.172870815 +0100
@@ -1,8 +1,13 @@
 /* See LICENSE file for copyright and license details. */
+#include "tcl.c"
 
 /* appearance */
 static const unsigned int borderpx  = 1;        /* border pixel of windows */
 static const unsigned int snap      = 32;       /* snap pixel */
+static const unsigned int gappx     = 0;        /* gaps between windows */
+static const int rainbow_border     = 0;        /* 1 = animated rainbow border on focused window */
+static const int rainbow_interval   = 50;       /* ms between animation frames */
+static const float rainbow_step     = 3.0;      /* hue degrees to shift per frame */
 static const int showbar            = 1;        /* 0 means no bar */
 static const int topbar             = 1;        /* 0 means bottom bar */
 static const char *fonts[]          = { "monospace:size=10" };
@@ -26,9 +31,9 @@
 	 *	WM_CLASS(STRING) = instance, class
 	 *	WM_NAME(STRING) = title
 	 */
-	/* class      instance    title       tags mask     isfloating   monitor */
-	{ "Gimp",     NULL,       NULL,       0,            1,           -1 },
-	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
+	/* class      instance    title       tags mask     iscentered   isfloating   monitor */
+	{ "Gimp",     NULL,       NULL,       0,            0,           1,           -1 },
+	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           0,           -1 },
 };
 
 /* layout(s) */
@@ -41,12 +46,14 @@
 static const Layout layouts[] = {
 	/* symbol     arrange function */
 	{ "[]=",      tile },    /* first entry is default */
-	{ "><>",      NULL },    /* no layout function means floating behavior */
+	{ "|||",      tcl },     /* triple column layout */
 	{ "[M]",      monocle },
+	{ "><>",      NULL },    /* no layout function means floating behavior */
 };
 
 /* key definitions */
 #define MODKEY Mod1Mask
+#define STATUSBAR "dwmblocks"
 #define TAGKEYS(KEY,TAG) \
 	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
 	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
@@ -76,10 +83,16 @@
 	{ MODKEY,                       XK_Tab,    view,           {0} },
 	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
 	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
-	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
+	{ MODKEY,                       XK_y,      setlayout,      {.v = &layouts[1]} },
 	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} },
+	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[3]} },
 	{ MODKEY,                       XK_space,  setlayout,      {0} },
 	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} },
+	{ MODKEY,                       XK_minus,  setgaps,        {.i = -5 } },
+	{ MODKEY,                       XK_equal,  setgaps,        {.i = +5 } },
+	{ MODKEY|ShiftMask,             XK_minus,  setgaps,        {.i = 0 } },
+	{ MODKEY,                       XK_F5,     togglerainbow,  {0} },
+	{ MODKEY|ShiftMask,             XK_F5,     togglerainbowbar,  {0} },
 	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } },
 	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
 	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
@@ -105,7 +118,12 @@
 	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
 	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
 	{ ClkWinTitle,          0,              Button2,        zoom,           {0} },
-	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
+	{ ClkStatusText,        0,              Button1,        sigstatusbar,   {.i = 1} },
+	{ ClkStatusText,        0,              Button2,        sigstatusbar,   {.i = 2} },
+	{ ClkStatusText,        0,              Button3,        sigstatusbar,   {.i = 3} },
+	{ ClkStatusText,        0,              Button4,        sigstatusbar,   {.i = 4} },
+	{ ClkStatusText,        0,              Button5,        sigstatusbar,   {.i = 5} },
+	{ ClkStatusText,        ShiftMask,      Button1,        sigstatusbar,   {.i = 6} },
 	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
 	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
 	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
@@ -114,4 +132,3 @@
 	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
 };
-
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/config.mk /tmp/b/config.mk
--- /tmp/a/config.mk	2026-01-30 11:19:28.660280483 +0100
+++ /tmp/b/config.mk	2026-02-12 20:15:34.935977179 +0100
@@ -23,13 +23,13 @@
 
 # includes and libs
 INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lm
 
 # flags
 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
 #CFLAGS   = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
-CFLAGS   = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
-LDFLAGS  = ${LIBS}
+CFLAGS   = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE ${INCS} ${CPPFLAGS}
+LDFLAGS  = -pie -Wl,-z,relro,-z,now ${LIBS}
 
 # Solaris
 #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/drw.c /tmp/b/drw.c
--- /tmp/a/drw.c	2026-01-30 11:19:28.660280483 +0100
+++ /tmp/b/drw.c	2026-02-12 21:57:48.708660438 +0100
@@ -79,6 +79,8 @@
 void
 drw_free(Drw *drw)
 {
+	if (!drw)
+		return;
 	XFreePixmap(drw->dpy, drw->drawable);
 	XFreeGC(drw->dpy, drw->gc);
 	drw_fontset_free(drw->fonts);
@@ -160,9 +162,12 @@
 void
 drw_fontset_free(Fnt *font)
 {
-	if (font) {
-		drw_fontset_free(font->next);
+	Fnt *next;
+
+	while (font) {
+		next = font->next;
 		xfont_free(font);
+		font = next;
 	}
 }
 
@@ -200,7 +205,6 @@
 	if (!drw || !c)
 		return;
 
-	/* c is typedef XftColor Clr */
 	XftColorFree(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
 	             DefaultColormap(drw->dpy, drw->screen), c);
 }
@@ -269,13 +273,17 @@
 	if (!render) {
 		w = invert ? invert : ~invert;
 	} else {
-		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
-		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+		if (!drw->nobg) {
+			XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
+			XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+		}
 		if (w < lpad)
 			return x + w;
 		d = XftDrawCreate(drw->dpy, drw->drawable,
 		                  DefaultVisual(drw->dpy, drw->screen),
 		                  DefaultColormap(drw->dpy, drw->screen));
+		if (!d)
+			return x + w;
 		x += lpad;
 		w -= lpad;
 	}
@@ -331,17 +339,29 @@
 		if (utf8strlen) {
 			if (render) {
 				ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
-				XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
-				                  usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
+				if (drw->nobg) {
+					static XftColor nobg_fg;
+					static int nobg_fg_init = 0;
+					if (!nobg_fg_init) {
+						if (XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
+							DefaultColormap(drw->dpy, drw->screen), "#000000", &nobg_fg))
+							nobg_fg_init = 1;
+					}
+					XftDrawStringUtf8(d, nobg_fg_init ? &nobg_fg : &drw->scheme[invert ? ColBg : ColFg],
+					                  usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
+				} else {
+					XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
+					                  usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
+				}
 			}
 			x += ew;
-			w -= ew;
+			w = ew < w ? w - ew : 0;
 		}
 		if (utf8err && (!render || invalid_width < w)) {
 			if (render)
 				drw_text(drw, x, y, w, h, 0, invalid, invert);
 			x += invalid_width;
-			w -= invalid_width;
+			w = invalid_width < w ? w - invalid_width : 0;
 		}
 		if (render && overflow)
 			drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
@@ -365,6 +385,15 @@
 			if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
 				goto no_match;
 
+			/* cap fallback fonts to prevent unbounded growth */
+			{
+				int nfonts = 0;
+				for (curfont = drw->fonts; curfont; curfont = curfont->next)
+					nfonts++;
+				if (nfonts >= 64)
+					goto no_match;
+			}
+
 			fccharset = FcCharSetCreate();
 			FcCharSetAddChar(fccharset, utf8codepoint);
 
@@ -412,7 +441,7 @@
 		return;
 
 	XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
-	XSync(drw->dpy, False);
+	XFlush(drw->dpy);
 }
 
 unsigned int
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/drw.h /tmp/b/drw.h
--- /tmp/a/drw.h	2026-01-30 11:19:28.660280483 +0100
+++ /tmp/b/drw.h	2026-02-12 21:57:48.708660438 +0100
@@ -24,6 +24,7 @@
 	GC gc;
 	Clr *scheme;
 	Fnt *fonts;
+	int nobg;
 } Drw;
 
 /* Drawable abstraction */
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/dwm.c /tmp/b/dwm.c
--- /tmp/a/dwm.c	2026-01-30 11:19:28.660280483 +0100
+++ /tmp/b/dwm.c	2026-02-16 16:56:18.592177229 +0100
@@ -20,14 +20,18 @@
  *
  * To understand everything else, start reading main().
  */
+#include <dirent.h>
 #include <errno.h>
 #include <locale.h>
+#include <math.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/select.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <X11/cursorfont.h>
@@ -91,7 +95,7 @@
 	int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
 	int bw, oldbw;
 	unsigned int tags;
-	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+	int isfixed, iscentered, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
 	Client *next;
 	Client *snext;
 	Monitor *mon;
@@ -110,6 +114,7 @@
 	void (*arrange)(Monitor *);
 } Layout;
 
+typedef struct Pertag Pertag;
 struct Monitor {
 	char ltsymbol[16];
 	float mfact;
@@ -118,6 +123,7 @@
 	int by;               /* bar geometry */
 	int mx, my, mw, mh;   /* screen size */
 	int wx, wy, ww, wh;   /* window area  */
+	int gappx;            /* gaps between windows */
 	unsigned int seltags;
 	unsigned int sellt;
 	unsigned int tagset[2];
@@ -129,6 +135,7 @@
 	Monitor *next;
 	Window barwin;
 	const Layout *lt[2];
+	Pertag *pertag;
 };
 
 typedef struct {
@@ -136,6 +143,7 @@
 	const char *instance;
 	const char *title;
 	unsigned int tags;
+	int iscentered;
 	int isfloating;
 	int monitor;
 } Rule;
@@ -162,6 +170,9 @@
 static Monitor *dirtomon(int dir);
 static void drawbar(Monitor *m);
 static void drawbars(void);
+static void drawrainbowbar(Monitor *m);
+static void drawrainbowborder(Client *c);
+static unsigned long hsvtorgb(float h, float s, float v);
 static void enternotify(XEvent *e);
 static void expose(XEvent *e);
 static void focus(Client *c);
@@ -171,6 +182,7 @@
 static Atom getatomprop(Client *c, Atom prop);
 static int getrootptr(int *x, int *y);
 static long getstate(Window w);
+static pid_t getstatusbarpid();
 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
 static void grabbuttons(Client *c, int focused);
 static void grabkeys(void);
@@ -187,6 +199,7 @@
 static void pop(Client *c);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
+static void restoresession(void);
 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);
@@ -199,17 +212,21 @@
 static void setclientstate(Client *c, long state);
 static void setfocus(Client *c);
 static void setfullscreen(Client *c, int fullscreen);
+static void setgaps(const Arg *arg);
 static void setlayout(const Arg *arg);
 static void setmfact(const Arg *arg);
 static void setup(void);
 static void seturgent(Client *c, int urg);
 static void showhide(Client *c);
+static void sigstatusbar(const Arg *arg);
 static void spawn(const Arg *arg);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void tile(Monitor *m);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
+static void togglerainbow(const Arg *arg);
+static void togglerainbowbar(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
 static void unfocus(Client *c, int setfocus);
@@ -236,6 +253,9 @@
 /* variables */
 static const char broken[] = "broken";
 static char stext[256];
+static int statusw;
+static int statussig;
+static pid_t statuspid = -1;
 static int screen;
 static int sw, sh;           /* X display screen geometry width, height */
 static int bh;               /* bar height */
@@ -259,6 +279,7 @@
 	[UnmapNotify] = unmapnotify
 };
 static Atom wmatom[WMLast], netatom[NetLast];
+static Atom dwmatom_tags, dwmatom_mon, dwmatom_index;
 static int running = 1;
 static Cur *cursor[CurLast];
 static Clr **scheme;
@@ -267,9 +288,29 @@
 static Monitor *mons, *selmon;
 static Window root, wmcheckwin;
 
+/* rainbow border state */
+static float rainbow_hue = 0;
+static Pixmap rainbow_pm = None;
+static int rainbow_pm_w = 0, rainbow_pm_h = 0;
+static GC rainbow_gc = None;
+static XImage *rainbow_img = NULL;
+static XImage *rainbow_bar_img = NULL;
+static int rainbow_bar_img_w = 0, rainbow_bar_img_h = 0;
+static int rainbow_enabled;
+static int rainbow_bar_enabled;
+
 /* configuration, allows nested code to access above variables */
 #include "config.h"
 
+struct Pertag {
+	unsigned int curtag, prevtag; /* current and previous tag */
+	int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+	float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+	unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+	const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes  */
+	int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+};
+
 /* compile-time check if all tags fit into an unsigned int bit array. */
 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
 
@@ -284,6 +325,7 @@
 	XClassHint ch = { NULL, NULL };
 
 	/* rule matching */
+	c->iscentered = 0;
 	c->isfloating = 0;
 	c->tags = 0;
 	XGetClassHint(dpy, c->win, &ch);
@@ -296,6 +338,7 @@
 		&& (!r->class || strstr(class, r->class))
 		&& (!r->instance || strstr(instance, r->instance)))
 		{
+			c->iscentered = r->iscentered;
 			c->isfloating = r->isfloating;
 			c->tags |= r->tags;
 			for (m = mons; m && m->num != r->monitor; m = m->next);
@@ -352,7 +395,7 @@
 			*h -= c->baseh;
 		}
 		/* adjust for aspect limits */
-		if (c->mina > 0 && c->maxa > 0) {
+		if (c->mina > 0 && c->maxa > 0 && *w > 0 && *h > 0) {
 			if (c->maxa < (float)*w / *h)
 				*w = *h * c->maxa + 0.5;
 			else if (c->mina < (float)*h / *w)
@@ -422,6 +465,7 @@
 	Client *c;
 	Monitor *m;
 	XButtonPressedEvent *ev = &e->xbutton;
+	char *text, *s, ch;
 
 	click = ClkRootWin;
 	/* focus monitor if necessary */
@@ -440,9 +484,27 @@
 			arg.ui = 1 << i;
 		} else if (ev->x < x + TEXTW(selmon->ltsymbol))
 			click = ClkLtSymbol;
-		else if (ev->x > selmon->ww - (int)TEXTW(stext))
+		else if (ev->x > selmon->ww - statusw) {
+			x = selmon->ww - statusw;
 			click = ClkStatusText;
-		else
+			statussig = 0;
+			for (text = s = stext; *s && x <= ev->x; s++) {
+				if ((unsigned char)(*s) < ' ') {
+					ch = *s;
+					*s = '\0';
+					x += TEXTW(text) - lrpad;
+					*s = ch;
+					text = s + 1;
+					if (x >= ev->x)
+						break;
+					/* reset on matching signal raw byte */
+					if (ch == statussig)
+						statussig = 0;
+					else
+						statussig = ch;
+				}
+			}
+		} else
 			click = ClkWinTitle;
 	} else if ((c = wintoclient(ev->window))) {
 		focus(c);
@@ -481,6 +543,14 @@
 		while (m->stack)
 			unmanage(m->stack, 0);
 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
+	if (rainbow_img)
+		XDestroyImage(rainbow_img);
+	if (rainbow_bar_img)
+		XDestroyImage(rainbow_bar_img);
+	if (rainbow_pm != None)
+		XFreePixmap(dpy, rainbow_pm);
+	if (rainbow_gc != None)
+		XFreeGC(dpy, rainbow_gc);
 	while (mons)
 		cleanupmon(mons);
 	for (i = 0; i < CurLast; i++)
@@ -508,6 +578,7 @@
 	}
 	XUnmapWindow(dpy, mon->barwin);
 	XDestroyWindow(dpy, mon->barwin);
+	free(mon->pertag);
 	free(mon);
 }
 
@@ -588,7 +659,7 @@
 	if ((c = wintoclient(ev->window))) {
 		if (ev->value_mask & CWBorderWidth)
 			c->bw = ev->border_width;
-		else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
+		else if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
 			m = c->mon;
 			if (ev->value_mask & CWX) {
 				c->oldx = c->x;
@@ -633,6 +704,7 @@
 createmon(void)
 {
 	Monitor *m;
+	unsigned int i;
 
 	m = ecalloc(1, sizeof(Monitor));
 	m->tagset[0] = m->tagset[1] = 1;
@@ -640,9 +712,24 @@
 	m->nmaster = nmaster;
 	m->showbar = showbar;
 	m->topbar = topbar;
+	m->gappx = gappx;
 	m->lt[0] = &layouts[0];
 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+	m->pertag = ecalloc(1, sizeof(Pertag));
+	m->pertag->curtag = m->pertag->prevtag = 1;
+
+	for (i = 0; i <= LENGTH(tags); i++) {
+		m->pertag->nmasters[i] = m->nmaster;
+		m->pertag->mfacts[i] = m->mfact;
+
+		m->pertag->ltidxs[i][0] = m->lt[0];
+		m->pertag->ltidxs[i][1] = m->lt[1];
+		m->pertag->sellts[i] = m->sellt;
+
+		m->pertag->showbars[i] = m->showbar;
+	}
+
 	return m;
 }
 
@@ -706,11 +793,32 @@
 	if (!m->showbar)
 		return;
 
+	/* paint rainbow gradient background when enabled */
+	if (rainbow_bar_enabled) {
+		drawrainbowbar(m);
+		drw->nobg = 1;
+	}
+
 	/* draw status first so it can be overdrawn by tags later */
 	if (m == selmon) { /* status is only drawn on selected monitor */
+		char *text, *s, ch;
 		drw_setscheme(drw, scheme[SchemeNorm]);
-		tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
-		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+
+		x = 0;
+		for (text = s = stext; *s; s++) {
+			if ((unsigned char)(*s) < ' ') {
+				ch = *s;
+				*s = '\0';
+				tw = TEXTW(text) - lrpad;
+				drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
+				x += tw;
+				*s = ch;
+				text = s + 1;
+			}
+		}
+		tw = TEXTW(text) - lrpad + 2;
+		drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
+		tw = statusw;
 	}
 
 	for (c = m->clients; c; c = c->next) {
@@ -720,9 +828,14 @@
 	}
 	x = 0;
 	for (i = 0; i < LENGTH(tags); i++) {
+		int sel = m->tagset[m->seltags] & 1 << i;
 		w = TEXTW(tags[i]);
-		drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+		drw_setscheme(drw, scheme[sel ? SchemeSel : SchemeNorm]);
+		if (sel && drw->nobg)
+			drw->nobg = 0;
 		drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+		if (sel && rainbow_bar_enabled)
+			drw->nobg = 1;
 		if (occ & 1 << i)
 			drw_rect(drw, x + boxs, boxs, boxw, boxw,
 				m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
@@ -739,11 +852,12 @@
 			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
 			if (m->sel->isfloating)
 				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
-		} else {
+		} else if (!rainbow_bar_enabled) {
 			drw_setscheme(drw, scheme[SchemeNorm]);
 			drw_rect(drw, x, 0, w, bh, 1, 1);
 		}
 	}
+	drw->nobg = 0;
 	drw_map(drw, m->barwin, 0, 0, m->ww, bh);
 }
 
@@ -756,6 +870,156 @@
 		drawbar(m);
 }
 
+unsigned long
+hsvtorgb(float h, float s, float v)
+{
+	float c = v * s;
+	float x = c * (1.0f - fabsf(fmodf(h / 60.0f, 2.0f) - 1.0f));
+	float m = v - c;
+	float r, g, b;
+
+	if (h < 60)       { r = c; g = x; b = 0; }
+	else if (h < 120)  { r = x; g = c; b = 0; }
+	else if (h < 180)  { r = 0; g = c; b = x; }
+	else if (h < 240)  { r = 0; g = x; b = c; }
+	else if (h < 300)  { r = x; g = 0; b = c; }
+	else               { r = c; g = 0; b = x; }
+
+	unsigned char R = (unsigned char)((r + m) * 255);
+	unsigned char G = (unsigned char)((g + m) * 255);
+	unsigned char B = (unsigned char)((b + m) * 255);
+
+	return (R << 16) | (G << 8) | B;
+}
+
+void
+drawrainbowbar(Monitor *m)
+{
+	int w = m->ww;
+
+	if (!m->showbar)
+		return;
+
+	if (!rainbow_bar_img || rainbow_bar_img_w != w || rainbow_bar_img_h != bh) {
+		if (rainbow_bar_img)
+			XDestroyImage(rainbow_bar_img);
+		char *data = calloc((size_t)w * bh, 4);
+		if (!data)
+			return;
+		rainbow_bar_img = XCreateImage(dpy, DefaultVisual(dpy, screen),
+			DefaultDepth(dpy, screen), ZPixmap, 0, data, w, bh, 32, 0);
+		if (!rainbow_bar_img) {
+			free(data);
+			return;
+		}
+		rainbow_bar_img_w = w;
+		rainbow_bar_img_h = bh;
+	}
+
+	for (int x = 0; x < w; x++) {
+		float hue = fmodf(rainbow_hue + 360.0f * x / w, 360.0f);
+		unsigned long color = hsvtorgb(hue, 0.7f, 1.0f);
+		for (int y = 0; y < bh; y++)
+			XPutPixel(rainbow_bar_img, x, y, color);
+	}
+
+	XPutImage(dpy, drw->drawable, drw->gc, rainbow_bar_img, 0, 0, 0, 0, w, bh);
+}
+
+void
+drawrainbowborder(Client *c)
+{
+	if (!c || c->isfullscreen || !c->bw)
+		return;
+
+	int bw = c->bw;
+	int w = c->w;
+	int h = c->h;
+	int ow = w + 2 * bw;
+	int oh = h + 2 * bw;
+	int perimeter = 2 * ow + 2 * h;
+	int pos = 0;
+	float hue;
+	unsigned long color;
+
+	/* create/resize cached pixmap */
+	if (rainbow_pm == None || rainbow_pm_w != ow || rainbow_pm_h != oh) {
+		if (rainbow_pm != None)
+			XFreePixmap(dpy, rainbow_pm);
+		rainbow_pm = XCreatePixmap(dpy, root, ow, oh, DefaultDepth(dpy, screen));
+		rainbow_pm_w = ow;
+		rainbow_pm_h = oh;
+		/* invalidate image cache on size change */
+		if (rainbow_img) {
+			XDestroyImage(rainbow_img);
+			rainbow_img = NULL;
+		}
+	}
+
+	if (rainbow_gc == None)
+		rainbow_gc = XCreateGC(dpy, root, 0, NULL);
+
+	/* create client-side image buffer (single XPutImage instead of per-pixel X calls) */
+	if (!rainbow_img) {
+		char *data = calloc(ow * oh, 4);
+		if (!data)
+			return;
+		rainbow_img = XCreateImage(dpy, DefaultVisual(dpy, screen),
+			DefaultDepth(dpy, screen), ZPixmap, 0, data, ow, oh, 32, 0);
+		if (!rainbow_img) {
+			free(data);
+			return;
+		}
+	}
+
+	/*
+	 * X11 tiles the border pixmap from the client area origin, not the
+	 * outer border corner.  Border regions map to these pixmap coords:
+	 *   Top:    y [oh-bw .. oh-1],  x wraps from (ow-bw)
+	 *   Right:  x [w .. w+bw-1],    y [0 .. h-1]
+	 *   Bottom: y [h .. h+bw-1],    x wraps from (ow-bw)
+	 *   Left:   x [ow-bw .. ow-1],  y [0 .. h-1]
+	 */
+
+	/* top border: screen left to right (includes corners) */
+	for (int i = 0; i < ow; i++, pos++) {
+		int px = (ow - bw + i) % ow;
+		hue = fmodf(rainbow_hue + 360.0f * pos / perimeter, 360.0f);
+		color = hsvtorgb(hue, 1.0f, 1.0f);
+		for (int j = 0; j < bw; j++)
+			XPutPixel(rainbow_img, px, oh - bw + j, color);
+	}
+
+	/* right border: top to bottom (excludes corners) */
+	for (int i = 0; i < h; i++, pos++) {
+		hue = fmodf(rainbow_hue + 360.0f * pos / perimeter, 360.0f);
+		color = hsvtorgb(hue, 1.0f, 1.0f);
+		for (int j = 0; j < bw; j++)
+			XPutPixel(rainbow_img, w + j, i, color);
+	}
+
+	/* bottom border: screen right to left (includes corners) */
+	for (int i = ow - 1; i >= 0; i--, pos++) {
+		int px = (ow - bw + i) % ow;
+		hue = fmodf(rainbow_hue + 360.0f * pos / perimeter, 360.0f);
+		color = hsvtorgb(hue, 1.0f, 1.0f);
+		for (int j = 0; j < bw; j++)
+			XPutPixel(rainbow_img, px, h + j, color);
+	}
+
+	/* left border: bottom to top (excludes corners) */
+	for (int i = h - 1; i >= 0; i--, pos++) {
+		hue = fmodf(rainbow_hue + 360.0f * pos / perimeter, 360.0f);
+		color = hsvtorgb(hue, 1.0f, 1.0f);
+		for (int j = 0; j < bw; j++)
+			XPutPixel(rainbow_img, ow - bw + j, i, color);
+	}
+
+	/* single X call to upload entire border image */
+	XPutImage(dpy, rainbow_pm, rainbow_gc, rainbow_img, 0, 0, 0, 0, ow, oh);
+	XSetWindowBorderPixmap(dpy, c->win, rainbow_pm);
+}
+
 void
 enternotify(XEvent *e)
 {
@@ -800,7 +1064,10 @@
 		detachstack(c);
 		attachstack(c);
 		grabbuttons(c, 1);
-		XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+		if (rainbow_enabled)
+			drawrainbowborder(c);
+		else
+			XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
 		setfocus(c);
 	} else {
 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@@ -877,6 +1144,58 @@
 	return atom;
 }
 
+pid_t
+getstatusbarpid()
+{
+	char path[280], name[256], *str, *c;
+	FILE *fp;
+	DIR *dir;
+	struct dirent *ent;
+	size_t n;
+
+	/* validate cached PID */
+	if (statuspid > 0) {
+		snprintf(path, sizeof(path), "/proc/%u/cmdline", (unsigned)statuspid);
+		if ((fp = fopen(path, "r"))) {
+			n = fread(name, 1, sizeof(name) - 1, fp);
+			fclose(fp);
+			if (n > 0) {
+				name[n] = '\0';
+				str = name;
+				while ((c = strchr(str, '/')))
+					str = c + 1;
+				if (!strcmp(str, STATUSBAR))
+					return statuspid;
+			}
+		}
+	}
+
+	/* scan /proc for the process */
+	if (!(dir = opendir("/proc")))
+		return -1;
+	while ((ent = readdir(dir))) {
+		if (ent->d_name[0] < '0' || ent->d_name[0] > '9')
+			continue;
+		snprintf(path, sizeof(path), "/proc/%s/cmdline", ent->d_name);
+		if (!(fp = fopen(path, "r")))
+			continue;
+		n = fread(name, 1, sizeof(name) - 1, fp);
+		fclose(fp);
+		if (n > 0) {
+			name[n] = '\0';
+			str = name;
+			while ((c = strchr(str, '/')))
+				str = c + 1;
+			if (!strcmp(str, STATUSBAR)) {
+				closedir(dir);
+				return strtol(ent->d_name, NULL, 10);
+			}
+		}
+	}
+	closedir(dir);
+	return -1;
+}
+
 int
 getrootptr(int *x, int *y)
 {
@@ -900,7 +1219,7 @@
 		&real, &format, &n, &extra, (unsigned char **)&p) != Success)
 		return -1;
 	if (n != 0)
-		result = *p;
+		result = *(long *)p;
 	XFree(p);
 	return result;
 }
@@ -931,7 +1250,7 @@
 void
 grabbuttons(Client *c, int focused)
 {
-	updatenumlockmask();
+	/* numlockmask is updated by grabkeys() on MappingNotify */
 	{
 		unsigned int i, j;
 		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
@@ -980,7 +1299,7 @@
 void
 incnmaster(const Arg *arg)
 {
-	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
 	arrange(selmon);
 }
 
@@ -1053,6 +1372,35 @@
 		applyrules(c);
 	}
 
+	/* restore tags and monitor from previous dwm session */
+	{
+		Atom da;
+		int di;
+		unsigned long nitems, dl;
+		unsigned char *p = NULL;
+
+		if (XGetWindowProperty(dpy, w, dwmatom_tags, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1)
+				c->tags = (unsigned int)(*(long *)p);
+			XFree(p);
+		}
+		p = NULL;
+		if (XGetWindowProperty(dpy, w, dwmatom_mon, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1) {
+				Monitor *m;
+				int mon = (int)(*(long *)p);
+				for (m = mons; m; m = m->next)
+					if (m->num == mon) {
+						c->mon = m;
+						break;
+					}
+			}
+			XFree(p);
+		}
+	}
+
 	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)
@@ -1068,6 +1416,10 @@
 	updatewindowtype(c);
 	updatesizehints(c);
 	updatewmhints(c);
+	if (c->iscentered) {
+		c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
+		c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
+	}
 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
 	grabbuttons(c, 0);
 	if (!c->isfloating)
@@ -1161,8 +1513,10 @@
 	if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 		None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
 		return;
-	if (!getrootptr(&x, &y))
+	if (!getrootptr(&x, &y)) {
+		XUngrabPointer(dpy, CurrentTime);
 		return;
+	}
 	do {
 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
 		switch(ev.type) {
@@ -1256,8 +1610,120 @@
 }
 
 void
+restoresession(void)
+{
+	Monitor *m;
+	Client *c, **list;
+	int *indices;
+	int i, n, di;
+	Atom da;
+	unsigned long nitems, dl;
+	unsigned char *p = NULL;
+
+	/* restore client order per monitor */
+	for (m = mons; m; m = m->next) {
+		/* count clients */
+		for (n = 0, c = m->clients; c; c = c->next, n++);
+		if (n == 0)
+			continue;
+
+		list = ecalloc(n, sizeof(Client *));
+		indices = ecalloc(n, sizeof(int));
+		for (i = 0, c = m->clients; c; c = c->next, i++)
+			list[i] = c;
+
+		/* read saved index for each client */
+		for (i = 0; i < n; i++) {
+			p = NULL;
+			indices[i] = n; /* default: high value = end of list */
+			if (XGetWindowProperty(dpy, list[i]->win, dwmatom_index, 0L, 1L, True, XA_CARDINAL,
+					&da, &di, &nitems, &dl, &p) == Success && p) {
+				if (nitems == 1)
+					indices[i] = (int)(*(long *)p);
+				XFree(p);
+			}
+		}
+
+		/* simple insertion sort by saved index */
+		for (i = 1; i < n; i++) {
+			Client *tmp = list[i];
+			int tmpidx = indices[i];
+			int j = i - 1;
+			while (j >= 0 && indices[j] > tmpidx) {
+				list[j + 1] = list[j];
+				indices[j + 1] = indices[j];
+				j--;
+			}
+			list[j + 1] = tmp;
+			indices[j + 1] = tmpidx;
+		}
+
+		/* rebuild the client list */
+		m->clients = list[0];
+		for (i = 0; i < n - 1; i++)
+			list[i]->next = list[i + 1];
+		list[n - 1]->next = NULL;
+
+		free(indices);
+		free(list);
+	}
+
+	/* restore active tagset per monitor */
+	for (m = mons; m; m = m->next) {
+		char atom_name[32];
+		Atom a;
+
+		snprintf(atom_name, sizeof(atom_name), "_DWM_TAGSET_%d", m->num);
+		a = XInternAtom(dpy, atom_name, False);
+		p = NULL;
+		if (XGetWindowProperty(dpy, root, a, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1)
+				m->tagset[m->seltags] = (unsigned int)(*(long *)p);
+			XFree(p);
+		}
+	}
+
+	/* rearrange all monitors */
+	for (m = mons; m; m = m->next)
+		arrange(m);
+
+	focus(NULL);
+	drawbars();
+}
+
+void
 quit(const Arg *arg)
 {
+	Monitor *m;
+	Client *c;
+	int i;
+
+	for (m = mons; m; m = m->next) {
+		i = 0;
+		for (c = m->clients; c; c = c->next, i++) {
+			long tags = (long)c->tags;
+			long mon = (long)m->num;
+			long idx = (long)i;
+			XChangeProperty(dpy, c->win, dwmatom_tags, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&tags, 1);
+			XChangeProperty(dpy, c->win, dwmatom_mon, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&mon, 1);
+			XChangeProperty(dpy, c->win, dwmatom_index, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&idx, 1);
+		}
+		/* save active tagset per monitor on root window */
+		{
+			char atom_name[32];
+			Atom a;
+			long tagset = (long)m->tagset[m->seltags];
+			snprintf(atom_name, sizeof(atom_name), "_DWM_TAGSET_%d", m->num);
+			a = XInternAtom(dpy, atom_name, False);
+			XChangeProperty(dpy, root, a, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&tagset, 1);
+		}
+	}
+	XSync(dpy, False);
 	running = 0;
 }
 
@@ -1294,7 +1760,6 @@
 	wc.border_width = c->bw;
 	XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
 	configure(c);
-	XSync(dpy, False);
 }
 
 void
@@ -1383,11 +1848,43 @@
 run(void)
 {
 	XEvent ev;
+	int xfd;
+	fd_set rfds;
+	struct timeval tv, now;
+	long long now_ms, last_rainbow_ms = 0;
+
 	/* main event loop */
 	XSync(dpy, False);
-	while (running && !XNextEvent(dpy, &ev))
-		if (handler[ev.type])
-			handler[ev.type](&ev); /* call handler */
+	xfd = ConnectionNumber(dpy);
+
+	while (running) {
+		FD_ZERO(&rfds);
+		FD_SET(xfd, &rfds);
+		tv.tv_sec = 0;
+		tv.tv_usec = (rainbow_enabled || rainbow_bar_enabled) ? (rainbow_interval * 1000L) : 200000L;
+
+		if (select(xfd + 1, &rfds, NULL, NULL, &tv) > 0) {
+			while (XPending(dpy)) {
+				XNextEvent(dpy, &ev);
+				if (handler[ev.type])
+					handler[ev.type](&ev);
+			}
+		}
+
+		/* rainbow animation: only tick at fixed interval */
+		if (rainbow_enabled || rainbow_bar_enabled) {
+			gettimeofday(&now, NULL);
+			now_ms = now.tv_sec * 1000LL + now.tv_usec / 1000;
+			if (now_ms - last_rainbow_ms >= rainbow_interval) {
+				last_rainbow_ms = now_ms;
+				rainbow_hue = fmodf(rainbow_hue + rainbow_step, 360.0f);
+				if (rainbow_enabled && selmon && selmon->sel)
+					drawrainbowborder(selmon->sel);
+				if (rainbow_bar_enabled)
+					drawbars();
+			}
+		}
+	}
 }
 
 void
@@ -1448,7 +1945,7 @@
 	int n;
 	Atom *protocols;
 	int exists = 0;
-	XEvent ev;
+	XEvent ev = {0};
 
 	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
 		while (!exists && n--)
@@ -1508,12 +2005,22 @@
 }
 
 void
+setgaps(const Arg *arg)
+{
+	if ((arg->i == 0) || (selmon->gappx + arg->i < 0))
+		selmon->gappx = 0;
+	else
+		selmon->gappx += arg->i;
+	arrange(selmon);
+}
+
+void
 setlayout(const Arg *arg)
 {
 	if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
-		selmon->sellt ^= 1;
+		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
 	if (arg && arg->v)
-		selmon->lt[selmon->sellt] = (Layout *)arg->v;
+		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
 	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
 	if (selmon->sel)
 		arrange(selmon);
@@ -1532,7 +2039,7 @@
 	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
 	if (f < 0.05 || f > 0.95)
 		return;
-	selmon->mfact = f;
+	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
 	arrange(selmon);
 }
 
@@ -1544,6 +2051,8 @@
 	Atom utf8string;
 	struct sigaction sa;
 
+	rainbow_enabled = rainbow_border;
+
 	/* do not transform children into zombies when they terminate */
 	sigemptyset(&sa.sa_mask);
 	sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
@@ -1579,6 +2088,9 @@
 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
 	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+	dwmatom_tags = XInternAtom(dpy, "_DWM_TAGS", False);
+	dwmatom_mon = XInternAtom(dpy, "_DWM_MON", False);
+	dwmatom_index = XInternAtom(dpy, "_DWM_INDEX", False);
 	/* init cursors */
 	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
 	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
@@ -1645,13 +2157,30 @@
 }
 
 void
+sigstatusbar(const Arg *arg)
+{
+	union sigval sv;
+
+	if (!statussig || statussig > SIGRTMAX - SIGRTMIN)
+		return;
+	sv.sival_int = arg->i;
+	if ((statuspid = getstatusbarpid()) <= 0)
+		return;
+
+	sigqueue(statuspid, SIGRTMIN+statussig, sv);
+}
+
+void
 spawn(const Arg *arg)
 {
 	struct sigaction sa;
+	pid_t pid;
 
-	if (arg->v == dmenucmd)
-		dmenumon[0] = '0' + selmon->num;
-	if (fork() == 0) {
+	if ((pid = fork()) < 0) {
+		fprintf(stderr, "dwm: fork failed: %s\n", strerror(errno));
+		return;
+	}
+	if (pid == 0) {
 		if (dpy)
 			close(ConnectionNumber(dpy));
 		setsid();
@@ -1697,25 +2226,25 @@
 	if (n > m->nmaster)
 		mw = m->nmaster ? m->ww * m->mfact : 0;
 	else
-		mw = m->ww;
-	for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+		mw = m->ww - m->gappx;
+	for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
 		if (i < m->nmaster) {
-			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
-			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
-			if (my + HEIGHT(c) < m->wh)
-				my += HEIGHT(c);
+			h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx;
+			resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0);
+			if (my + HEIGHT(c) + m->gappx < m->wh)
+				my += HEIGHT(c) + m->gappx;
 		} else {
-			h = (m->wh - ty) / (n - i);
-			resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
-			if (ty + HEIGHT(c) < m->wh)
-				ty += HEIGHT(c);
+			h = (m->wh - ty) / (n - i) - m->gappx;
+			resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0);
+			if (ty + HEIGHT(c) + m->gappx < m->wh)
+				ty += HEIGHT(c) + m->gappx;
 		}
 }
 
 void
 togglebar(const Arg *arg)
 {
-	selmon->showbar = !selmon->showbar;
+	selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
 	updatebarpos(selmon);
 	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
 	arrange(selmon);
@@ -1736,6 +2265,21 @@
 }
 
 void
+togglerainbow(const Arg *arg)
+{
+	rainbow_enabled = !rainbow_enabled;
+	if (!rainbow_enabled && selmon && selmon->sel)
+		XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColBorder].pixel);
+}
+
+void
+togglerainbowbar(const Arg *arg)
+{
+	rainbow_bar_enabled = !rainbow_bar_enabled;
+	drawbars();
+}
+
+void
 toggletag(const Arg *arg)
 {
 	unsigned int newtags;
@@ -1754,9 +2298,33 @@
 toggleview(const Arg *arg)
 {
 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+	int i;
 
 	if (newtagset) {
 		selmon->tagset[selmon->seltags] = newtagset;
+
+		if (newtagset == ~0) {
+			selmon->pertag->prevtag = selmon->pertag->curtag;
+			selmon->pertag->curtag = 0;
+		}
+
+		/* test if the user did not select the same tag */
+		if (selmon->pertag->curtag == 0 || !(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+			selmon->pertag->prevtag = selmon->pertag->curtag;
+			for (i = 0; !(newtagset & 1 << i); i++) ;
+			selmon->pertag->curtag = i + 1;
+		}
+
+		/* apply settings for this view */
+		selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+		selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+		selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+		if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+			togglebar(NULL);
+
 		focus(NULL);
 		arrange(selmon);
 	}
@@ -2005,8 +2573,25 @@
 void
 updatestatus(void)
 {
-	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
 		strcpy(stext, "dwm-"VERSION);
+		statusw = TEXTW(stext) - lrpad + 2;
+	} else {
+		char *text, *s, ch;
+
+		statusw  = 0;
+		for (text = s = stext; *s; s++) {
+			if ((unsigned char)(*s) < ' ') {
+				ch = *s;
+				*s = '\0';
+				statusw += TEXTW(text) - lrpad;
+				*s = ch;
+				text = s + 1;
+			}
+		}
+		statusw += TEXTW(text) - lrpad + 2;
+
+	}
 	drawbar(selmon);
 }
 
@@ -2027,8 +2612,10 @@
 
 	if (state == netatom[NetWMFullscreen])
 		setfullscreen(c, 1);
-	if (wtype == netatom[NetWMWindowTypeDialog])
+	if (wtype == netatom[NetWMWindowTypeDialog]) {
+		c->iscentered = 1;
 		c->isfloating = 1;
+	}
 }
 
 void
@@ -2053,11 +2640,37 @@
 void
 view(const Arg *arg)
 {
+	int i;
+	unsigned int tmptag;
+
 	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
 		return;
 	selmon->seltags ^= 1; /* toggle sel tagset */
-	if (arg->ui & TAGMASK)
+	if (arg->ui & TAGMASK) {
 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+		selmon->pertag->prevtag = selmon->pertag->curtag;
+
+		if (arg->ui == ~0)
+			selmon->pertag->curtag = 0;
+		else {
+			for (i = 0; !(arg->ui & 1 << i); i++) ;
+			selmon->pertag->curtag = i + 1;
+		}
+	} else {
+		tmptag = selmon->pertag->prevtag;
+		selmon->pertag->prevtag = selmon->pertag->curtag;
+		selmon->pertag->curtag = tmptag;
+	}
+
+	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+	selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+	selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+	if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+		togglebar(NULL);
+
 	focus(NULL);
 	arrange(selmon);
 }
@@ -2158,6 +2771,7 @@
 		die("pledge");
 #endif /* __OpenBSD__ */
 	scan();
+	restoresession();
 	run();
 	cleanup();
 	XCloseDisplay(dpy);
diff -ruN '--exclude=.git' '--exclude=*.o' '--exclude=dwm' '--exclude=config.h' '--exclude=*.diff' '--exclude=*.orig' '--exclude=*.rej' '--exclude=.gitignore' '--exclude=patches' '--exclude=dwm.png' '--exclude=.claude' /tmp/a/tcl.c /tmp/b/tcl.c
--- /tmp/a/tcl.c	1970-01-01 01:00:00.000000000 +0100
+++ /tmp/b/tcl.c	2026-02-12 20:02:08.026887295 +0100
@@ -0,0 +1,81 @@
+void
+tcl(Monitor *m)
+{
+	int x, y, h, mw, sw, bdw, gap;
+	unsigned int i, n, rc, lc;
+	Client *c;
+
+	for (n = 0, c = nexttiled(m->clients); c;
+	        c = nexttiled(c->next), n++);
+
+	if (n == 0)
+		return;
+
+	gap = m->gappx;
+	c = nexttiled(m->clients);
+
+	mw = m->mfact * m->ww;
+	sw = (m->ww - mw) / 2;
+	bdw = (2 * c->bw);
+	int rsw = m->ww - mw - sw; /* right stack absorbs remainder pixel */
+
+	/* master window */
+	{
+		int mww = (n == 1 ? m->ww - 2 * gap : n == 2 ? mw - gap : mw - 2 * gap) - bdw;
+		int mwh = m->wh - bdw - 2 * gap;
+		resize(c,
+		       (n < 3 ? m->wx : m->wx + sw) + gap,
+		       m->wy + gap,
+		       MAX(1, mww), MAX(1, mwh),
+		       False);
+	}
+
+	if (--n == 0)
+		return;
+
+	c = nexttiled(c->next);
+
+	/* 2 total windows: master + one stack window (right side) */
+	if (n == 1) {
+		int sw2 = m->ww - mw - bdw - 2 * gap;
+		int sh2 = m->wh - bdw - 2 * gap;
+		resize(c,
+		       m->wx + mw + gap,
+		       m->wy + gap,
+		       MAX(1, sw2), MAX(1, sh2),
+		       False);
+		return;
+	}
+
+	/* 3+ total windows: left stack | master | right stack */
+	rc = n / 2;
+	lc = (n + 1) / 2;
+
+	/* right stack */
+	x = m->wx + mw + sw;
+	y = m->wy + gap;
+	for (i = 0; c && i < rc; c = nexttiled(c->next), i++)
+	{
+		int denom = rc - i;
+		if (denom <= 0) denom = 1;
+		h = (m->wh - (y - m->wy)) / denom - gap;
+		int rw = rsw - bdw - gap;
+		int rh = h - bdw;
+		resize(c, x, y, MAX(1, rw), MAX(1, rh), False);
+		y += HEIGHT(c) + gap;
+	}
+
+	/* left stack */
+	x = m->wx + gap;
+	y = m->wy + gap;
+	for (i = 0; c; c = nexttiled(c->next), i++)
+	{
+		int denom = lc - i;
+		if (denom <= 0) denom = 1;
+		h = (m->wh - (y - m->wy)) / denom - gap;
+		int lw = sw - bdw - gap;
+		int lh = h - bdw;
+		resize(c, x, y, MAX(1, lw), MAX(1, lh), False);
+		y += HEIGHT(c) + gap;
+	}
+}
