dwm-noxz

[fork] suckless dwm - personal fork
git clone https://noxz.tech/git/dwm-noxz.git
dwm-noxz

commit: 19f9d53f2d5b1861e3f0873bf83819038414100c
parent: 6ea8b683de816b459da845acd91fca1da933a1f2
author: Chris Noxz <chris@noxz.tech>
date:   Tue, 4 Feb 2020 22:13:12 +0100
Implement various features

* fifo support
* sticky clients
* command dispatching
* stack management
* layout management
* pertag support
Mconfig.def.h56++-
Mdwm.c404+++++++++++++++++++-
2 files changed, 441 insertions(+), 19 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -50,16 +50,16 @@ static const Rule rules[] = {
 };
 
 /* layout(s) */
-static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */
-static const int nmaster     = 0;    /* number of clients in master area */
-static const int resizehints = 0;    /* 1 means respect size hints in tiled resizals */
+static const float mfact            = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster            = 0;    /* number of clients in master area */
+static const int resizehints        = 0;    /* 1 means respect size hints in tiled resizals */
 
 static const Layout layouts[] = {
 	/* symbol     arrange function */
-	{ "###",      nrowgrid },/* first entry is default */
-	{ "[]=",      tile },
-	{ "><>",      NULL },    /* no layout function means floating behavior */
-	{ "[M]",      monocle },
+	[LayoutGrid]                = { "###",      nrowgrid }, /* default */
+	[LayoutTiled]               = { "[]=",      tile },
+	[LayoutMonocle]             = { "[M]",      monocle },
+	[LayoutFloating]            = { "><>",      NULL },    /* no layout function means floating behavior */
 };
 
 /* key definitions */
@@ -133,3 +133,45 @@ static Button buttons[] = {
 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
 };
 
+static const char *dwmfifo = "/tmp/dwm.fifo";
+static Command commands[] = {
+	{ "spawn ...",          spawn,          {.i = DispCmdLine} },
+	{ "quit",               quit,           {0} },
+	{ "toggle bar",         togglebar,      {0} },
+	{ "focus stack +",      focusstack,     {.i = +1} },
+	{ "focus stack -",      focusstack,     {.i = -1} },
+	{ "move stack +",       movestack,      {.i = +1} },
+	{ "move stack -",       movestack,      {.i = -1} },
+	{ "rotate stack +",     rotatestack,    {.i = +1} },
+	{ "rotate stack -",     rotatestack,    {.i = -1} },
+	{ "inc nmaster +",      incnmaster,     {.i = +1} },
+	{ "inc nmaster -",      incnmaster,     {.i = -1} },
+	{ "set mfact +",        setmfact,       {.f = +0.05} },
+	{ "set mfact -",        setmfact,       {.f = -0.05} },
+	{ "zoom",               zoom,           {0} },
+	{ "kill client",        killclient,     {0} },
+	
+	{ "set layout grid",    setlayout,      {.v = &layouts[LayoutGrid]} },
+	{ "set layout tiled",   setlayout,      {.v = &layouts[LayoutTiled]} },
+	{ "set layout float",   setlayout,      {.v = &layouts[LayoutFloating]} },
+	{ "set layout monocle", setlayout,      {.v = &layouts[LayoutMonocle]} },
+	{ "toggle monocle",     togglelayout,   {.v = &layouts[LayoutMonocle]} },
+	{ "toggle layout",      setlayout,      {0} },
+	{ "rotate layout +",    rotatelayout,   {.i = +1} },
+	{ "rotate layout -",    rotatelayout,   {.i = -1} },
+	
+	{ "toggle floating",    togglefloating, {0} },
+	{ "toggle sticky",      togglesticky,   {0} },
+	{ "focus mon +",        focusmon,       {.i = +1} },
+	{ "focus mon -",        focusmon,       {.i = -1} },
+	{ "tag mon +",          tagmon,         {.i = +1} },
+	{ "tag mon -",          tagmon,         {.i = -1} },
+	
+	{ "view",               view,           {0} },
+	{ "view all",           view,           {.ui = ~0} },
+	{ "tag all",            tag,            {.ui = ~0} },
+	{ "view ...",           view,           {.i = DispUi} },
+	{ "toggle view ...",    toggleview,     {.i = DispUi} },
+	{ "tag ...",            tag,            {.i = DispUi} },
+	{ "toggle tag ...",     toggletag,      {.i = DispUi} },
+};
diff --git a/dwm.c b/dwm.c
@@ -21,6 +21,7 @@
  * To understand everything else, start reading main().
  */
 #include <errno.h>
+#include <fcntl.h>
 #include <locale.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -28,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/select.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <X11/cursorfont.h>
@@ -49,7 +51,7 @@
 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
 #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
                                * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
-#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
+#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
 #define LENGTH(X)               (sizeof X / sizeof X[0])
 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
 #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
@@ -58,6 +60,8 @@
 #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
 
 /* enums */
+enum { DispUi, DispCmdLine }; /* dispatch types */
+enum { LayoutGrid, LayoutTiled, LayoutMonocle, LayoutFloating }; /* layouts, first is default */
 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
 enum { SchemeNorm, SchemeSel, SchemeTagsNorm, SchemeTagsSel, SchemeTitleNorm, SchemeTitleSel, SchemeStatus }; /* color schemes */
 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
@@ -82,6 +86,7 @@ typedef struct {
 	const Arg arg;
 } Button;
 
+typedef struct Pertag Pertag;
 typedef struct Monitor Monitor;
 typedef struct Client Client;
 struct Client {
@@ -92,7 +97,7 @@ struct Client {
 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
 	int bw, oldbw;
 	unsigned int tags;
-	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, issticky;
 	Client *next;
 	Client *snext;
 	Monitor *mon;
@@ -130,6 +135,7 @@ struct Monitor {
 	Monitor *next;
 	Window barwin;
 	const Layout *lt[2];
+	Pertag *pertag;
 };
 
 typedef struct {
@@ -141,6 +147,12 @@ typedef struct {
 	int monitor;
 } Rule;
 
+typedef struct {
+	const char *name;
+	void (*func)(const Arg *arg);
+	const Arg arg;
+} Command;
+
 /* function declarations */
 static void applyrules(Client *c);
 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
@@ -161,9 +173,15 @@ static void destroynotify(XEvent *e);
 static void detach(Client *c);
 static void detachstack(Client *c);
 static Monitor *dirtomon(int dir);
+static void strsplit(char *, char ***, const char *);
+static void dispatchline(const char*, int, void (*)(const Arg*), const Arg*);
+static void dispatchcmd(void);
 static void drawbar(Monitor *m);
 static void drawbars(void);
+static void enqueue(Client *c);
+static void enqueuestack(Client *c);
 static void enternotify(XEvent *e);
+static Bool evpredicate();
 static void expose(XEvent *e);
 static void focus(Client *c);
 static void focusin(XEvent *e);
@@ -192,6 +210,8 @@ 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 movestack(const Arg *arg);
+static void rotatestack(const Arg *arg);
 static void run(void);
 static void scan(void);
 static int sendevent(Client *c, Atom proto);
@@ -200,6 +220,8 @@ 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 togglelayout(const Arg *arg);
+static void rotatelayout(const Arg *arg);
 static void setmfact(const Arg *arg);
 static void get_vt_colors(void);
 static int get_luminance(char *rgb);
@@ -214,6 +236,7 @@ static void tile(Monitor *);
 static void nrowgrid(Monitor *);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
+static void togglesticky(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
 static void unfocus(Client *c, int setfocus);
@@ -270,10 +293,20 @@ static Display *dpy;
 static Drw *drw;
 static Monitor *mons, *selmon;
 static Window root, wmcheckwin;
+static int fifofd;
 
 /* 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]; };
 
@@ -494,6 +527,7 @@ cleanup(void)
 	XSync(dpy, False);
 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
 	XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+	close(fifofd);
 }
 
 void
@@ -634,6 +668,7 @@ Monitor *
 createmon(void)
 {
 	Monitor *m;
+	unsigned int i;
 
 	m = ecalloc(1, sizeof(Monitor));
 	m->tagset[0] = m->tagset[1] = 1;
@@ -644,6 +679,18 @@ createmon(void)
 	m->lt[0] = &layouts[0];
 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+	m->pertag = ecalloc(1, sizeof(Pertag));
+	m->pertag->curtag = m->pertag->prevtag = 1;
+	for (i = 0; i <= LENGTH(tags); i++) {
+		m->pertag->nmasters[i] = m->nmaster;
+		m->pertag->mfacts[i] = m->mfact;
+
+		m->pertag->ltidxs[i][0] = m->lt[0];
+		m->pertag->ltidxs[i][1] = m->lt[1];
+		m->pertag->sellts[i] = m->sellt;
+
+		m->pertag->showbars[i] = m->showbar;
+	}
 	return m;
 }
 
@@ -695,6 +742,106 @@ dirtomon(int dir)
 	return m;
 }
 
+void
+strsplit(char *str, char ***arr, const char *toks)
+{
+	char *p = strtok((char *)str, toks);
+	int len = 0;
+
+	while (p) {
+		if ((*arr = realloc(*arr, sizeof (char*) * len++)) == NULL)
+			die("realloc: failed\n");
+		(*arr)[len - 1] = p;
+		p = strtok(NULL, toks);
+	}
+
+	if ((*arr = realloc(*arr, sizeof (char*) * (len + 1))) == NULL)
+		die("realloc: failed\n");
+	(*arr)[len] = 0;
+}
+
+void
+dispatchline(const char *c, int n, void (*func)(const Arg *), const Arg *arg)
+{
+	char *cmd = NULL;
+	char *line = NULL;
+	char **arr = NULL;
+	Arg a;
+
+	if (strlen(c) < n)
+		return;
+
+	cmd = malloc(n + 1);
+	line = malloc(strlen(c) + 1);
+
+	strncpy(cmd, c, n);
+	strcpy(line, c + n);
+	strsplit(line, &arr, " ");
+
+	switch (arg->i) {
+		case DispUi: {
+			if (sscanf(arr[0], "%d", &a.i))
+			a.ui = 1 << a.i;
+		} break;
+		case DispCmdLine:
+			a.v = (const char **)arr;
+		break;
+	}
+
+	func(&a);
+
+	free(cmd);
+	free(line);
+	free(arr);
+}
+
+void
+dispatchcmd(void)
+{
+	char buf[BUFSIZ];
+	char *ptr, *line, *next;
+	ssize_t n, m;
+	int i;
+
+	if ((n = read(fifofd, buf, sizeof(buf) - 1)) == -1)
+		return;
+
+	buf[n] = '\0';
+	line = buf;
+
+	/* read each line as a single command */
+	while (line) {
+		next = strchr(line, '\n');
+		if (next)
+			*next = '\0';
+		for (i = 0; i < LENGTH(commands); i++) {
+			m = MAX(strlen(line), strlen(commands[i].name));
+			n = (((ptr = strstr(commands[i].name, "...")))
+				? ptr - commands[i].name
+				: m
+			);
+			if (strncmp(commands[i].name, line, n) == 0) {
+				if (n != m)
+					dispatchline(
+						line, n,
+						commands[i].func,
+						&commands[i].arg
+					);
+				else
+					commands[i].func(&commands[i].arg);
+				break;
+			}
+		}
+		if (next)
+			*next = '\n';
+		line = next ? next + 1 : NULL;
+	}
+
+	/* make sure fifo is empty */
+	while (errno != EWOULDBLOCK)
+		read(fifofd, buf, sizeof(buf) - 1);
+}
+
 void
 drawbar(Monitor *m)
 {
@@ -755,6 +902,28 @@ drawbars(void)
 		drawbar(m);
 }
 
+void
+enqueue(Client *c)
+{
+	Client *l;
+	for (l = c->mon->clients; l && l->next; l = l->next);
+	if (l) {
+		l->next = c;
+		c->next = NULL;
+	}
+}
+
+void
+enqueuestack(Client *c)
+{
+	Client *l;
+	for (l = c->mon->stack; l && l->snext; l = l->snext);
+	if (l) {
+		l->snext = c;
+		c->snext = NULL;
+	}
+}
+
 void
 enternotify(XEvent *e)
 {
@@ -774,6 +943,12 @@ enternotify(XEvent *e)
 	focus(c);
 }
 
+Bool
+evpredicate()
+{
+	return True;
+}
+
 void
 expose(XEvent *e)
 {
@@ -973,7 +1148,7 @@ grabkeys(void)
 void
 incnmaster(const Arg *arg)
 {
-	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
 	arrange(selmon);
 }
 
@@ -1388,15 +1563,116 @@ restack(Monitor *m)
 	while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
 }
 
+void
+movestack(const Arg *arg)
+{
+	Client *c = NULL, *p = NULL, *pc = NULL, *i;
+
+	if(arg->i > 0) {
+		/* find the client after selmon->sel */
+		for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+		if(!c)
+			for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+
+	}
+	else {
+		/* find the client before selmon->sel */
+		for(i = selmon->clients; i != selmon->sel; i = i->next)
+			if(ISVISIBLE(i) && !i->isfloating)
+				c = i;
+		if(!c)
+			for(; i; i = i->next)
+				if(ISVISIBLE(i) && !i->isfloating)
+					c = i;
+	}
+	/* find the client before selmon->sel and c */
+	for(i = selmon->clients; i && (!p || !pc); i = i->next) {
+		if(i->next == selmon->sel)
+			p = i;
+		if(i->next == c)
+			pc = i;
+	}
+
+	/* swap c and selmon->sel selmon->clients in the selmon->clients list */
+	if(c && c != selmon->sel) {
+		Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next;
+		selmon->sel->next = c->next==selmon->sel?c:c->next;
+		c->next = temp;
+
+		if(p && p != c)
+			p->next = c;
+		if(pc && pc != selmon->sel)
+			pc->next = selmon->sel;
+
+		if(selmon->sel == selmon->clients)
+			selmon->clients = c;
+		else if(c == selmon->clients)
+			selmon->clients = selmon->sel;
+
+		arrange(selmon);
+	}
+}
+
+void
+rotatestack(const Arg *arg)
+{
+	Client *c = NULL, *f;
+
+	if (!selmon->sel)
+		return;
+	f = selmon->sel;
+	if (arg->i > 0) {
+		for (c = nexttiled(selmon->clients); c && nexttiled(c->next); c = nexttiled(c->next));
+		if (c){
+			detach(c);
+			attach(c);
+			detachstack(c);
+			attachstack(c);
+		}
+	} else {
+		if ((c = nexttiled(selmon->clients))){
+			detach(c);
+			enqueue(c);
+			detachstack(c);
+			enqueuestack(c);
+		}
+	}
+	if (c){
+		arrange(selmon);
+		//unfocus(f, 1);
+		focus(f);
+		restack(selmon);
+	}
+}
+
 void
 run(void)
 {
 	XEvent ev;
+	fd_set rfds;
+	int n;
+	int dpyfd, maxfd;
 	/* main event loop */
 	XSync(dpy, False);
-	while (running && !XNextEvent(dpy, &ev))
-		if (handler[ev.type])
-			handler[ev.type](&ev); /* call handler */
+	dpyfd = ConnectionNumber(dpy);
+	maxfd = fifofd;
+	if (dpyfd > maxfd)
+		maxfd = dpyfd;
+	maxfd++;
+	while (running) {
+		FD_ZERO(&rfds);
+		FD_SET(fifofd, &rfds);
+		FD_SET(dpyfd, &rfds);
+		n = select(maxfd, &rfds, NULL, NULL, NULL);
+		if (n > 0) {
+			if (FD_ISSET(fifofd, &rfds))
+				dispatchcmd();
+			if (FD_ISSET(dpyfd, &rfds))
+				while (XCheckIfEvent(dpy, &ev, evpredicate, NULL))
+					if (handler[ev.type])
+						handler[ev.type](&ev); /* call handler */
+		}
+	}
 }
 
 void
@@ -1520,9 +1796,51 @@ 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);
+	else
+		drawbar(selmon);
+}
+
+void
+togglelayout(const Arg *arg)
+{
+	if (selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] != (Layout *)arg->v)
+		setlayout(arg);
+	else
+		setlayout(0);
+}
+
+void
+rotatelayout(const Arg *arg)
+{
+	int i,
+		idx = -1,
+		max = LENGTH(layouts);
+
+	if (!arg || !arg->i || arg->i == 0)
+		return;
+
+	for (i = 0; i < max && idx == -1; i++) {
+		if (selmon->lt[selmon->sellt] == &layouts[i])
+			idx = i;
+	}
+
+	if (idx == -1)
+		return;
+
+	if (arg->i < 0 && idx-- == 0)
+		idx = max - 1;
+
+	if (arg->i > 0 && idx++ == max - 1)
+		idx = 0;
+
+	selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = &layouts[idx];
+	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);
@@ -1530,6 +1848,7 @@ setlayout(const Arg *arg)
 		drawbar(selmon);
 }
 
+
 /* arg > 1.0 will set mfact absolutely */
 void
 setmfact(const Arg *arg)
@@ -1541,7 +1860,7 @@ setmfact(const Arg *arg)
 	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
 	if (f < 0.1 || f > 0.9)
 		return;
-	selmon->mfact = f;
+	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
 	arrange(selmon);
 }
 
@@ -1687,8 +2006,13 @@ setup(void)
 	XSelectInput(dpy, root, wa.event_mask);
 	grabkeys();
 	focus(NULL);
-}
 
+	/* fifo */
+	mkfifo(dwmfifo, 0600);
+	fifofd = open(dwmfifo, O_RDWR | O_NONBLOCK);
+	if (fifofd < 0)
+		die("Failed to open() DWM fifo %s:", dwmfifo);
+}
 
 void
 seturgent(Client *c, int urg)
@@ -1838,7 +2162,7 @@ nrowgrid(Monitor *m)
 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);
@@ -1862,6 +2186,15 @@ togglefloating(const Arg *arg)
 	arrange(selmon);
 }
 
+void
+togglesticky(const Arg *arg)
+{
+	if (!selmon->sel)
+		return;
+	selmon->sel->issticky = !selmon->sel->issticky;
+	arrange(selmon);
+}
+
 void
 toggletag(const Arg *arg)
 {
@@ -1881,9 +2214,31 @@ void
 toggleview(const Arg *arg)
 {
 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+	int i;
 
 	if (newtagset) {
 		selmon->tagset[selmon->seltags] = newtagset;
+		if (newtagset == ~0) {
+			selmon->pertag->prevtag = selmon->pertag->curtag;
+			selmon->pertag->curtag = 0;
+		}
+
+		/* test if the user did not select the same tag */
+		if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+			selmon->pertag->prevtag = selmon->pertag->curtag;
+			for (i = 0; !(newtagset & 1 << i); i++) ;
+			selmon->pertag->curtag = i + 1;
+		}
+
+		/* apply settings for this view */
+		selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+		selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+		selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+		if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+			togglebar(NULL);
 		focus(NULL);
 		arrange(selmon);
 	}
@@ -2178,11 +2533,36 @@ updatewmhints(Client *c)
 void
 view(const Arg *arg)
 {
+	int i;
+	unsigned int tmptag;
+
 	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
 		return;
 	selmon->seltags ^= 1; /* toggle sel tagset */
-	if (arg->ui & TAGMASK)
+	if (arg->ui & TAGMASK) {
 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+		selmon->pertag->prevtag = selmon->pertag->curtag;
+
+		if (arg->ui == ~0)
+			selmon->pertag->curtag = 0;
+		else {
+			for (i = 0; !(arg->ui & 1 << i); i++) ;
+			selmon->pertag->curtag = i + 1;
+		}
+	} else {
+		tmptag = selmon->pertag->prevtag;
+		selmon->pertag->prevtag = selmon->pertag->curtag;
+		selmon->pertag->curtag = tmptag;
+	}
+
+	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+	selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+	selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+	if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+		togglebar(NULL);
 	focus(NULL);
 	arrange(selmon);
 }