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
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);
}