summaryrefslogtreecommitdiff
path: root/patch
diff options
context:
space:
mode:
Diffstat (limited to 'patch')
-rw-r--r--patch/1627554433214.webmbin0 -> 2950748 bytes
-rw-r--r--patch/aspectresize.c25
-rw-r--r--patch/aspectresize.h2
-rw-r--r--patch/attachx.c43
-rw-r--r--patch/attachx.h2
-rw-r--r--patch/autostart.c84
-rw-r--r--patch/autostart.h2
-rw-r--r--patch/bar_alpha.c43
-rw-r--r--patch/bar_alpha.h4
-rw-r--r--patch/bar_alternativetags.c7
-rw-r--r--patch/bar_alternativetags.h2
-rw-r--r--patch/bar_anybar.c94
-rw-r--r--patch/bar_anybar.h5
-rw-r--r--patch/bar_awesomebar.c90
-rw-r--r--patch/bar_awesomebar.h4
-rw-r--r--patch/bar_dwmblocks.c51
-rw-r--r--patch/bar_dwmblocks.h3
-rw-r--r--patch/bar_ewmhtags.c53
-rw-r--r--patch/bar_ewmhtags.h7
-rw-r--r--patch/bar_fancybar.c88
-rw-r--r--patch/bar_fancybar.h4
-rw-r--r--patch/bar_flexwintitle.c446
-rw-r--r--patch/bar_flexwintitle.h11
-rw-r--r--patch/bar_holdbar.c38
-rw-r--r--patch/bar_holdbar.h3
-rw-r--r--patch/bar_indicators.c111
-rw-r--r--patch/bar_indicators.h21
-rw-r--r--patch/bar_layoutmenu.c18
-rw-r--r--patch/bar_layoutmenu.h2
-rw-r--r--patch/bar_ltsymbol.c18
-rw-r--r--patch/bar_ltsymbol.h4
-rw-r--r--patch/bar_powerline_status.c122
-rw-r--r--patch/bar_powerline_status.h12
-rw-r--r--patch/bar_powerline_tags.c107
-rw-r--r--patch/bar_powerline_tags.h4
-rw-r--r--patch/bar_status.c34
-rw-r--r--patch/bar_status.h10
-rw-r--r--patch/bar_status2d.c268
-rw-r--r--patch/bar_status2d.h14
-rw-r--r--patch/bar_statusbutton.c18
-rw-r--r--patch/bar_statusbutton.h4
-rw-r--r--patch/bar_statuscmd.c75
-rw-r--r--patch/bar_statuscmd.h12
-rw-r--r--patch/bar_statuscolors.c24
-rw-r--r--patch/bar_systray.c198
-rw-r--r--patch/bar_systray.h42
-rw-r--r--patch/bar_tabgroups.c231
-rw-r--r--patch/bar_tabgroups.h8
-rw-r--r--patch/bar_taggrid.c150
-rw-r--r--patch/bar_taggrid.h5
-rw-r--r--patch/bar_tagicons.c21
-rw-r--r--patch/bar_tagicons.h8
-rw-r--r--patch/bar_tags.c89
-rw-r--r--patch/bar_tags.h4
-rw-r--r--patch/bar_vtcolors.c69
-rw-r--r--patch/bar_vtcolors.h3
-rw-r--r--patch/bar_winicon.c146
-rw-r--r--patch/bar_winicon.h8
-rw-r--r--patch/bar_wintitle.c59
-rw-r--r--patch/bar_wintitle.h4
-rw-r--r--patch/bar_wintitle_floating.c46
-rw-r--r--patch/bar_wintitle_floating.h9
-rw-r--r--patch/bar_wintitle_hidden.c46
-rw-r--r--patch/bar_wintitle_hidden.h9
-rw-r--r--patch/bar_wintitleactions.c94
-rw-r--r--patch/bar_wintitleactions.h6
-rw-r--r--patch/cfacts.c24
-rw-r--r--patch/cfacts.h2
-rw-r--r--patch/cmdcustomize.c6
-rw-r--r--patch/cmdcustomize.h2
-rw-r--r--patch/combo.c50
-rw-r--r--patch/combo.h6
-rw-r--r--patch/cool_autostart.c29
-rw-r--r--patch/cool_autostart.h2
-rw-r--r--patch/cyclelayouts.c18
-rw-r--r--patch/cyclelayouts.h2
-rw-r--r--patch/decorationhints.c39
-rw-r--r--patch/decorationhints.h9
-rw-r--r--patch/distributetags.c17
-rw-r--r--patch/distributetags.h2
-rw-r--r--patch/dragcfact.c83
-rw-r--r--patch/dragcfact.h2
-rw-r--r--patch/dragmfact.c232
-rw-r--r--patch/dragmfact.h2
-rwxr-xr-xpatch/dwmc130
-rw-r--r--patch/dwmc.c101
-rw-r--r--patch/dwmc.h14
-rw-r--r--patch/exresize.c196
-rw-r--r--patch/exresize.h9
-rw-r--r--patch/fakefullscreenclient.c19
-rw-r--r--patch/fakefullscreenclient.h2
-rw-r--r--patch/floatpos.c195
-rw-r--r--patch/floatpos.h4
-rw-r--r--patch/focusadjacenttag.c102
-rw-r--r--patch/focusadjacenttag.h7
-rw-r--r--patch/focusdir.c66
-rw-r--r--patch/focusdir.h2
-rw-r--r--patch/focusmaster.c14
-rw-r--r--patch/focusmaster.h2
-rw-r--r--patch/focusurgent.c16
-rw-r--r--patch/focusurgent.h2
-rw-r--r--patch/fsignal.c41
-rw-r--r--patch/fsignal.h8
-rw-r--r--patch/fullscreen.c18
-rw-r--r--patch/fullscreen.h2
-rw-r--r--patch/include.c359
-rw-r--r--patch/include.h349
-rw-r--r--patch/inplacerotate.c84
-rw-r--r--patch/inplacerotate.h2
-rw-r--r--patch/insets.c19
-rw-r--r--patch/insets.h3
-rw-r--r--patch/ipc.c111
-rw-r--r--patch/ipc.h7
-rw-r--r--patch/ipc/IPCClient.c67
-rw-r--r--patch/ipc/IPCClient.h62
-rw-r--r--patch/ipc/dwm-msg.c549
-rw-r--r--patch/ipc/ipc.c1202
-rw-r--r--patch/ipc/ipc.h320
-rw-r--r--patch/ipc/util.c136
-rw-r--r--patch/ipc/util.h5
-rw-r--r--patch/ipc/yajl_dumps.c356
-rw-r--r--patch/ipc/yajl_dumps.h66
-rw-r--r--patch/keymodes.c144
-rw-r--r--patch/keymodes.h22
-rw-r--r--patch/killunsel.c28
-rw-r--r--patch/killunsel.h2
-rw-r--r--patch/layout_bstack.c75
-rw-r--r--patch/layout_bstack.h2
-rw-r--r--patch/layout_bstackhoriz.c77
-rw-r--r--patch/layout_bstackhoriz.h2
-rw-r--r--patch/layout_centeredfloatingmaster.c95
-rw-r--r--patch/layout_centeredfloatingmaster.h2
-rw-r--r--patch/layout_centeredmaster.c160
-rw-r--r--patch/layout_centeredmaster.h2
-rw-r--r--patch/layout_columns.c74
-rw-r--r--patch/layout_columns.h2
-rw-r--r--patch/layout_deck.c67
-rw-r--r--patch/layout_deck.h2
-rw-r--r--patch/layout_facts.c52
-rw-r--r--patch/layout_fibonacci.c191
-rw-r--r--patch/layout_fibonacci.h8
-rw-r--r--patch/layout_flextile-deluxe.c891
-rw-r--r--patch/layout_flextile-deluxe.h121
-rw-r--r--patch/layout_gapplessgrid.c99
-rw-r--r--patch/layout_gapplessgrid.h2
-rw-r--r--patch/layout_grid.c61
-rw-r--r--patch/layout_grid.h2
-rw-r--r--patch/layout_horizgrid.c104
-rw-r--r--patch/layout_horizgrid.h2
-rw-r--r--patch/layout_monocle.c38
-rw-r--r--patch/layout_monocle.h2
-rw-r--r--patch/layout_nrowgrid.c104
-rw-r--r--patch/layout_nrowgrid.h2
-rw-r--r--patch/layout_tile.c74
-rw-r--r--patch/layout_tile.h2
-rwxr-xr-xpatch/layoutmenu.sh8
-rw-r--r--patch/maximize.c70
-rw-r--r--patch/maximize.h5
-rw-r--r--patch/moveplace.c30
-rw-r--r--patch/moveplace.h4
-rw-r--r--patch/moveresize.c65
-rw-r--r--patch/moveresize.h2
-rw-r--r--patch/movestack.c51
-rw-r--r--patch/movestack.h2
-rw-r--r--patch/mpdcontrol.c145
-rw-r--r--patch/mpdcontrol.h3
-rw-r--r--patch/nomodbuttons.c8
-rw-r--r--patch/nomodbuttons.h2
-rw-r--r--patch/pertag.c78
-rw-r--r--patch/pertag.h2
-rw-r--r--patch/placemouse.c153
-rw-r--r--patch/placemouse.h7
-rw-r--r--patch/push.c72
-rw-r--r--patch/push.h5
-rw-r--r--patch/push_no_master.c44
-rw-r--r--patch/push_no_master.h4
-rw-r--r--patch/reorganizetags.c28
-rw-r--r--patch/reorganizetags.h2
-rw-r--r--patch/restartsig.c16
-rw-r--r--patch/restartsig.h3
-rw-r--r--patch/riodraw.c104
-rw-r--r--patch/riodraw.h6
-rw-r--r--patch/rotatestack.c53
-rw-r--r--patch/rotatestack.h4
-rw-r--r--patch/roundedcorners.c51
-rw-r--r--patch/roundedcorners.h2
-rw-r--r--patch/scratchpad.c77
-rw-r--r--patch/scratchpad.h9
-rw-r--r--patch/scratchpad_alt_1.c72
-rw-r--r--patch/scratchpad_alt_1.h9
-rw-r--r--patch/selfrestart.c69
-rw-r--r--patch/selfrestart.h3
-rw-r--r--patch/setborderpx.c45
-rw-r--r--patch/setborderpx.h2
-rw-r--r--patch/shiftview.c19
-rw-r--r--patch/shiftview.h2
-rw-r--r--patch/shiftviewclients.c43
-rw-r--r--patch/shiftviewclients.h2
-rw-r--r--patch/sizehints_ruled.c25
-rw-r--r--patch/sizehints_ruled.h2
-rw-r--r--patch/sortscreens.c16
-rw-r--r--patch/sortscreens.h4
-rw-r--r--patch/stacker.c113
-rw-r--r--patch/stacker.h11
-rw-r--r--patch/sticky.c9
-rw-r--r--patch/sticky.h2
-rw-r--r--patch/swallow.c206
-rw-r--r--patch/swallow.h8
-rw-r--r--patch/swapfocus.c22
-rw-r--r--patch/swapfocus.h2
-rw-r--r--patch/swaptags.c23
-rw-r--r--patch/swaptags.h2
-rw-r--r--patch/switchcol.c29
-rw-r--r--patch/switchcol.h2
-rw-r--r--patch/tab.c133
-rw-r--r--patch/tab.h5
-rw-r--r--patch/tagall.c26
-rw-r--r--patch/tagall.h2
-rw-r--r--patch/tagallmon.c49
-rw-r--r--patch/tagallmon.h2
-rw-r--r--patch/tagothermonitor.c44
-rw-r--r--patch/tagothermonitor.h9
-rw-r--r--patch/tagswapmon.c75
-rw-r--r--patch/tagswapmon.h2
-rw-r--r--patch/tapresize.c39
-rw-r--r--patch/tapresize.h2
-rw-r--r--patch/togglefullscreen.c18
-rw-r--r--patch/togglefullscreen.h2
-rw-r--r--patch/transfer.c34
-rw-r--r--patch/transfer.h2
-rw-r--r--patch/transferall.c26
-rw-r--r--patch/transferall.h2
-rw-r--r--patch/unfloatvisible.c15
-rw-r--r--patch/unfloatvisible.h2
-rw-r--r--patch/vanitygaps.c199
-rw-r--r--patch/vanitygaps.h20
-rw-r--r--patch/warp.c38
-rw-r--r--patch/warp.h2
-rw-r--r--patch/winview.c21
-rw-r--r--patch/winview.h2
-rw-r--r--patch/xkb.c68
-rw-r--r--patch/xkb.h8
-rw-r--r--patch/xrdb.c128
-rw-r--r--patch/xrdb.h22
-rw-r--r--patch/zoomswap.c14
-rw-r--r--patch/zoomswap.h2
246 files changed, 13799 insertions, 0 deletions
diff --git a/patch/1627554433214.webm b/patch/1627554433214.webm
new file mode 100644
index 0000000..8c4a62d
--- /dev/null
+++ b/patch/1627554433214.webm
Binary files differ
diff --git a/patch/aspectresize.c b/patch/aspectresize.c
new file mode 100644
index 0000000..cdd5afd
--- /dev/null
+++ b/patch/aspectresize.c
@@ -0,0 +1,25 @@
+void
+aspectresize(const Arg *arg)
+{
+ /* only floating windows can be moved */
+ Client *c;
+ c = selmon->sel;
+ float ratio;
+ int w, h,nw, nh;
+
+ if (!c || !arg)
+ return;
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+ return;
+
+ ratio = (float)c->w / (float)c->h;
+ h = arg->i;
+ w = (int)(ratio * h);
+
+ nw = c->w + w;
+ nh = c->h + h;
+
+ XRaiseWindow(dpy, c->win);
+ resize(c, c->x, c->y, nw, nh, True);
+}
+
diff --git a/patch/aspectresize.h b/patch/aspectresize.h
new file mode 100644
index 0000000..4ac7cbb
--- /dev/null
+++ b/patch/aspectresize.h
@@ -0,0 +1,2 @@
+static void aspectresize(const Arg *arg);
+
diff --git a/patch/attachx.c b/patch/attachx.c
new file mode 100644
index 0000000..9e06b94
--- /dev/null
+++ b/patch/attachx.c
@@ -0,0 +1,43 @@
+void
+attachx(Client *c)
+{
+ #if ATTACHABOVE_PATCH
+ Client *at;
+ if (!(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating)) {
+ for (at = c->mon->clients; at->next != c->mon->sel; at = at->next);
+ c->next = at->next;
+ at->next = c;
+ return;
+ }
+ #elif ATTACHASIDE_PATCH
+ Client *at;
+ unsigned int n;
+
+ for (at = c->mon->clients, n = 0; at; at = at->next)
+ if (!at->isfloating && ISVISIBLEONTAG(at, c->tags))
+ if (++n >= c->mon->nmaster)
+ break;
+
+ if (at && c->mon->nmaster) {
+ c->next = at->next;
+ at->next = c;
+ return;
+ }
+ #elif ATTACHBELOW_PATCH
+ if (!(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating)) {
+ c->next = c->mon->sel->next;
+ c->mon->sel->next = c;
+ return;
+ }
+ #elif ATTACHBOTTOM_PATCH
+ Client *at;
+ for (at = c->mon->clients; at && at->next; at = at->next);
+ if (at) {
+ at->next = c;
+ c->next = NULL;
+ return;
+ }
+ #endif
+ 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/autostart.c b/patch/autostart.c
new file mode 100644
index 0000000..03477bb
--- /dev/null
+++ b/patch/autostart.c
@@ -0,0 +1,84 @@
+void
+runautostart(void)
+{
+ char *pathpfx;
+ char *path;
+ char *xdgdatahome;
+ char *home;
+
+ if ((home = getenv("HOME")) == NULL)
+ /* this is almost impossible */
+ return;
+
+ /* if $XDG_DATA_HOME is defined, use $XDG_DATA_HOME/dwm,
+ * otherwise use ~/.local/share/dwm as autostart script directory
+ */
+ if ((xdgdatahome = getenv("XDG_DATA_HOME")) != NULL) {
+ /* space for path segments, separators and nul */
+ if ((pathpfx = malloc(strlen(xdgdatahome) + strlen(dwmdir) + 2)) == NULL)
+ return;
+
+ if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) {
+ free(pathpfx);
+ return;
+ }
+ } else {
+ /* space for path segments, separators and nul */
+ if ((pathpfx = malloc(strlen(home) + strlen(localshare) + strlen(dwmdir) + 3)) == NULL)
+ return;
+
+ if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) {
+ free(pathpfx);
+ return;
+ }
+ }
+
+ /* check if the autostart script directory exists */
+ struct stat sb;
+
+ if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ /* the XDG conformant path does not exist or are not directories
+ * so we try ~/.dwm instead
+ */
+ if (realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3) == NULL) {
+ free(pathpfx);
+ return;
+ }
+
+ if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) {
+ free(pathpfx);
+ return;
+ }
+ }
+
+ /* try the blocking script first */
+ if ((path = malloc(strlen(pathpfx) + strlen(autostartblocksh) + 2)) == NULL) {
+ free(pathpfx);
+ return;
+ } else
+ if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) {
+ free(path);
+ free(pathpfx);
+ }
+
+ if (access(path, X_OK) == 0)
+ system(path);
+
+ /* now the non-blocking script */
+ if ((path = realloc(path, strlen(pathpfx) + strlen(autostartsh) + 4)) == NULL) {
+ free(pathpfx);
+ free(path);
+ return;
+ } else
+ if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) {
+ free(path);
+ free(pathpfx);
+ }
+
+ if (access(path, X_OK) == 0) {
+ system(strcat(path, " &"));
+ free(pathpfx);
+ free(path);
+ }
+}
+
diff --git a/patch/autostart.h b/patch/autostart.h
new file mode 100644
index 0000000..db29377
--- /dev/null
+++ b/patch/autostart.h
@@ -0,0 +1,2 @@
+static void runautostart(void);
+
diff --git a/patch/bar_alpha.c b/patch/bar_alpha.c
new file mode 100644
index 0000000..465f6f2
--- /dev/null
+++ b/patch/bar_alpha.c
@@ -0,0 +1,43 @@
+
+static int useargb = 0;
+static Visual *visual;
+static int depth;
+static Colormap cmap;
+
+void
+xinitvisual()
+{
+ XVisualInfo *infos;
+ XRenderPictFormat *fmt;
+ int nitems;
+ int i;
+
+ XVisualInfo tpl = {
+ .screen = screen,
+ .depth = 32,
+ .class = TrueColor
+ };
+ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
+
+ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
+ visual = NULL;
+ for (i = 0; i < nitems; i ++) {
+ fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
+ visual = infos[i].visual;
+ depth = infos[i].depth;
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
+ useargb = 1;
+ break;
+ }
+ }
+
+ XFree(infos);
+
+ if (!visual) {
+ visual = DefaultVisual(dpy, screen);
+ depth = DefaultDepth(dpy, screen);
+ cmap = DefaultColormap(dpy, screen);
+ }
+}
+
diff --git a/patch/bar_alpha.h b/patch/bar_alpha.h
new file mode 100644
index 0000000..1c2a012
--- /dev/null
+++ b/patch/bar_alpha.h
@@ -0,0 +1,4 @@
+#define OPAQUE 0xffU
+
+static void xinitvisual();
+
diff --git a/patch/bar_alternativetags.c b/patch/bar_alternativetags.c
new file mode 100644
index 0000000..bc800f2
--- /dev/null
+++ b/patch/bar_alternativetags.c
@@ -0,0 +1,7 @@
+void
+togglealttag()
+{
+ selmon->alttag = !selmon->alttag;
+ drawbar(selmon);
+}
+
diff --git a/patch/bar_alternativetags.h b/patch/bar_alternativetags.h
new file mode 100644
index 0000000..0f7a25a
--- /dev/null
+++ b/patch/bar_alternativetags.h
@@ -0,0 +1,2 @@
+static void togglealttag();
+
diff --git a/patch/bar_anybar.c b/patch/bar_anybar.c
new file mode 100644
index 0000000..d9bdb27
--- /dev/null
+++ b/patch/bar_anybar.c
@@ -0,0 +1,94 @@
+void
+managealtbar(Window win, XWindowAttributes *wa)
+{
+ Monitor *m;
+ Bar *bar;
+ int i = 0;
+ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
+ return;
+ for (bar = m->bar; bar && bar->win && bar->next; bar = bar->next); // find last bar
+ if (!bar) {
+ bar = m->bar = ecalloc(1, sizeof(Bar));
+ bar->topbar = topbar;
+ } else if (bar && bar->win) {
+ i = bar->idx + 1;
+ bar->next = ecalloc(1, sizeof(Bar));
+ #if BAR_ANYBAR_TOP_AND_BOTTOM_BARS_PATCH
+ bar->next->topbar = !bar->topbar;
+ #else
+ bar->next->topbar = topbar;
+ #endif // BAR_ANYBAR_TOP_AND_BOTTOM_BARS_PATCH
+ bar = bar->next;
+ }
+ bar->external = 1;
+ bar->showbar = 1;
+ bar->mon = m;
+ bar->idx = i;
+ bar->borderpx = 0;
+ bar->win = win;
+ bar->bw = wa->width;
+ bar->bh = wa->height;
+ updatebarpos(m);
+ arrange(m);
+ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ XMapWindow(dpy, win);
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+ arrange(selmon);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &win, 1);
+}
+
+void
+spawnbar()
+{
+ if (*altbarcmd)
+ system(altbarcmd);
+}
+
+void
+unmanagealtbar(Window w)
+{
+ Monitor *m = wintomon(w);
+ Bar *bar, *next, *prev = NULL;
+
+ if (!m)
+ return;
+
+ for (bar = m->bar; bar && bar->win; bar = next) {
+ next = bar->next;
+ if (bar->win == w) {
+ if (prev)
+ prev->next = next;
+ else
+ m->bar = next;
+ free(bar);
+ break;
+ }
+ prev = bar;
+ }
+ updatebarpos(m);
+ arrange(m);
+}
+
+int
+wmclasscontains(Window win, const char *class, const char *name)
+{
+ XClassHint ch = { NULL, NULL };
+ int res = 1;
+
+ if (XGetClassHint(dpy, win, &ch)) {
+ if (ch.res_name && strstr(ch.res_name, name) == NULL)
+ res = 0;
+ if (ch.res_class && strstr(ch.res_class, class) == NULL)
+ res = 0;
+ } else
+ res = 0;
+
+ if (ch.res_class)
+ XFree(ch.res_class);
+ if (ch.res_name)
+ XFree(ch.res_name);
+
+ return res;
+}
+
diff --git a/patch/bar_anybar.h b/patch/bar_anybar.h
new file mode 100644
index 0000000..980f5e2
--- /dev/null
+++ b/patch/bar_anybar.h
@@ -0,0 +1,5 @@
+static void managealtbar(Window win, XWindowAttributes *wa);
+static void spawnbar();
+static void unmanagealtbar(Window w);
+static int wmclasscontains(Window win, const char *class, const char *name);
+
diff --git a/patch/bar_awesomebar.c b/patch/bar_awesomebar.c
new file mode 100644
index 0000000..b02c6e7
--- /dev/null
+++ b/patch/bar_awesomebar.c
@@ -0,0 +1,90 @@
+int
+width_awesomebar(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_awesomebar(Bar *bar, BarArg *a)
+{
+ int n = 0, scm, remainder = 0, tabw, pad;
+ unsigned int i;
+ #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad;
+ #elif BAR_TITLE_LEFT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad / 2;
+ #elif BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x, w = a->w - lrpad / 2;
+ #else
+ int x = a->x, w = a->w;
+ #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH
+
+ Client *c;
+ for (c = bar->mon->clients; c; c = c->next)
+ if (ISVISIBLE(c))
+ n++;
+
+ if (n > 0) {
+ remainder = w % n;
+ tabw = w / n;
+ for (i = 0, c = bar->mon->clients; c; c = c->next, i++) {
+ if (!ISVISIBLE(c))
+ continue;
+ if (bar->mon->sel == c && HIDDEN(c))
+ scm = SchemeHidSel;
+ else if (HIDDEN(c))
+ scm = SchemeHidNorm;
+ else if (bar->mon->sel == c)
+ scm = SchemeTitleSel;
+ else
+ scm = SchemeTitleNorm;
+
+ pad = lrpad / 2;
+ #if BAR_CENTEREDWINDOWNAME_PATCH
+ if (TEXTW(c->name) < tabw)
+ pad = (tabw - TEXTW(c->name) + lrpad) / 2;
+ #endif // BAR_CENTEREDWINDOWNAME_PATCH
+
+ drw_setscheme(drw, scheme[scm]);
+
+ #if BAR_WINICON_PATCH
+ drw_text(drw, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False);
+ if (c->icon)
+ drw_img(drw, x + pad, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon);
+ #else
+ drw_text(drw, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, pad, c->name, 0, False);
+ #endif // BAR_WINICON_PATCH
+
+ drawstateindicator(c->mon, c, 1, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, 0, 0, c->isfixed);
+ x += tabw + (i < remainder ? 1 : 0);
+ }
+ }
+ return n;
+}
+
+int
+click_awesomebar(Bar *bar, Arg *arg, BarArg *a)
+{
+ int x = 0, n = 0;
+ Client *c;
+
+ for (c = bar->mon->clients; c; c = c->next)
+ if (ISVISIBLE(c))
+ n++;
+
+ c = bar->mon->clients;
+
+ do {
+ if (!c || !ISVISIBLE(c))
+ continue;
+ else
+ x += (1.0 / (double)n) * a->w;
+ } while (c && a->x > x && (c = c->next));
+
+ if (c) {
+ arg->v = c;
+ return ClkWinTitle;
+ }
+ return -1;
+}
+
diff --git a/patch/bar_awesomebar.h b/patch/bar_awesomebar.h
new file mode 100644
index 0000000..5ea51f6
--- /dev/null
+++ b/patch/bar_awesomebar.h
@@ -0,0 +1,4 @@
+static int width_awesomebar(Bar *bar, BarArg *a);
+static int draw_awesomebar(Bar *bar, BarArg *a);
+static int click_awesomebar(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_dwmblocks.c b/patch/bar_dwmblocks.c
new file mode 100644
index 0000000..25268c5
--- /dev/null
+++ b/patch/bar_dwmblocks.c
@@ -0,0 +1,51 @@
+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("pidof -s "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;
+
+ #if BAR_DWMBLOCKS_SIGUSR1_PATCH
+ sv.sival_int = (statussig << 8) | arg->i;
+ if (sigqueue(statuspid, SIGUSR1, sv) == -1) {
+ if (errno == ESRCH) {
+ if (!getstatusbarpid())
+ sigqueue(statuspid, SIGUSR1, sv);
+ }
+ }
+ #else
+ sv.sival_int = arg->i;
+ sigqueue(statuspid, SIGRTMIN+statussig, sv);
+ #endif // BAR_DWMBLOCKS_SIGUSR1_PATCH
+}
+
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..d86fd88
--- /dev/null
+++ b/patch/bar_ewmhtags.c
@@ -0,0 +1,53 @@
+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_fancybar.c b/patch/bar_fancybar.c
new file mode 100644
index 0000000..10bac83
--- /dev/null
+++ b/patch/bar_fancybar.c
@@ -0,0 +1,88 @@
+int
+width_fancybar(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_fancybar(Bar *bar, BarArg *a)
+{
+ int ftw, mw, ew = 0, n = 0;
+ unsigned int i;
+ Client *c;
+ Monitor *m = bar->mon;
+
+ #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad;
+ #elif BAR_TITLE_LEFT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad / 2;
+ #elif BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x, w = a->w - lrpad / 2;
+ #else
+ int x = a->x, w = a->w;
+ #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH
+
+ for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c))
+ n++;
+ }
+
+ if (n > 0) {
+ ftw = TEXTW(m->sel->name);
+ #if BAR_WINICON_PATCH
+ if (m->sel->icon)
+ ftw += m->sel->icon->width + ICONSPACING;
+ #endif // BAR_WINICON_PATCH
+ mw = (ftw >= w || n == 1) ? 0 : (w - ftw) / (n - 1);
+
+ i = 0;
+
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || c == m->sel)
+ continue;
+ ftw = TEXTW(c->name);
+ #if BAR_WINICON_PATCH
+ if (c->icon)
+ ftw += c->icon->width + ICONSPACING;
+ #endif // BAR_WINICON_PATCH
+ if (ftw < mw)
+ ew += (mw - ftw);
+ else
+ i++;
+ }
+
+ if (i > 0)
+ mw += ew / i;
+
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ ftw = MIN(m->sel == c ? w : mw, TEXTW(c->name));
+ drw_setscheme(drw, scheme[m->sel == c ? SchemeTitleSel : SchemeTitleNorm]);
+ if (ftw > 0) { /* trap special handling of 0 in drw_text */
+
+ drw_text(drw, x, a->y, ftw, a->h, lrpad / 2, c->name, 0, False);
+
+ #if BAR_WINICON_PATCH
+ drw_text(drw, x, a->y, ftw, a->h, lrpad / 2 + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False);
+ if (c->icon)
+ drw_img(drw, x + lrpad / 2, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon);
+ #else
+ drw_text(drw, x, a->y, ftw, a->h, lrpad / 2, c->name, 0, False);
+ #endif // BAR_WINICON_PATCH
+
+ }
+ drawstateindicator(c->mon, c, 1, x, a->y, ftw, a->h, 0, 0, c->isfixed);
+ x += ftw;
+ w -= ftw;
+ }
+ }
+ return n;
+}
+
+int
+click_fancybar(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkWinTitle;
+}
+
diff --git a/patch/bar_fancybar.h b/patch/bar_fancybar.h
new file mode 100644
index 0000000..473cca3
--- /dev/null
+++ b/patch/bar_fancybar.h
@@ -0,0 +1,4 @@
+static int width_fancybar(Bar *bar, BarArg *a);
+static int draw_fancybar(Bar *bar, BarArg *a);
+static int click_fancybar(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_flexwintitle.c b/patch/bar_flexwintitle.c
new file mode 100644
index 0000000..2f59240
--- /dev/null
+++ b/patch/bar_flexwintitle.c
@@ -0,0 +1,446 @@
+/* Flexwintitle properties, you can override these in your config.h if you want. */
+#ifndef FLEXWINTITLE_BORDERS
+#define FLEXWINTITLE_BORDERS 1 // 0 = off, 1 = on
+#endif
+#ifndef FLEXWINTITLE_SHOWFLOATING
+#define FLEXWINTITLE_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown
+#endif
+#ifndef FLEXWINTITLE_MASTERWEIGHT
+#define FLEXWINTITLE_MASTERWEIGHT 9 // master weight compared to stack, hidden and floating window titles
+#endif
+#ifndef FLEXWINTITLE_STACKWEIGHT
+#define FLEXWINTITLE_STACKWEIGHT 3 // stack weight compared to master, hidden and floating window titles
+#endif
+#ifndef FLEXWINTITLE_HIDDENWEIGHT
+#define FLEXWINTITLE_HIDDENWEIGHT 0 // hidden window title weight
+#endif
+#ifndef FLEXWINTITLE_FLOATWEIGHT
+#define FLEXWINTITLE_FLOATWEIGHT 0 // floating window title weight, set to 0 to not show floating windows
+#endif
+
+#define SCHEMEFOR(c) getschemefor(m, c, groupactive == c)
+
+enum { GRP_NOSELECTION, GRP_MASTER, GRP_STACK1, GRP_STACK2, GRP_FLOAT, GRP_HIDDEN };
+
+int
+width_flexwintitle(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_flexwintitle(Bar *bar, BarArg *a)
+{
+ drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1);
+ return flextitlecalculate(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a);
+}
+
+int
+click_flexwintitle(Bar *bar, Arg *arg, BarArg *a)
+{
+ flextitlecalculate(bar->mon, 0, a->w, a->x, flextitleclick, arg, a);
+ return ClkWinTitle;
+}
+
+Client *
+flextitledrawarea(Monitor *m, Client *c, int x, int r, int w, int max_clients, int scheme, int draw_tiled, int draw_hidden, int draw_floating,
+ int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg)
+{
+ int i;
+ for (i = 0; c && i < max_clients; c = c->next) {
+ if (
+ ISVISIBLE(c) &&
+ (
+ (draw_tiled && !c->isfloating && !HIDDEN(c)) ||
+ (draw_floating && c->isfloating && !HIDDEN(c)) ||
+ (draw_hidden && HIDDEN(c))
+ )
+ ) {
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), scheme, arg, barg);
+ x += w + (i < r ? 1 : 0);
+ i++;
+ }
+ }
+ return c;
+}
+
+int
+getschemefor(Monitor *m, int group, int activegroup)
+{
+ switch (group) {
+ case GRP_NOSELECTION:
+ case GRP_MASTER:
+ case GRP_STACK1:
+ case GRP_STACK2:
+ #if BSTACK_LAYOUT
+ if (m->lt[m->sellt]->arrange == &bstack)
+ return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR);
+ #endif // BSTACK_LAYOUT
+ #if BSTACKHORIZ_LAYOUT
+ if (m->lt[m->sellt]->arrange == &bstackhoriz) {
+ if (group == GRP_MASTER)
+ return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR);
+ else
+ return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB);
+ }
+ #endif // BSTACKHORIZ_LAYOUT
+ #if CENTEREDMASTER_LAYOUT
+ if (m->lt[m->sellt]->arrange == &centeredmaster)
+ return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB);
+ #endif // CENTEREDMASTER_LAYOUT
+ #if CENTEREDFLOATINGMASTER_LAYOUT
+ if (m->lt[m->sellt]->arrange == &centeredfloatingmaster)
+ return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR);
+ #endif // CENTEREDFLOATINGMASTER_LAYOUT
+ #if COLUMNS_LAYOUT
+ if (m->lt[m->sellt]->arrange == &col) {
+ if (group == GRP_MASTER)
+ return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR);
+ else
+ return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB);
+ }
+ #endif // COLUMNS_LAYOUT
+ #if DECK_LAYOUT
+ if (m->lt[m->sellt]->arrange == &deck) {
+ if (group == GRP_MASTER)
+ return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB);
+ else
+ return (activegroup ? SchemeFlexActMONO : SchemeFlexInaMONO);
+ }
+ #endif // DECK_LAYOUT
+ #if FIBONACCI_DWINDLE_LAYOUT
+ if (m->lt[m->sellt]->arrange == &dwindle)
+ return (activegroup ? SchemeFlexActDWDL : SchemeFlexInaDWDL);
+ #endif // FIBONACCI_DWINDLE_LAYOUT
+ #if FIBONACCI_SPIRAL_LAYOUT
+ if (m->lt[m->sellt]->arrange == &spiral)
+ return (activegroup ? SchemeFlexActSPRL : SchemeFlexInaSPRL);
+ #endif // FIBONACCI_SPIRAL_LAYOUT
+ #if FLEXTILE_DELUXE_LAYOUT
+ if (m->lt[m->sellt]->arrange == &flextile)
+ return (activegroup ? SchemeFlexActTTB + m->ltaxis[group] : SchemeFlexInaTTB + m->ltaxis[group]);
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ #if GAPPLESSGRID_LAYOUT
+ if (m->lt[m->sellt]->arrange == &gaplessgrid)
+ return (activegroup ? SchemeFlexActGRID : SchemeFlexInaGRID);
+ #endif // GAPPLESSGRID_LAYOUT
+ #if GRIDMODE_LAYOUT
+ if (m->lt[m->sellt]->arrange == &grid)
+ return (activegroup ? SchemeFlexActGRDM : SchemeFlexInaGRDM);
+ #endif // GRIDMODE_LAYOUT
+ #if HORIZGRID_LAYOUT
+ if (m->lt[m->sellt]->arrange == &horizgrid)
+ return (activegroup ? SchemeFlexActHGRD : SchemeFlexInaHGRD);
+ #endif // HORIZGRID_LAYOUT
+ #if NROWGRID_LAYOUT
+ if (m->lt[m->sellt]->arrange == &nrowgrid)
+ return (activegroup ? SchemeFlexActGRD1 : SchemeFlexInaGRD1);
+ #endif // NROWGRID_LAYOUT
+ #if TILE_LAYOUT
+ if (m->lt[m->sellt]->arrange == &tile)
+ return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB);
+ #endif // TILE_LAYOUT
+ #if MONOCLE_LAYOUT
+ if (m->lt[m->sellt]->arrange == &monocle)
+ return (activegroup ? SchemeFlexActMONO : SchemeFlexInaMONO);
+ #endif // MONOCLE_LAYOUT
+ return SchemeTitleNorm;
+ case GRP_HIDDEN:
+ return SchemeHidNorm;
+ case GRP_FLOAT:
+ return (activegroup ? SchemeFlexActFloat : SchemeFlexInaFloat);
+ }
+ return SchemeTitleNorm;
+}
+
+int
+getselschemefor(int scheme)
+{
+ if (scheme == SchemeFlexActFloat || scheme == SchemeFlexInaFloat)
+ return SchemeFlexSelFloat;
+ if (scheme >= SchemeFlexInaTTB)
+ return scheme + SchemeFlexInaTTB - SchemeFlexActTTB;
+ if (scheme >= SchemeFlexActTTB)
+ return scheme + SchemeFlexSelTTB - SchemeFlexActTTB;
+ return SchemeTitleSel;
+}
+
+void
+flextitledraw(Monitor *m, Client *c, int unused, int x, int w, int tabscheme, Arg *arg, BarArg *barg)
+{
+ if (!c)
+ return;
+ int i, nclienttags = 0, nviewtags = 0, pad = lrpad / 2;
+ int clientscheme = (
+ c == selmon->sel && HIDDEN(c)
+ ? SchemeHidSel
+ : HIDDEN(c)
+ ? SchemeHidNorm
+ : c == selmon->sel
+ ? getselschemefor(tabscheme)
+ : c->isurgent
+ ? SchemeUrg
+ : tabscheme
+ );
+ drw_setscheme(drw, scheme[clientscheme]);
+ XSetWindowBorder(dpy, c->win, scheme[clientscheme][ColBorder].pixel);
+ if (w <= TEXTW("A") - lrpad + pad) // reduce text padding if wintitle is too small
+ pad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2);
+ #if BAR_CENTEREDWINDOWNAME_PATCH
+ else if (TEXTW(c->name) < w)
+ pad = (w - TEXTW(c->name) + lrpad) / 2;
+ #endif // BAR_CENTEREDWINDOWNAME_PATCH
+
+ #if BAR_WINICON_PATCH
+ drw_text(drw, x, barg->y, w, barg->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False);
+ if (c->icon)
+ drw_img(drw, x + pad, barg->y + (barg->h - c->icon->height) / 2, c->icon, tmpicon);
+ #else
+ drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False);
+ #endif // BAR_WINICON_PATCH
+
+ drawstateindicator(m, c, 1, x + 2, barg->y, w, barg->h, 0, 0, 0);
+
+ if (FLEXWINTITLE_BORDERS) {
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, barg->y, 3, barg->h);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w - (x + w >= barg->w ? 1 : 0), barg->y, 3, barg->h);
+ }
+ /* Optional tags icons */
+ for (i = 0; i < NUMTAGS; i++) {
+ if ((m->tagset[m->seltags] >> i) & 1)
+ nviewtags++;
+ if ((c->tags >> i) & 1)
+ nclienttags++;
+ }
+
+ if (TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1)
+ drawindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, 0, INDICATOR_RIGHT_TAGS);
+}
+
+#ifndef HIDDEN
+#define HIDDEN(C) 0
+#endif
+
+void
+flextitleclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg)
+{
+ if (passx >= x && passx <= x + w)
+ arg->v = c;
+}
+
+int
+flextitlecalculate(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+) {
+ Client *c;
+ int n, center = 0, mirror = 0, fixed = 0; // layout configuration
+ int clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0;
+ int i, w, r, num = 0, den, fulllayout = 0;
+ int clientsnstack2 = 0;
+ int groupactive = 0;
+ int selidx = 0;
+ int dualstack = 0;
+ int rw, rr;
+
+ int mas_x = offx, st1_x = offx, st2_x = offx, hid_x = offx, flt_x = offx;
+ int mas_w, st1_w, st2_w, hid_w;
+
+ for (i = 0, c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ if (HIDDEN(c)) {
+ if (FLEXWINTITLE_HIDDENWEIGHT)
+ clientsnhidden++;
+ continue;
+ }
+
+ if (c->isfloating) {
+ if (FLEXWINTITLE_FLOATWEIGHT)
+ clientsnfloating++;
+ continue;
+ }
+
+ if (m->sel == c)
+ selidx = i;
+
+ if (i < m->nmaster)
+ clientsnmaster++;
+ #if FLEXTILE_DELUXE_LAYOUT
+ else if (m->nstack) {
+ if (clientsnstack < m->nstack)
+ clientsnstack++;
+ else
+ clientsnstack2++;
+ }
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ else if ((i - m->nmaster) % 2)
+ clientsnstack2++;
+ else
+ clientsnstack++;
+ i++;
+ }
+
+ if (!m->sel)
+ groupactive = GRP_NOSELECTION;
+ else if (HIDDEN(m->sel))
+ groupactive = GRP_HIDDEN;
+ else if (m->sel->isfloating)
+ groupactive = GRP_FLOAT;
+ else if (selidx < clientsnmaster)
+ groupactive = GRP_MASTER;
+ else if (selidx < clientsnmaster + clientsnstack)
+ groupactive = GRP_STACK1;
+ else if (selidx < clientsnmaster + clientsnstack + clientsnstack2)
+ groupactive = GRP_STACK2;
+
+ n = clientsnmaster + clientsnstack + clientsnstack2 + clientsnfloating + clientsnhidden;
+ if (n == 0)
+ return 0;
+ #if FLEXTILE_DELUXE_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &flextile) {
+ int layout = m->ltaxis[LAYOUT];
+ if (layout < 0) {
+ mirror = 1;
+ layout *= -1;
+ }
+ if (layout > FLOATING_MASTER) {
+ layout -= FLOATING_MASTER;
+ fixed = 1;
+ }
+
+ if (layout == SPLIT_HORIZONTAL_DUAL_STACK || layout == SPLIT_HORIZONTAL_DUAL_STACK_FIXED)
+ dualstack = 1;
+ else if (layout == SPLIT_CENTERED_VERTICAL && (fixed || n - m->nmaster > 1))
+ center = 1;
+ else if (layout == FLOATING_MASTER)
+ center = 1;
+ else if (layout == SPLIT_CENTERED_HORIZONTAL) {
+ if (fixed || n - m->nmaster > 1)
+ center = 1;
+ }
+ }
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ #if CENTEREDMASTER_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &centeredmaster && (fixed || n - m->nmaster > 1))
+ center = 1;
+ #endif // CENTEREDMASTER_LAYOUT
+ #if CENTEREDFLOATINGMASTER_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &centeredfloatingmaster)
+ center = 1;
+ #endif // CENTEREDFLOATINGMASTER_LAYOUT
+
+ /* Certain layouts have no master / stack areas */
+ if (!m->lt[m->sellt]->arrange // floating layout
+ || (!n || (!fixed && m->nmaster && n <= m->nmaster)) // no master
+ #if MONOCLE_LAYOUT
+ || m->lt[m->sellt]->arrange == &monocle
+ #endif // MONOCLE_LAYOUT
+ #if GRIDMODE_LAYOUT
+ || m->lt[m->sellt]->arrange == &grid
+ #endif // GRIDMODE_LAYOUT
+ #if HORIZGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &horizgrid
+ #endif // HORIZGRID_LAYOUT
+ #if GAPPLESSGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &gaplessgrid
+ #endif // GAPPLESSGRID_LAYOUT
+ #if NROWGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &nrowgrid
+ #endif // NROWGRID_LAYOUT
+ #if FLEXTILE_DELUXE_LAYOUT
+ || (m->lt[m->sellt]->arrange == &flextile && m->ltaxis[LAYOUT] == NO_SPLIT)
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ )
+ fulllayout = 1;
+
+ num = tabw;
+ c = m->clients;
+
+ /* floating mode */
+ if ((fulllayout && FLEXWINTITLE_FLOATWEIGHT > 0) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) {
+ den = clientsnmaster + clientsnstack + clientsnstack2 + clientsnfloating + clientsnhidden;
+ w = num / den;
+ r = num % den; // rest
+ c = flextitledrawarea(m, c, mas_x, r, w, den, !m->lt[m->sellt]->arrange ? SchemeFlexActFloat : SCHEMEFOR(GRP_MASTER), 1, FLEXWINTITLE_HIDDENWEIGHT, FLEXWINTITLE_FLOATWEIGHT, passx, tabfn, arg, barg); // floating
+ /* no master and stack mode, e.g. monocole, grid layouts, fibonacci */
+ } else if (fulllayout) {
+ den = clientsnmaster + clientsnstack + clientsnstack2 + clientsnhidden;
+ w = num / den;
+ r = num % den; // rest
+ c = flextitledrawarea(m, c, mas_x, r, w, den, SCHEMEFOR(GRP_MASTER), 1, FLEXWINTITLE_HIDDENWEIGHT, 0, passx, tabfn, arg, barg); // full
+ /* tiled mode */
+ } else {
+ den = clientsnmaster * FLEXWINTITLE_MASTERWEIGHT + (clientsnstack + clientsnstack2) * FLEXWINTITLE_STACKWEIGHT + clientsnfloating * FLEXWINTITLE_FLOATWEIGHT + clientsnhidden * FLEXWINTITLE_HIDDENWEIGHT;
+ w = num / den; // weight width per client
+ r = num % den; // weight rest width
+ rw = r / n; // rest incr per client
+ rr = r % n; // rest rest
+ #if FLEXTILE_DELUXE_LAYOUT
+ if ((!center && !dualstack) || (center && n <= m->nmaster + (m->nstack ? m->nstack : 1)))
+ #else
+ if ((!center && !dualstack) || (center && n <= m->nmaster + 1))
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ {
+ clientsnstack += clientsnstack2;
+ clientsnstack2 = 0;
+ if (groupactive == GRP_STACK2)
+ groupactive = GRP_STACK1;
+ }
+
+ mas_w = clientsnmaster * rw + w * clientsnmaster * FLEXWINTITLE_MASTERWEIGHT + (rr > 0 ? MIN(rr, clientsnmaster) : 0);
+ rr -= clientsnmaster;
+ st1_w = clientsnstack * (rw + w * FLEXWINTITLE_STACKWEIGHT) + (rr > 0 ? MIN(rr, clientsnstack) : 0);
+ rr -= clientsnstack;
+ st2_w = clientsnstack2 * (rw + w * FLEXWINTITLE_STACKWEIGHT) + (rr > 0 ? MIN(rr, clientsnstack2) : 0);
+ rr -= clientsnstack2;
+ hid_w = clientsnhidden * (rw + w * FLEXWINTITLE_HIDDENWEIGHT) + (rr > 0 ? MIN(rr, clientsnhidden) : 0);
+ rr -= clientsnhidden;
+ rr = r % n;
+
+ if (mirror) {
+ if (center && clientsnstack2) {
+ mas_x = st1_x + st1_w;
+ st2_x = mas_x + mas_w;
+ hid_x = st2_x + st2_w;
+ } else {
+ if (clientsnstack2) {
+ st2_x = st1_x + st1_w;
+ mas_x = st2_x + st2_w;
+ } else
+ mas_x = st1_x + st1_w;
+ hid_x = mas_x + mas_w;
+ }
+ } else {
+ if (center && clientsnstack2) {
+ mas_x = st2_x + st2_w;
+ st1_x = mas_x + mas_w;
+ hid_x = st1_x + st1_w;
+ } else {
+ st1_x = mas_x + mas_w;
+ if (clientsnstack2) {
+ st2_x = st1_x + st1_w;
+ hid_x = st2_x + st2_w;
+ } else
+ hid_x = st1_x + st1_w;
+ }
+ }
+
+ flt_x = hid_x + hid_w;
+ c = flextitledrawarea(m, c, mas_x, rr, w * FLEXWINTITLE_MASTERWEIGHT + rw, clientsnmaster, SCHEMEFOR(GRP_MASTER), 1, 0, 0, passx, tabfn, arg, barg); // master
+ rr -= clientsnmaster;
+ c = flextitledrawarea(m, c, st1_x, rr, w * FLEXWINTITLE_STACKWEIGHT + rw, clientsnstack, SCHEMEFOR(GRP_STACK1), 1, 0, 0, passx, tabfn, arg, barg); // stack1
+ rr -= clientsnstack;
+ if (clientsnstack2) {
+ c = flextitledrawarea(m, c, st2_x, rr, w * FLEXWINTITLE_STACKWEIGHT + rw, clientsnstack2, SCHEMEFOR(GRP_STACK2), 1, 0, 0, passx, tabfn, arg, barg); // stack2
+ rr -= clientsnstack2;
+ }
+ c = flextitledrawarea(m, m->clients, hid_x, rr, w * FLEXWINTITLE_HIDDENWEIGHT + rw, clientsnhidden, SCHEMEFOR(GRP_HIDDEN), 0, 1, 0, passx, tabfn, arg, barg); // hidden
+ rr -= clientsnhidden;
+ c = flextitledrawarea(m, m->clients, flt_x, rr, w * FLEXWINTITLE_FLOATWEIGHT + rw, clientsnfloating, SCHEMEFOR(GRP_FLOAT), 0, 0, 1, passx, tabfn, arg, barg); // floating
+ }
+ return 1;
+}
+
diff --git a/patch/bar_flexwintitle.h b/patch/bar_flexwintitle.h
new file mode 100644
index 0000000..f4c6612
--- /dev/null
+++ b/patch/bar_flexwintitle.h
@@ -0,0 +1,11 @@
+static int width_flexwintitle(Bar *bar, BarArg *a);
+static int draw_flexwintitle(Bar *bar, BarArg *a);
+static int click_flexwintitle(Bar *bar, Arg *arg, BarArg *a);
+
+static void flextitledraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg);
+static void flextitleclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg);
+static int flextitlecalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg);
+static int getschemefor(Monitor *m, int group, int activegroup);
+static int getselschemefor(int scheme);
+static Client *flextitledrawarea(Monitor *m, Client *c, int x, int r, int w, int max_clients, int tabscheme, int draw_tiled, int draw_hidden, int draw_floating, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg);
+
diff --git a/patch/bar_holdbar.c b/patch/bar_holdbar.c
new file mode 100644
index 0000000..1e00dc8
--- /dev/null
+++ b/patch/bar_holdbar.c
@@ -0,0 +1,38 @@
+void
+holdbar(const Arg *arg)
+{
+ if (selmon->showbar)
+ return;
+ Bar *bar;
+ selmon->showbar = 2;
+ updatebarpos(selmon);
+ for (bar = selmon->bar; bar; bar = bar->next)
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+}
+
+void
+keyrelease(XEvent *e)
+{
+ Bar *bar;
+ if (XEventsQueued(dpy, QueuedAfterReading)) {
+ XEvent ne;
+ XPeekEvent(dpy, &ne);
+
+ if (ne.type == KeyPress && ne.xkey.time == e->xkey.time &&
+ ne.xkey.keycode == e->xkey.keycode) {
+ XNextEvent(dpy, &ne);
+ return;
+ }
+ }
+ if (e->xkey.keycode == XKeysymToKeycode(dpy, HOLDKEY) && selmon->showbar == 2) {
+ selmon->showbar = 0;
+ updatebarpos(selmon);
+ for (bar = selmon->bar; bar; bar = bar->next)
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+ arrange(selmon);
+ }
+ #if COMBO_PATCH
+ combo = 0;
+ #endif // COMBO_PATCH
+}
+
diff --git a/patch/bar_holdbar.h b/patch/bar_holdbar.h
new file mode 100644
index 0000000..bcde089
--- /dev/null
+++ b/patch/bar_holdbar.h
@@ -0,0 +1,3 @@
+static void keyrelease(XEvent *e);
+static void holdbar(const Arg *arg);
+
diff --git a/patch/bar_indicators.c b/patch/bar_indicators.c
new file mode 100644
index 0000000..62326bc
--- /dev/null
+++ b/patch/bar_indicators.c
@@ -0,0 +1,111 @@
+/* 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 FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
+ if (c->fakefullscreen && c->isfloating)
+ drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatfakefsindicatortype);
+ else if (c->fakefullscreen)
+ drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, fakefsindicatortype);
+ else
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+ 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_layoutmenu.c b/patch/bar_layoutmenu.c
new file mode 100644
index 0000000..1b95069
--- /dev/null
+++ b/patch/bar_layoutmenu.c
@@ -0,0 +1,18 @@
+void
+layoutmenu(const Arg *arg) {
+ FILE *p;
+ char c[3], *s;
+ int i;
+
+ if (!(p = popen(layoutmenu_cmd, "r")))
+ return;
+ s = fgets(c, sizeof(c), p);
+ pclose(p);
+
+ if (!s || *s == '\0' || c == '\0')
+ return;
+
+ i = atoi(c);
+ setlayout(&((Arg) { .v = &layouts[i] }));
+}
+
diff --git a/patch/bar_layoutmenu.h b/patch/bar_layoutmenu.h
new file mode 100644
index 0000000..d05455c
--- /dev/null
+++ b/patch/bar_layoutmenu.h
@@ -0,0 +1,2 @@
+static void layoutmenu(const Arg *arg);
+
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_powerline_status.c b/patch/bar_powerline_status.c
new file mode 100644
index 0000000..a09487f
--- /dev/null
+++ b/patch/bar_powerline_status.c
@@ -0,0 +1,122 @@
+static Clr **statusscheme;
+
+int
+width_pwrl_status(Bar *bar, BarArg *a)
+{
+ #if BAR_STATUSCMD_PATCH
+ return widthpowerlinestatus(rawstext);
+ #else
+ return widthpowerlinestatus(stext);
+ #endif // BAR_STATUSCMD_PATCH
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+width_pwrl_status_es(Bar *bar, BarArg *a)
+{
+ #if BAR_STATUSCMD_PATCH
+ return widthpowerlinestatus(rawestext);
+ #else
+ return widthpowerlinestatus(estext);
+ #endif // BAR_STATUSCMD_PATCH
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+int
+draw_pwrl_status(Bar *bar, BarArg *a)
+{
+ #if BAR_STATUSCMD_PATCH
+ return drawpowerlinestatus(a->x + a->w, rawstext, a);
+ #else
+ return drawpowerlinestatus(a->x + a->w, stext, a);
+ #endif // BAR_STATUSCMD_PATCH
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+draw_pwrl_status_es(Bar *bar, BarArg *a)
+{
+ #if BAR_STATUSCMD_PATCH
+ return drawpowerlinestatus(a->x + a->w, rawestext, a);
+ #else
+ return drawpowerlinestatus(a->x + a->w, estext, a);
+ #endif // BAR_STATUSCMD_PATCH
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+int
+click_pwrl_status(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkStatusText;
+}
+
+int
+widthpowerlinestatus(char *stext)
+{
+ char status[512];
+ int w = 0, i, n = strlen(stext);
+ int plw = drw->fonts->h / 2 + 1;
+ char *bs, bp = '|';
+ strcpy(status, stext);
+
+ for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) {
+ if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */
+ if (bp != '|')
+ w += plw;
+ w += TEXTW(bs+2);
+ bp = *bs;
+ *bs = 0;
+ }
+ }
+ if (bp != '|')
+ w += plw * 2;
+
+ return w;
+}
+
+int
+drawpowerlinestatus(int xpos, char *stext, BarArg *barg)
+{
+ char status[512];
+ int i, n = strlen(stext), cn = 0;
+ int x = xpos, w = 0;
+ int plw = drw->fonts->h / 2 + 1;
+ char *bs, bp = '|';
+ Clr *prevscheme = statusscheme[0], *nxtscheme;
+ strcpy(status, stext);
+
+ for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) {
+ if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */
+ cn = ((int) *(bs+1)) - 1;
+
+ if (cn < LENGTH(statuscolors)) {
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[cn]));
+ } else {
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[0]));
+ }
+
+ if (bp != '|') {
+ drw_arrow(drw, x - plw, barg->y, plw, barg->h, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1);
+ x -= plw;
+ }
+
+ drw_setscheme(drw, nxtscheme);
+ w = TEXTW(bs+2);
+ drw_text(drw, x - w, barg->y, w, barg->h, lrpad / 2, bs+2, 0, False);
+ x -= w;
+
+ bp = *bs;
+ *bs = 0;
+ prevscheme = nxtscheme;
+ }
+ }
+ if (bp != '|') {
+ drw_settrans(drw, prevscheme, scheme[SchemeNorm]);
+ drw_arrow(drw, x - plw, barg->y, plw, barg->h, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1);
+ drw_rect(drw, x - 2 * plw, barg->y, plw, barg->h, 1, 1);
+ x -= plw * 2;
+ }
+
+ return xpos - x;
+}
+
diff --git a/patch/bar_powerline_status.h b/patch/bar_powerline_status.h
new file mode 100644
index 0000000..46b78e0
--- /dev/null
+++ b/patch/bar_powerline_status.h
@@ -0,0 +1,12 @@
+static int width_pwrl_status(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int width_pwrl_status_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+static int draw_pwrl_status(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int draw_pwrl_status_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+static int click_pwrl_status(Bar *bar, Arg *arg, BarArg *a);
+static int drawpowerlinestatus(int x, char *stext, BarArg *a);
+static int widthpowerlinestatus(char *stext);
+
diff --git a/patch/bar_powerline_tags.c b/patch/bar_powerline_tags.c
new file mode 100644
index 0000000..d5ad787
--- /dev/null
+++ b/patch/bar_powerline_tags.c
@@ -0,0 +1,107 @@
+int
+width_pwrl_tags(Bar *bar, BarArg *a)
+{
+ int w, i;
+ int plw = drw->fonts->h / 2 + 1;
+ #if BAR_HIDEVACANTTAGS_PATCH
+ Client *c;
+ unsigned int occ = 0;
+ for (c = bar->mon->clients; c; c = c->next)
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ for (w = 0, i = 0; i < NUMTAGS; i++) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ w += TEXTW(tagicon(bar->mon, i)) + plw;
+ }
+ return w + lrpad;
+}
+
+int
+draw_pwrl_tags(Bar *bar, BarArg *a)
+{
+ int x, w;
+ int invert;
+ int plw = drw->fonts->h / 2 + 1;
+ unsigned int i, occ = 0, urg = 0;
+ char *icon;
+ Client *c;
+ Clr *prevscheme, *nxtscheme;
+
+ for (c = bar->mon->clients; c; c = c->next) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #else
+ occ |= c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ if (c->isurgent)
+ urg |= c->tags;
+ }
+ x = a->x;
+ prevscheme = scheme[SchemeNorm];
+ for (i = 0; i < NUMTAGS; i++) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ /* do not draw vacant tags */
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ icon = tagicon(bar->mon, i);
+ invert = 0;
+ w = TEXTW(icon);
+ if (urg & 1 << i) {
+ drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeUrg]));
+ } else {
+ drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm]));
+ }
+ #if BAR_POWERLINE_TAGS_SLASH_PATCH
+ drw_arrow(drw, x, a->y, plw, a->h, 1, 1);
+ #else
+ drw_arrow(drw, x, a->y, plw, a->h, 1, 0);
+ #endif // BAR_POWERLINE_TAGS_SLASH_PATCH
+ x += plw;
+ drw_setscheme(drw, nxtscheme);
+ drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False);
+ drawindicator(bar->mon, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype);
+ x += w;
+ prevscheme = nxtscheme;
+ }
+ nxtscheme = scheme[SchemeNorm];
+
+ drw_settrans(drw, prevscheme, nxtscheme);
+ #if BAR_POWERLINE_TAGS_SLASH_PATCH
+ drw_arrow(drw, x, a->y, plw, a->h, 1, 1);
+ #else
+ drw_arrow(drw, x, a->y, plw, a->h, 1, 0);
+ #endif // BAR_POWERLINE_TAGS_SLASH_PATCH
+ return 1;
+}
+
+int
+click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a)
+{
+ int i = 0, x = lrpad / 2;
+ int plw = drw->fonts->h / 2 + 1;
+ #if BAR_HIDEVACANTTAGS_PATCH
+ Client *c;
+ unsigned int occ = 0;
+ for (c = bar->mon->clients; c; c = c->next)
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ do {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ x += TEXTW(tagicon(bar->mon, i)) + plw;
+ } while (a->x >= x && ++i < NUMTAGS);
+ if (i < NUMTAGS) {
+ arg->ui = 1 << i;
+ }
+ return ClkTagBar;
+}
+
diff --git a/patch/bar_powerline_tags.h b/patch/bar_powerline_tags.h
new file mode 100644
index 0000000..a51dcc7
--- /dev/null
+++ b/patch/bar_powerline_tags.h
@@ -0,0 +1,4 @@
+static int width_pwrl_tags(Bar *bar, BarArg *a);
+static int draw_pwrl_tags(Bar *bar, BarArg *a);
+static int click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_status.c b/patch/bar_status.c
new file mode 100644
index 0000000..715b6d2
--- /dev/null
+++ b/patch/bar_status.c
@@ -0,0 +1,34 @@
+int
+width_status(Bar *bar, BarArg *a)
+{
+ return TEXTWM(stext);
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+width_status_es(Bar *bar, BarArg *a)
+{
+ return TEXTWM(estext) - lrpad;
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+int
+draw_status(Bar *bar, BarArg *a)
+{
+ return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, stext, 0, True);
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+draw_status_es(Bar *bar, BarArg *a)
+{
+ return drw_text(drw, a->x, a->y, a->w, a->h, 0, estext, 0, True);
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+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..4bf5e58
--- /dev/null
+++ b/patch/bar_status.h
@@ -0,0 +1,10 @@
+static int width_status(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int width_status_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+static int draw_status(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int draw_status_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+static int click_status(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_status2d.c b/patch/bar_status2d.c
new file mode 100644
index 0000000..860fd83
--- /dev/null
+++ b/patch/bar_status2d.c
@@ -0,0 +1,268 @@
+#if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH
+static char termcol0[] = "#000000"; /* black */
+static char termcol1[] = "#ff0000"; /* red */
+static char termcol2[] = "#33ff00"; /* green */
+static char termcol3[] = "#ff0099"; /* yellow */
+static char termcol4[] = "#0066ff"; /* blue */
+static char termcol5[] = "#cc00ff"; /* magenta */
+static char termcol6[] = "#00ffff"; /* cyan */
+static char termcol7[] = "#d0d0d0"; /* white */
+static char termcol8[] = "#808080"; /* black */
+static char termcol9[] = "#ff0000"; /* red */
+static char termcol10[] = "#33ff00"; /* green */
+static char termcol11[] = "#ff0099"; /* yellow */
+static char termcol12[] = "#0066ff"; /* blue */
+static char termcol13[] = "#cc00ff"; /* magenta */
+static char termcol14[] = "#00ffff"; /* cyan */
+static char termcol15[] = "#ffffff"; /* white */
+static char *termcolor[] = {
+ termcol0, termcol1, termcol2, termcol3, termcol4, termcol5, termcol6, termcol7,
+ termcol8, termcol9, termcol10, termcol11, termcol12, termcol13, termcol14, termcol15,
+};
+#endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH
+
+int
+width_status2d(Bar *bar, BarArg *a)
+{
+ int width;
+ #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH
+ width = status2dtextlength(rawstext);
+ #else
+ width = status2dtextlength(stext);
+ #endif // #if BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
+ return width ? width + lrpad : 0;
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+width_status2d_es(Bar *bar, BarArg *a)
+{
+ int width;
+ #if BAR_STATUSCMD_PATCH
+ width = status2dtextlength(rawestext);
+ #else
+ width = status2dtextlength(estext);
+ #endif // BAR_STATUSCMD_PATCH
+ return width ? width + lrpad : 0;
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+int
+draw_status2d(Bar *bar, BarArg *a)
+{
+ #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH
+ return drawstatusbar(a, rawstext);
+ #else
+ return drawstatusbar(a, stext);
+ #endif // #if BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+draw_status2d_es(Bar *bar, BarArg *a)
+{
+ #if BAR_STATUSCMD_PATCH
+ return drawstatusbar(a, rawestext);
+ #else
+ return drawstatusbar(a, estext);
+ #endif // BAR_STATUSCMD_PATCH
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+#if !BAR_STATUSCMD_PATCH
+int
+click_status2d(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkStatusText;
+}
+#endif // BAR_STATUSCMD_PATCH
+
+int
+drawstatusbar(BarArg *a, char* stext)
+{
+ int i, w, len;
+ int x = a->x;
+ int y = a->y;
+ short isCode = 0;
+ char *text;
+ char *p;
+ Clr oldbg, oldfg;
+ len = strlen(stext);
+ if (!(text = (char*) malloc(sizeof(char)*(len + 1))))
+ die("malloc");
+ p = text;
+ #if BAR_STATUSCMD_PATCH
+ copyvalidchars(text, stext);
+ #else
+ memcpy(text, stext, len);
+ #endif // BAR_STATUSCMD_PATCH
+
+ x += lrpad / 2;
+ drw_setscheme(drw, scheme[LENGTH(colors)]);
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
+
+ /* process status text */
+ i = -1;
+ while (text[++i]) {
+ if (text[i] == '^' && !isCode) {
+ isCode = 1;
+
+ text[i] = '\0';
+ w = TEXTWM(text) - lrpad;
+ drw_text(drw, x, y, w, bh, 0, text, 0, True);
+
+ x += w;
+
+ /* process code */
+ while (text[++i] != '^') {
+ if (text[i] == 'c') {
+ char buf[8];
+ if (i + 7 >= len) {
+ i += 7;
+ len = 0;
+ break;
+ }
+ memcpy(buf, (char*)text+i+1, 7);
+ buf[7] = '\0';
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, 0xff);
+ #elif BAR_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, alphas[SchemeNorm][ColFg]);
+ #else
+ drw_clr_create(drw, &drw->scheme[ColFg], buf);
+ #endif // BAR_ALPHA_PATCH
+ i += 7;
+ } else if (text[i] == 'b') {
+ char buf[8];
+ if (i + 7 >= len) {
+ i += 7;
+ len = 0;
+ break;
+ }
+ memcpy(buf, (char*)text+i+1, 7);
+ buf[7] = '\0';
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, 0xff);
+ #elif BAR_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, alphas[SchemeNorm][ColBg]);
+ #else
+ drw_clr_create(drw, &drw->scheme[ColBg], buf);
+ #endif // BAR_ALPHA_PATCH
+ i += 7;
+ #if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH
+ } else if (text[i] == 'C') {
+ int c = atoi(text + ++i) % 16;
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c], 0xff);
+ #elif BAR_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c], alphas[SchemeNorm][ColBg]);
+ #else
+ drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c]);
+ #endif // BAR_ALPHA_PATCH
+ } else if (text[i] == 'B') {
+ int c = atoi(text + ++i) % 16;
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c], 0xff);
+ #elif BAR_ALPHA_PATCH
+ drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c], alphas[SchemeNorm][ColBg]);
+ #else
+ drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c]);
+ #endif // BAR_ALPHA_PATCH
+ #endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH
+ } else if (text[i] == 'd') {
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
+ } else if (text[i] == 'w') {
+ Clr swp;
+ swp = drw->scheme[ColFg];
+ drw->scheme[ColFg] = drw->scheme[ColBg];
+ drw->scheme[ColBg] = swp;
+ } else if (text[i] == 'v') {
+ oldfg = drw->scheme[ColFg];
+ oldbg = drw->scheme[ColBg];
+ } else if (text[i] == 't') {
+ drw->scheme[ColFg] = oldfg;
+ drw->scheme[ColBg] = oldbg;
+ } else if (text[i] == 'r') {
+ int rx = atoi(text + ++i);
+ while (text[++i] != ',');
+ int ry = atoi(text + ++i);
+ while (text[++i] != ',');
+ int rw = atoi(text + ++i);
+ while (text[++i] != ',');
+ int rh = atoi(text + ++i);
+
+ if (ry < 0)
+ ry = 0;
+ if (rx < 0)
+ rx = 0;
+
+ drw_rect(drw, rx + x, y + ry, rw, rh, 1, 0);
+ } else if (text[i] == 'f') {
+ x += atoi(text + ++i);
+ }
+ }
+
+ text = text + i + 1;
+ len -= i + 1;
+ i = -1;
+ isCode = 0;
+ if (len <= 0)
+ break;
+ }
+ }
+ if (!isCode && len > 0) {
+ w = TEXTWM(text) - lrpad;
+ drw_text(drw, x, y, w, bh, 0, text, 0, True);
+ x += w;
+ }
+ free(p);
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ return 1;
+}
+
+int
+status2dtextlength(char* stext)
+{
+ int i, w, len;
+ short isCode = 0;
+ char *text;
+ char *p;
+
+ len = strlen(stext) + 1;
+ if (!(text = (char*) malloc(sizeof(char)*len)))
+ die("malloc");
+ p = text;
+ #if BAR_STATUSCMD_PATCH
+ copyvalidchars(text, stext);
+ #else
+ memcpy(text, stext, len);
+ #endif // BAR_STATUSCMD_PATCH
+
+ /* compute width of the status text */
+ w = 0;
+ i = -1;
+ while (text[++i]) {
+ if (text[i] == '^') {
+ if (!isCode) {
+ isCode = 1;
+ text[i] = '\0';
+ w += TEXTWM(text) - lrpad;
+ text[i] = '^';
+ if (text[++i] == 'f')
+ w += atoi(text + ++i);
+ } else {
+ isCode = 0;
+ text = text + i + 1;
+ i = -1;
+ }
+ }
+ }
+ if (!isCode)
+ w += TEXTWM(text) - lrpad;
+ free(p);
+ return w;
+}
+
diff --git a/patch/bar_status2d.h b/patch/bar_status2d.h
new file mode 100644
index 0000000..8e088fb
--- /dev/null
+++ b/patch/bar_status2d.h
@@ -0,0 +1,14 @@
+static int width_status2d(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int width_status2d_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+static int draw_status2d(Bar *bar, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int draw_status2d_es(Bar *bar, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+#if !BAR_STATUSCMD_PATCH
+static int click_status2d(Bar *bar, Arg *arg, BarArg *a);
+#endif // BAR_STATUSCMD_PATCH
+static int drawstatusbar(BarArg *a, char *text);
+static int status2dtextlength(char *stext);
+
diff --git a/patch/bar_statusbutton.c b/patch/bar_statusbutton.c
new file mode 100644
index 0000000..5e43fe0
--- /dev/null
+++ b/patch/bar_statusbutton.c
@@ -0,0 +1,18 @@
+int
+width_stbutton(Bar *bar, BarArg *a)
+{
+ return TEXTW(buttonbar);
+}
+
+int
+draw_stbutton(Bar *bar, BarArg *a)
+{
+ return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, buttonbar, 0, False);
+}
+
+int
+click_stbutton(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkButton;
+}
+
diff --git a/patch/bar_statusbutton.h b/patch/bar_statusbutton.h
new file mode 100644
index 0000000..ed5beb5
--- /dev/null
+++ b/patch/bar_statusbutton.h
@@ -0,0 +1,4 @@
+static int width_stbutton(Bar *bar, BarArg *a);
+static int draw_stbutton(Bar *bar, BarArg *a);
+static int click_stbutton(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/bar_statuscmd.c b/patch/bar_statuscmd.c
new file mode 100644
index 0000000..5b26932
--- /dev/null
+++ b/patch/bar_statuscmd.c
@@ -0,0 +1,75 @@
+#if !BAR_DWMBLOCKS_PATCH
+static const char statusexport[] = "export BUTTON=-;";
+static int statuscmdn;
+static char lastbutton[] = "-";
+#endif // BAR_DWMBLOCKS_PATCH
+
+int
+click_statuscmd(Bar *bar, Arg *arg, BarArg *a)
+{
+ return click_statuscmd_text(arg, a->x, rawstext);
+}
+
+#if BAR_EXTRASTATUS_PATCH
+int
+click_statuscmd_es(Bar *bar, Arg *arg, BarArg *a)
+{
+ return click_statuscmd_text(arg, a->x, rawestext);
+}
+#endif // BAR_EXTRASTATUS_PATCH
+
+int
+click_statuscmd_text(Arg *arg, int rel_x, char *text)
+{
+ int i = -1;
+ int x = 0;
+ char ch;
+ #if BAR_DWMBLOCKS_PATCH
+ statussig = -1;
+ #else
+ statuscmdn = 0;
+ #endif // BAR_DWMBLOCKS_PATCH
+ while (text[++i]) {
+ if ((unsigned char)text[i] < ' ') {
+ ch = text[i];
+ text[i] = '\0';
+ #if BAR_STATUS2D_PATCH && !BAR_BAR_STATUSCOLORS_PATCH
+ x += status2dtextlength(text);
+ #else
+ x += TEXTWM(text) - lrpad;
+ #endif // BAR_STATUS2D_PATCH
+ text[i] = ch;
+ text += i+1;
+ i = -1;
+ #if BAR_DWMBLOCKS_PATCH
+ if (x >= rel_x && statussig != -1)
+ break;
+ statussig = ch;
+ #else
+ if (x >= rel_x)
+ break;
+ if (ch <= LENGTH(statuscmds))
+ statuscmdn = ch;
+ #endif // BAR_DWMBLOCKS_PATCH
+ }
+ }
+ #if BAR_DWMBLOCKS_PATCH
+ if (statussig == -1)
+ statussig = 0;
+ #endif // BAR_DWMBLOCKS_PATCH
+ 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..a4c4d24
--- /dev/null
+++ b/patch/bar_statuscmd.h
@@ -0,0 +1,12 @@
+static int click_statuscmd(Bar *bar, Arg *arg, BarArg *a);
+#if BAR_EXTRASTATUS_PATCH
+static int click_statuscmd_es(Bar *bar, Arg *arg, BarArg *a);
+#endif // BAR_EXTRASTATUS_PATCH
+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_statuscolors.c b/patch/bar_statuscolors.c
new file mode 100644
index 0000000..4ade4df
--- /dev/null
+++ b/patch/bar_statuscolors.c
@@ -0,0 +1,24 @@
+int
+textw_wosc(char *s)
+{
+ char *ts = s;
+ char *tp = s;
+ int sw = 0;
+ char ctmp;
+ while (1) {
+ if ((unsigned int)*ts > LENGTH(colors)) {
+ ts++;
+ continue;
+ }
+ ctmp = *ts;
+ *ts = '\0';
+ sw += drw_fontset_getwidth(drw, tp, True);
+ *ts = ctmp;
+ if (ctmp == '\0')
+ break;
+ tp = ++ts;
+ }
+
+ return sw;
+}
+
diff --git a/patch/bar_systray.c b/patch/bar_systray.c
new file mode 100644
index 0000000..67d1d2d
--- /dev/null
+++ b/patch/bar_systray.c
@@ -0,0 +1,198 @@
+static Systray *systray = NULL;
+static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
+
+int
+width_systray(Bar *bar, BarArg *a)
+{
+ unsigned int w = 0;
+ Client *i;
+ if (!systray)
+ return 1;
+ if (showsystray)
+ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
+ return w ? w + lrpad - systrayspacing : 0;
+}
+
+int
+draw_systray(Bar *bar, BarArg *a)
+{
+ if (!showsystray)
+ return 0;
+
+ XSetWindowAttributes wa;
+ XWindowChanges wc;
+ Client *i;
+ unsigned int w;
+
+ if (!systray) {
+ /* init systray */
+ if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
+
+ wa.override_redirect = True;
+ wa.event_mask = ButtonPressMask|ExposureMask;
+ wa.border_pixel = 0;
+ systray->h = MIN(a->h, drw->fonts->h);
+ #if BAR_ALPHA_PATCH
+ wa.background_pixel = 0;
+ wa.colormap = cmap;
+ systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by + a->y + (a->h - systray->h) / 2, MAX(a->w + 40, 1), systray->h, 0, depth,
+ InputOutput, visual,
+ CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
+ #else
+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
+ systray->win = XCreateSimpleWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by + a->y + (a->h - systray->h) / 2, MIN(a->w, 1), systray->h, 0, 0, scheme[SchemeNorm][ColBg].pixel);
+ XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa);
+ #endif // BAR_ALPHA_PATCH
+
+ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&systrayorientation, 1);
+ #if BAR_ALPHA_PATCH
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
+ PropModeReplace, (unsigned char *)&visual->visualid, 1);
+ #endif // BAR_ALPHA_PATCH
+ XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1);
+ XMapRaised(dpy, systray->win);
+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
+ XSync(dpy, False);
+ } else {
+ fprintf(stderr, "dwm: unable to obtain system tray.\n");
+ free(systray);
+ systray = NULL;
+ return 0;
+ }
+ }
+
+ systray->bar = bar;
+
+ wc.stack_mode = Above;
+ wc.sibling = bar->win;
+ XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc);
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ for (w = 0, i = systray->icons; i; i = i->next) {
+ #if BAR_ALPHA_PATCH
+ wa.background_pixel = 0;
+ #else
+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
+ #endif // BAR_ALPHA_PATCH
+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
+ XMapRaised(dpy, i->win);
+ i->x = w;
+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
+ w += i->w;
+ if (i->next)
+ w += systrayspacing;
+ if (i->mon != bar->mon)
+ i->mon = bar->mon;
+ }
+
+ XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -bar->by - a->y), MAX(w, 1), systray->h);
+ return w;
+}
+
+int
+click_systray(Bar *bar, Arg *arg, BarArg *a)
+{
+ return -1;
+}
+
+void
+removesystrayicon(Client *i)
+{
+ Client **ii;
+
+ if (!showsystray || !i)
+ return;
+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
+ if (ii)
+ *ii = i->next;
+ free(i);
+ drawbarwin(systray->bar);
+}
+
+void
+resizerequest(XEvent *e)
+{
+ XResizeRequestEvent *ev = &e->xresizerequest;
+ Client *i;
+
+ if ((i = wintosystrayicon(ev->window))) {
+ updatesystrayicongeom(i, ev->width, ev->height);
+ drawbarwin(systray->bar);
+ }
+}
+
+void
+updatesystrayicongeom(Client *i, int w, int h)
+{
+ if (!systray)
+ return;
+
+ int icon_height = systray->h;
+ if (i) {
+ i->h = icon_height;
+ if (w == h)
+ i->w = icon_height;
+ else if (h == icon_height)
+ i->w = w;
+ else
+ i->w = (int) ((float)icon_height * ((float)w / (float)h));
+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
+ /* force icons into the systray dimensions if they don't want to */
+ if (i->h > icon_height) {
+ if (i->w == i->h)
+ i->w = icon_height;
+ else
+ i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h));
+ i->h = icon_height;
+ }
+ if (i->w > 2 * icon_height)
+ i->w = icon_height;
+ }
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+ long flags;
+ int code = 0;
+
+ if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
+ !(flags = getatomprop(i, xatom[XembedInfo])))
+ return;
+
+ if (flags & XEMBED_MAPPED && !i->tags) {
+ i->tags = 1;
+ code = XEMBED_WINDOW_ACTIVATE;
+ XMapRaised(dpy, i->win);
+ setclientstate(i, NormalState);
+ }
+ else if (!(flags & XEMBED_MAPPED) && i->tags) {
+ i->tags = 0;
+ code = XEMBED_WINDOW_DEACTIVATE;
+ XUnmapWindow(dpy, i->win);
+ setclientstate(i, WithdrawnState);
+ }
+ else
+ return;
+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+ systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+Client *
+wintosystrayicon(Window w)
+{
+ if (!systray)
+ return NULL;
+ Client *i = NULL;
+ if (!showsystray || !w)
+ return i;
+ for (i = systray->icons; i && i->win != w; i = i->next);
+ return i;
+}
+
diff --git a/patch/bar_systray.h b/patch/bar_systray.h
new file mode 100644
index 0000000..a64b971
--- /dev/null
+++ b/patch/bar_systray.h
@@ -0,0 +1,42 @@
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
+
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_MODALITY_ON 10
+
+#define XEMBED_MAPPED (1 << 0)
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_WINDOW_DEACTIVATE 2
+
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
+
+/* enums */
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+
+typedef struct Systray Systray;
+struct Systray {
+ Window win;
+ Client *icons;
+ Bar *bar;
+ int h;
+};
+
+/* bar integration */
+static int width_systray(Bar *bar, BarArg *a);
+static int draw_systray(Bar *bar, BarArg *a);
+static int click_systray(Bar *bar, Arg *arg, BarArg *a);
+
+/* function declarations */
+static Atom getatomprop(Client *c, Atom prop);
+static void removesystrayicon(Client *i);
+static void resizerequest(XEvent *e);
+static void updatesystrayicongeom(Client *i, int w, int h);
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
+static Client *wintosystrayicon(Window w);
+
+
diff --git a/patch/bar_tabgroups.c b/patch/bar_tabgroups.c
new file mode 100644
index 0000000..1498bc2
--- /dev/null
+++ b/patch/bar_tabgroups.c
@@ -0,0 +1,231 @@
+/* Bartabgroups properties, you can override these in your config.h if you want. */
+#ifndef BARTAB_BORDERS
+#define BARTAB_BORDERS 1 // 0 = off, 1 = on
+#endif
+#ifndef BARTAB_SHOWFLOATING
+#define BARTAB_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown
+#endif
+#ifndef BARTAB_STACKWEIGHT
+#define BARTAB_STACKWEIGHT 1 // stack weight compared to hidden and floating window titles
+#endif
+#ifndef BARTAB_HIDDENWEIGHT
+#define BARTAB_HIDDENWEIGHT 1 // hidden window title weight
+#endif
+#ifndef BARTAB_FLOATWEIGHT
+#define BARTAB_FLOATWEIGHT 1 // floating window title weight, set to 0 to not show floating windows
+#endif
+
+int
+width_bartabgroups(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_bartabgroups(Bar *bar, BarArg *a)
+{
+ drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1);
+ return bartabcalculate(bar->mon, a->x, a->w, -1, bartabdraw, NULL, a);
+}
+
+int
+click_bartabgroups(Bar *bar, Arg *arg, BarArg *a)
+{
+ bartabcalculate(bar->mon, 0, a->w, a->x, bartabclick, arg, a);
+ return ClkWinTitle;
+}
+
+void
+bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg)
+{
+ if (!c)
+ return;
+ int i, nclienttags = 0, nviewtags = 0, pad = lrpad / 2;
+ drw_setscheme(drw, scheme[
+ m->sel == c
+ #ifdef HIDDEN
+ && HIDDEN(c)
+ ? SchemeHidSel
+ : HIDDEN(c)
+ ? SchemeHidNorm
+ : m->sel == c
+ #endif
+ ? SchemeSel
+ : groupactive
+ ? SchemeTitleSel
+ : SchemeTitleNorm
+ ]);
+ if (w <= TEXTW("A") - lrpad + pad) // reduce text padding if wintitle is too small
+ pad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2);
+ #if BAR_CENTEREDWINDOWNAME_PATCH
+ else if (TEXTW(c->name) < w)
+ pad = (w - TEXTW(c->name) + lrpad) / 2;
+ #endif // BAR_CENTEREDWINDOWNAME_PATCH
+
+ #if BAR_WINICON_PATCH
+ drw_text(drw, x, barg->y, w, barg->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False);
+ if (c->icon)
+ drw_img(drw, x + pad, barg->y + (barg->h - c->icon->height) / 2, c->icon, tmpicon);
+ #else
+ drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False);
+ #endif // BAR_WINICON_PATCH
+
+ drawstateindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, c->isfixed);
+
+ if (BARTAB_BORDERS) {
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, barg->y, 1, barg->h);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w - (x + w >= barg->w ? 1 : 0), barg->y, 1, barg->h);
+ }
+ /* Optional tags icons */
+ for (i = 0; i < NUMTAGS; i++) {
+ if ((m->tagset[m->seltags] >> i) & 1)
+ nviewtags++;
+ if ((c->tags >> i) & 1)
+ nclienttags++;
+ }
+
+ if (TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1)
+ drawindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, 0, INDICATOR_RIGHT_TAGS);
+}
+
+#ifndef HIDDEN
+#define HIDDEN(C) 0
+#endif
+
+void
+bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg)
+{
+ if (passx >= x && passx <= x + w)
+ arg->v = c;
+}
+
+int
+bartabcalculate(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+) {
+ Client *c;
+ int
+ i, clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0,
+ masteractive = 0, fulllayout = 0,
+ x = offx, w, r, num = 0, den, tgactive;
+
+ for (i = 0; i < LENGTH(bartabmonfns); i++)
+ if (m ->lt[m->sellt]->arrange == bartabmonfns[i]) {
+ fulllayout = 1;
+ break;
+ }
+
+ for (i = 0, c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ if (HIDDEN(c)) {
+ clientsnhidden++;
+ continue;
+ }
+ if (c->isfloating) {
+ clientsnfloating++;
+ continue;
+ }
+ if (m->sel == c)
+ masteractive = i < m->nmaster;
+ if (i < m->nmaster)
+ clientsnmaster++;
+ else
+ clientsnstack++;
+ i++;
+ }
+
+ if (clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden == 0)
+ return 0;
+
+ tgactive = 1;
+ num = tabw;
+ /* floating mode */
+ if ((fulllayout && BARTAB_FLOATWEIGHT) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) {
+ den = clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden;
+ r = num % den;
+ w = num / den;
+ for (c = m->clients, i = 0; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg);
+ x += w + (i < r ? 1 : 0);
+ i++;
+ }
+ /* no master and stack mode, e.g. monocole, grid layouts, fibonacci */
+ } else if (fulllayout) {
+ den = clientsnmaster + clientsnstack + clientsnhidden;
+ r = num % den;
+ w = num / den;
+ for (c = m->clients, i = 0; c; c = c->next) {
+ if (!ISVISIBLE(c) || (c->isfloating && !HIDDEN(c)))
+ continue;
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg);
+ x += w + (i < r ? 1 : 0);
+ i++;
+ }
+ /* tiled mode */
+ } else {
+ den = clientsnmaster;
+ c = m->clients;
+ i = 0;
+ if (den) {
+ if (clientsnstack + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden) {
+ tgactive = masteractive;
+ num = tabw * m->mfact;
+ }
+ r = num % den;
+ w = num / den;
+ for (; c && i < m->nmaster; c = c->next) { // tiled master
+ if (!ISVISIBLE(c) || c->isfloating || HIDDEN(c))
+ continue;
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg);
+ x += w + (i < r ? 1 : 0);
+ i++;
+ }
+ tgactive = !tgactive;
+ num = tabw - num;
+ }
+
+ den = clientsnstack * BARTAB_STACKWEIGHT + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden * BARTAB_HIDDENWEIGHT;
+ if (!den)
+ return 1;
+
+ r = num % den;
+ w = num / den;
+ #if BARTAB_STACKWEIGHT
+ for (; c; c = c->next) { // tiled stack
+ if (!ISVISIBLE(c) || HIDDEN(c) || c->isfloating)
+ continue;
+ tabfn(m, c, passx, x, w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg);
+ x += w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0);
+ i++;
+ }
+ #endif // BARTAB_STACKWEIGHT
+
+ #if BARTAB_HIDDENWEIGHT
+ for (c = m->clients; c; c = c->next) { // hidden windows
+ if (!ISVISIBLE(c) || !HIDDEN(c))
+ continue;
+ tabfn(m, c, passx, x, w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg);
+ x += w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0);
+ i++;
+ }
+ #endif // BARTAB_HIDDENWEIGHT
+
+ #if BARTAB_FLOATWEIGHT
+ for (c = m->clients; c; c = c->next) { // floating windows
+ if (!ISVISIBLE(c) || HIDDEN(c) || !c->isfloating)
+ continue;
+ tabfn(m, c, passx, x, w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg);
+ x += w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0);
+ i++;
+ }
+ #endif // BARTAB_FLOATWEIGHT
+ }
+ return 1;
+}
+
diff --git a/patch/bar_tabgroups.h b/patch/bar_tabgroups.h
new file mode 100644
index 0000000..75a8512
--- /dev/null
+++ b/patch/bar_tabgroups.h
@@ -0,0 +1,8 @@
+static int width_bartabgroups(Bar *bar, BarArg *a);
+static int draw_bartabgroups(Bar *bar, BarArg *a);
+static int click_bartabgroups(Bar *bar, Arg *arg, BarArg *a);
+
+static void bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg);
+static void bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg);
+static int bartabcalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg);
+
diff --git a/patch/bar_taggrid.c b/patch/bar_taggrid.c
new file mode 100644
index 0000000..675c8de
--- /dev/null
+++ b/patch/bar_taggrid.c
@@ -0,0 +1,150 @@
+int
+width_taggrid(Bar *bar, BarArg *a)
+{
+ return (a->h / 2) * (NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0)) + lrpad;
+}
+
+int
+draw_taggrid(Bar *bar, BarArg *a)
+{
+ unsigned int x, y, h, max_x = 0, columns, occ = 0;
+ int invert, i,j, k;
+ Client *c;
+
+ for (c = bar->mon->clients; c; c = c->next)
+ occ |= c->tags;
+
+ max_x = x = a->x + lrpad / 2;
+ h = a->h / tagrows - 1;
+ y = a->y;
+ columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0);
+
+ /* Firstly we will fill the borders of squares */
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeTagsNorm][ColBg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x, y, h*columns + 1, a->h);
+
+ /* We will draw NUMTAGS squares in tagraws raws. */
+ for (j = 0, i = 0; j < tagrows; j++) {
+ x = a->x + lrpad / 2;
+ for (k = 0; k < columns; k++, i++) {
+ if (i < NUMTAGS) {
+ invert = bar->mon->tagset[bar->mon->seltags] & 1 << i ? 0 : 1;
+
+ /* Select active color for current square */
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeTagsSel][ColBg].pixel :
+ scheme[SchemeTagsNorm][ColFg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h-1);
+
+ /* Mark square if tag has client */
+ if (occ & 1 << i) {
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeTagsSel][ColFg].pixel :
+ scheme[SchemeTagsNorm][ColBg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x + 1, y + 1,
+ h / 2, h / 2);
+ }
+ } else {
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeTagsNorm][ColBg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h);
+ }
+ x += h;
+ if (x > max_x) {
+ max_x = x;
+ }
+ }
+ y += h;
+ }
+ return 1;
+}
+
+int
+click_taggrid(Bar *bar, Arg *arg, BarArg *a)
+{
+ unsigned int i, h, columns;
+
+ h = a->h / tagrows - 1;
+ columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0);
+ i = (a->x - lrpad / 2) / h + columns * (a->y / h);
+ if (i >= NUMTAGS) {
+ i = NUMTAGS - 1;
+ }
+ arg->ui = 1 << i;
+ return ClkTagBar;
+}
+
+void
+switchtag(const Arg *arg)
+{
+ unsigned int columns;
+ unsigned int new_tagset = 0;
+ unsigned int pos, i;
+ int col, row;
+ Arg new_arg;
+
+ columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0);
+
+ for (i = 0; i < NUMTAGS; ++i) {
+ if (!(selmon->tagset[selmon->seltags] & 1 << i)) {
+ continue;
+ }
+ pos = i;
+ row = pos / columns;
+ col = pos % columns;
+ if (arg->ui & SWITCHTAG_UP) { /* UP */
+ row --;
+ if (row < 0) {
+ row = tagrows - 1;
+ }
+ do {
+ pos = row * columns + col;
+ row --;
+ } while (pos >= NUMTAGS);
+ }
+ if (arg->ui & SWITCHTAG_DOWN) { /* DOWN */
+ row ++;
+ if (row >= tagrows) {
+ row = 0;
+ }
+ pos = row * columns + col;
+ if (pos >= NUMTAGS) {
+ row = 0;
+ }
+ pos = row * columns + col;
+ }
+ if (arg->ui & SWITCHTAG_LEFT) { /* LEFT */
+ col --;
+ if (col < 0) {
+ col = columns - 1;
+ }
+ do {
+ pos = row * columns + col;
+ col --;
+ } while (pos >= NUMTAGS);
+ }
+ if (arg->ui & SWITCHTAG_RIGHT) { /* RIGHT */
+ col ++;
+ if (col >= columns) {
+ col = 0;
+ }
+ pos = row * columns + col;
+ if (pos >= NUMTAGS) {
+ col = 0;
+ pos = row * columns + col;
+ }
+ }
+ new_tagset |= 1 << pos;
+ }
+ new_arg.ui = new_tagset;
+ if (arg->ui & SWITCHTAG_TOGGLETAG) {
+ toggletag(&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_TAG) {
+ tag(&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_VIEW) {
+ view (&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_TOGGLEVIEW) {
+ toggleview (&new_arg);
+ }
+}
+
diff --git a/patch/bar_taggrid.h b/patch/bar_taggrid.h
new file mode 100644
index 0000000..dfc60de
--- /dev/null
+++ b/patch/bar_taggrid.h
@@ -0,0 +1,5 @@
+static int width_taggrid(Bar *bar, BarArg *a);
+static int draw_taggrid(Bar *bar, BarArg *a);
+static int click_taggrid(Bar *bar, Arg *arg, BarArg *a);
+static void switchtag(const Arg *arg);
+
diff --git a/patch/bar_tagicons.c b/patch/bar_tagicons.c
new file mode 100644
index 0000000..235a6e2
--- /dev/null
+++ b/patch/bar_tagicons.c
@@ -0,0 +1,21 @@
+char *
+tagicon(Monitor *m, int tag)
+{
+ #if BAR_ALTTAGSDECORATION_PATCH
+ Client *c;
+ #endif // BAR_ALTTAGSDECORATION_PATCH
+ int tagindex = tag + NUMTAGS * m->index;
+ if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS]))
+ tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]);
+ #if BAR_ALTTAGSDECORATION_PATCH
+ for (c = m->clients; c && (!(c->tags & 1 << tag) || HIDDEN(c)); c = c->next);
+ if (c)
+ return tagicons[ALT_TAGS_DECORATION][tagindex];
+ #endif // BAR_ALTTAGSDECORATION_PATCH
+ #if BAR_ALTERNATIVE_TAGS_PATCH
+ if (m->alttag)
+ return tagicons[ALTERNATIVE_TAGS][tagindex];
+ #endif // BAR_ALTERNATIVE_TAGS_PATCH
+ 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..c00818d
--- /dev/null
+++ b/patch/bar_tags.c
@@ -0,0 +1,89 @@
+int
+width_tags(Bar *bar, BarArg *a)
+{
+ int w, i;
+ #if BAR_HIDEVACANTTAGS_PATCH
+ Client *c;
+ unsigned int occ = 0;
+ for (c = bar->mon->clients; c; c = c->next)
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ for (w = 0, i = 0; i < NUMTAGS; i++) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ 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) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #else
+ occ |= c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ if (c->isurgent)
+ urg |= c->tags;
+ }
+ for (i = 0; i < NUMTAGS; i++) {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ /* do not draw vacant tags */
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ 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 = lrpad / 2;
+ #if BAR_HIDEVACANTTAGS_PATCH
+ Client *c;
+ unsigned int occ = 0;
+ for (c = bar->mon->clients; c; c = c->next)
+ occ |= c->tags == 255 ? 0 : c->tags;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+
+ do {
+ #if BAR_HIDEVACANTTAGS_PATCH
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
+ continue;
+ #endif // BAR_HIDEVACANTTAGS_PATCH
+ x += TEXTW(tagicon(bar->mon, i));
+ } while (a->x >= x && ++i < NUMTAGS);
+ if (i < NUMTAGS) {
+ arg->ui = 1 << i;
+ }
+ return ClkTagBar;
+}
+
diff --git a/patch/bar_tags.h b/patch/bar_tags.h
new file mode 100644
index 0000000..9261261
--- /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);
+
diff --git a/patch/bar_vtcolors.c b/patch/bar_vtcolors.c
new file mode 100644
index 0000000..7c66e2d
--- /dev/null
+++ b/patch/bar_vtcolors.c
@@ -0,0 +1,69 @@
+void
+get_vt_colors(void)
+{
+ char *cfs[3] = {
+ "/sys/module/vt/parameters/default_red",
+ "/sys/module/vt/parameters/default_grn",
+ "/sys/module/vt/parameters/default_blu",
+ };
+ char vtcs[16][8];
+ char tk[] = ",";
+ char cl[64];
+ char *tp = NULL;
+ FILE *fp;
+ size_t r;
+ int i, c, n, len;
+ for (i = 0; i < 16; i++)
+ strcpy(vtcs[i], "#000000");
+
+ for (i = 0, r = 0; i < 3; i++) {
+ if ((fp = fopen(cfs[i], "r")) == NULL)
+ continue;
+ while ((cl[r] = fgetc(fp)) != EOF && cl[r] != '\n')
+ r++;
+ cl[r] = '\0';
+ for (c = 0, tp = cl, n = 0; c < 16; c++, tp++) {
+ if ((r = strcspn(tp, tk)) == -1)
+ break;
+ for (n = 0; r && *tp >= 48 && *tp < 58; r--, tp++)
+ n = n * 10 - 48 + *tp;
+ vtcs[c][i * 2 + 1] = n / 16 < 10 ? n / 16 + 48 : n / 16 + 87;
+ vtcs[c][i * 2 + 2] = n % 16 < 10 ? n % 16 + 48 : n % 16 + 87;
+ }
+ fclose(fp);
+ }
+
+ len = LENGTH(colors);
+ if (len > LENGTH(color_ptrs))
+ len = LENGTH(color_ptrs);
+ for (i = 0; i < len; i++) {
+ for (c = 0; c < ColCount; c++) {
+ n = color_ptrs[i][c];
+ if (n > -1 && strlen(colors[i][c]) >= strlen(vtcs[n]))
+ memcpy(colors[i][c], vtcs[n], 7);
+ }
+ }
+}
+
+int get_luminance(char *r)
+{
+ char *c = r;
+ int n[3] = {0};
+ int i = 0;
+
+ while (*c) {
+ if (*c >= 48 && *c < 58)
+ n[i / 2] = n[i / 2] * 16 - 48 + *c;
+ else if (*c >= 65 && *c < 71)
+ n[i / 2] = n[i / 2] * 16 - 55 + *c;
+ else if (*c >= 97 && *c < 103)
+ n[i / 2] = n[i / 2] * 16 - 87 + *c;
+ else
+ i--;
+ i++;
+ c++;
+ }
+
+ return (0.299 * n[0] + 0.587 * n[1] + 0.114 * n[2]) / 2.55;
+}
+
diff --git a/patch/bar_vtcolors.h b/patch/bar_vtcolors.h
new file mode 100644
index 0000000..8c5d6c1
--- /dev/null
+++ b/patch/bar_vtcolors.h
@@ -0,0 +1,3 @@
+static void get_vt_colors(void);
+static int get_luminance(char *rgb);
+
diff --git a/patch/bar_winicon.c b/patch/bar_winicon.c
new file mode 100644
index 0000000..5ae7fe7
--- /dev/null
+++ b/patch/bar_winicon.c
@@ -0,0 +1,146 @@
+static uint32_t tmpicon[ICONSIZE * ICONSIZE];
+
+static uint32_t prealpha(uint32_t p) {
+ uint8_t a = p >> 24u;
+ uint32_t rb = (a * (p & 0xFF00FFu)) >> 8u;
+ uint32_t g = (a * (p & 0x00FF00u)) >> 8u;
+ return (rb & 0xFF00FFu) | (g & 0x00FF00u) | ((~a) << 24u);
+}
+
+#if BAR_ALPHA_PATCH
+static uint8_t div255(uint16_t x) { return (x*0x8081u) >> 23u; }
+static uint32_t blend(uint32_t p1rb, uint32_t p1g, uint8_t p1a, uint32_t p2) {
+ uint8_t a = p2 >> 24u;
+ uint32_t rb = (p2 & 0xFF00FFu) + ( (a * p1rb) >> 8u );
+ uint32_t g = (p2 & 0x00FF00u) + ( (a * p1g) >> 8u );
+ return (rb & 0xFF00FFu) | (g & 0x00FF00u) | div255(~a * 255u + a * p1a) << 24u;
+}
+
+void
+drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp)
+{
+ if (!drw || !drw->scheme)
+ return;
+ uint32_t *data = (uint32_t *)img->data, p = drw->scheme[ColBg].pixel,
+ prb = p & 0xFF00FFu, pg = p & 0x00FF00u;
+ uint8_t pa = p >> 24u;
+ int icsz = img->width * img->height, i;
+ for (i = 0; i < icsz; ++i) tmp[i] = blend(prb, pg, pa, data[i]);
+
+ img->data = (char *) tmp;
+ XPutImage(drw->dpy, drw->drawable, drw->gc, img, 0, 0, x, y, img->width, img->height);
+ img->data = (char *) data;
+}
+#else
+static uint32_t blend(uint32_t p1rb, uint32_t p1g, uint32_t p2) {
+ uint8_t a = p2 >> 24u;
+ uint32_t rb = (p2 & 0xFF00FFu) + ( (a * p1rb) >> 8u );
+ uint32_t g = (p2 & 0x00FF00u) + ( (a * p1g) >> 8u );
+ return (rb & 0xFF00FFu) | (g & 0x00FF00u) | ((~a) << 24u);
+}
+
+void
+drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp)
+{
+ if (!drw || !drw->scheme)
+ return;
+ uint32_t *data = (uint32_t *)img->data, p = drw->scheme[ColBg].pixel, prb = p & 0xFF00FFu, pg = p & 0x00FF00u;
+ int icsz = img->width * img->height, i;
+ for (i = 0; i < icsz; ++i) tmp[i] = blend(prb, pg, data[i]);
+ img->data = (char *) tmp;
+ XPutImage(drw->dpy, drw->drawable, drw->gc, img, 0, 0, x, y, img->width, img->height);
+ img->data = (char *) data;
+}
+#endif // BAR_ALPHA_PATCH
+
+XImage *
+geticonprop(Window win)
+{
+ int format;
+ unsigned long n, extra, *p = NULL;
+ Atom real;
+
+ if (XGetWindowProperty(dpy, win, netatom[NetWMIcon], 0L, LONG_MAX, False, AnyPropertyType,
+ &real, &format, &n, &extra, (unsigned char **)&p) != Success)
+ return NULL;
+ if (n == 0 || format != 32) { XFree(p); return NULL; }
+
+ unsigned long *bstp = NULL;
+ uint32_t w, h, sz;
+
+ {
+ const unsigned long *end = p + n;
+ unsigned long *i;
+ uint32_t bstd = UINT32_MAX, d, m;
+ for (i = p; i < end - 1; i += sz) {
+ if ((w = *i++) > UINT16_MAX || (h = *i++) > UINT16_MAX) { XFree(p); return NULL; }
+ if ((sz = w * h) > end - i) break;
+ if ((m = w > h ? w : h) >= ICONSIZE && (d = m - ICONSIZE) < bstd) { bstd = d; bstp = i; }
+ }
+ if (!bstp) {
+ for (i = p; i < end - 1; i += sz) {
+ if ((w = *i++) > UINT16_MAX || (h = *i++) > UINT16_MAX) { XFree(p); return NULL; }
+ if ((sz = w * h) > end - i) break;
+ if ((d = ICONSIZE - (w > h ? w : h)) < bstd) { bstd = d; bstp = i; }
+ }
+ }
+ if (!bstp) { XFree(p); return NULL; }
+ }
+
+ if ((w = *(bstp - 2)) == 0 || (h = *(bstp - 1)) == 0) { XFree(p); return NULL; }
+
+ uint32_t icw, ich, icsz;
+ if (w <= h) {
+ ich = ICONSIZE; icw = w * ICONSIZE / h;
+ if (icw == 0) icw = 1;
+ }
+ else {
+ icw = ICONSIZE; ich = h * ICONSIZE / w;
+ if (ich == 0) ich = 1;
+ }
+ icsz = icw * ich;
+
+ uint32_t i;
+#if ULONG_MAX > UINT32_MAX
+ uint32_t *bstp32 = (uint32_t *)bstp;
+ for (sz = w * h, i = 0; i < sz; ++i) bstp32[i] = bstp[i];
+#endif
+ uint32_t *icbuf = malloc(icsz << 2); if(!icbuf) { XFree(p); return NULL; }
+ if (w == icw && h == ich) memcpy(icbuf, bstp, icsz << 2);
+ else {
+ Imlib_Image origin = imlib_create_image_using_data(w, h, (DATA32 *)bstp);
+ if (!origin) { XFree(p); free(icbuf); return NULL; }
+ imlib_context_set_image(origin);
+ imlib_image_set_has_alpha(1);
+ Imlib_Image scaled = imlib_create_cropped_scaled_image(0, 0, w, h, icw, ich);
+ imlib_free_image_and_decache();
+ if (!scaled) { XFree(p); free(icbuf); return NULL; }
+ imlib_context_set_image(scaled);
+ imlib_image_set_has_alpha(1);
+ memcpy(icbuf, imlib_image_get_data_for_reading_only(), icsz << 2);
+ imlib_free_image_and_decache();
+ }
+ XFree(p);
+ for (i = 0; i < icsz; ++i) icbuf[i] = prealpha(icbuf[i]);
+ #if BAR_ALPHA_PATCH
+ return XCreateImage(dpy, drw->visual, drw->depth, ZPixmap, 0, (char *)icbuf, icw, ich, 32, 0);
+ #else
+ return XCreateImage(dpy, DefaultVisual(dpy, screen), DefaultDepth(dpy, screen), ZPixmap, 0, (char *)icbuf, icw, ich, 32, 0);
+ #endif // BAR_ALPHA_PATCH
+}
+
+void
+freeicon(Client *c)
+{
+ if (c->icon) {
+ XDestroyImage(c->icon);
+ c->icon = NULL;
+ }
+}
+
+void
+updateicon(Client *c)
+{
+ freeicon(c);
+ c->icon = geticonprop(c->win);
+} \ No newline at end of file
diff --git a/patch/bar_winicon.h b/patch/bar_winicon.h
new file mode 100644
index 0000000..791182e
--- /dev/null
+++ b/patch/bar_winicon.h
@@ -0,0 +1,8 @@
+#include <Imlib2.h>
+#include <limits.h>
+#include <stdint.h>
+
+void drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp);
+static XImage *geticonprop(Window win);
+static void freeicon(Client *c);
+static void updateicon(Client *c); \ No newline at end of file
diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c
new file mode 100644
index 0000000..d2241d2
--- /dev/null
+++ b/patch/bar_wintitle.c
@@ -0,0 +1,59 @@
+int
+width_wintitle(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_wintitle(Bar *bar, BarArg *a)
+{
+ #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad;
+ #elif BAR_TITLE_LEFT_PAD_PATCH
+ int x = a->x + lrpad / 2, w = a->w - lrpad / 2;
+ #elif BAR_TITLE_RIGHT_PAD_PATCH
+ int x = a->x, w = a->w - lrpad / 2;
+ #else
+ int x = a->x, w = a->w;
+ #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH
+ Monitor *m = bar->mon;
+ Client *c = m->sel;
+ int pad = lrpad / 2;
+
+ if (!c) {
+ drw_setscheme(drw, scheme[SchemeTitleNorm]);
+ drw_rect(drw, x, a->y, w, a->h, 1, 1);
+ return 0;
+ }
+
+ drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]);
+ #if BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
+ XSetErrorHandler(xerrordummy);
+ #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
+ #if BAR_CENTEREDWINDOWNAME_PATCH
+ if (TEXTW(c->name) < w)
+ pad = (w - TEXTW(c->name) + lrpad) / 2;
+ #endif // BAR_CENTEREDWINDOWNAME_PATCH
+
+ #if BAR_WINICON_PATCH
+ drw_text(drw, x, a->y, w, a->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False);
+ if (c->icon)
+ drw_img(drw, x + pad, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon);
+ #else
+ drw_text(drw, x, a->y, w, a->h, pad, c->name, 0, False);
+ #endif // BAR_WINICON_PATCH
+
+ #if BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
+ 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/bar_wintitle_floating.c b/patch/bar_wintitle_floating.c
new file mode 100644
index 0000000..3a15b8e
--- /dev/null
+++ b/patch/bar_wintitle_floating.c
@@ -0,0 +1,46 @@
+int
+width_wintitle_floating(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_wintitle_floating(Bar *bar, BarArg *a)
+{
+ drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1);
+ return calc_wintitle_floating(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a);
+}
+
+int
+click_wintitle_floating(Bar *bar, Arg *arg, BarArg *a)
+{
+ calc_wintitle_floating(bar->mon, 0, a->w, a->x, flextitleclick, arg, a);
+ return ClkWinTitle;
+}
+
+int
+calc_wintitle_floating(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+) {
+ Client *c;
+ int clientsnfloating = 0, w, r;
+ int groupactive = GRP_FLOAT;
+
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ if (c->isfloating)
+ clientsnfloating++;
+ }
+
+ if (!clientsnfloating)
+ return 0;
+
+ w = tabw / clientsnfloating;
+ r = tabw % clientsnfloating;
+ c = flextitledrawarea(m, m->clients, offx, r, w, clientsnfloating, SCHEMEFOR(GRP_FLOAT), 0, 0, 1, passx, tabfn, arg, barg);
+ return 1;
+}
+
diff --git a/patch/bar_wintitle_floating.h b/patch/bar_wintitle_floating.h
new file mode 100644
index 0000000..e73d53a
--- /dev/null
+++ b/patch/bar_wintitle_floating.h
@@ -0,0 +1,9 @@
+static int width_wintitle_floating(Bar *bar, BarArg *a);
+static int draw_wintitle_floating(Bar *bar, BarArg *a);
+static int click_wintitle_floating(Bar *bar, Arg *arg, BarArg *a);
+static int calc_wintitle_floating(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+);
+
diff --git a/patch/bar_wintitle_hidden.c b/patch/bar_wintitle_hidden.c
new file mode 100644
index 0000000..2d2414c
--- /dev/null
+++ b/patch/bar_wintitle_hidden.c
@@ -0,0 +1,46 @@
+int
+width_wintitle_hidden(Bar *bar, BarArg *a)
+{
+ return a->w;
+}
+
+int
+draw_wintitle_hidden(Bar *bar, BarArg *a)
+{
+ drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1);
+ return calc_wintitle_hidden(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a);
+}
+
+int
+click_wintitle_hidden(Bar *bar, Arg *arg, BarArg *a)
+{
+ calc_wintitle_hidden(bar->mon, 0, a->w, a->x, flextitleclick, arg, a);
+ return ClkWinTitle;
+}
+
+int
+calc_wintitle_hidden(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+) {
+ Client *c;
+ int clientsnhidden = 0, w, r;
+ int groupactive = GRP_HIDDEN;
+
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ if (HIDDEN(c))
+ clientsnhidden++;
+ }
+
+ if (!clientsnhidden)
+ return 0;
+
+ w = tabw / clientsnhidden;
+ r = tabw % clientsnhidden;
+ c = flextitledrawarea(m, m->clients, offx, r, w, clientsnhidden, SCHEMEFOR(GRP_HIDDEN), 0, 1, 0, passx, tabfn, arg, barg);
+ return 1;
+}
+
diff --git a/patch/bar_wintitle_hidden.h b/patch/bar_wintitle_hidden.h
new file mode 100644
index 0000000..0495d49
--- /dev/null
+++ b/patch/bar_wintitle_hidden.h
@@ -0,0 +1,9 @@
+static int width_wintitle_hidden(Bar *bar, BarArg *a);
+static int draw_wintitle_hidden(Bar *bar, BarArg *a);
+static int click_wintitle_hidden(Bar *bar, Arg *arg, BarArg *a);
+static int calc_wintitle_hidden(
+ Monitor *m, int offx, int tabw, int passx,
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg),
+ Arg *arg, BarArg *barg
+);
+
diff --git a/patch/bar_wintitleactions.c b/patch/bar_wintitleactions.c
new file mode 100644
index 0000000..61a5d21
--- /dev/null
+++ b/patch/bar_wintitleactions.c
@@ -0,0 +1,94 @@
+void
+hide(Client *c) {
+
+ Client *n;
+ if (!c || HIDDEN(c))
+ return;
+
+ Window w = c->win;
+ static XWindowAttributes ra, ca;
+
+ // more or less taken directly from blackbox's hide() function
+ XGrabServer(dpy);
+ XGetWindowAttributes(dpy, root, &ra);
+ XGetWindowAttributes(dpy, w, &ca);
+ // prevent UnmapNotify events
+ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
+ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, w);
+ setclientstate(c, IconicState);
+ XSelectInput(dpy, root, ra.your_event_mask);
+ XSelectInput(dpy, w, ca.your_event_mask);
+ XUngrabServer(dpy);
+
+ if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+ for (n = c->snext; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext);
+ if (!n)
+ for (n = c->mon->stack; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext);
+ } else {
+ n = nexttiled(c);
+ if (!n)
+ n = prevtiled(c);
+ }
+ focus(n);
+ arrange(c->mon);
+}
+
+void
+show(Client *c)
+{
+ if (!c || !HIDDEN(c))
+ return;
+
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+ arrange(c->mon);
+}
+
+void
+togglewin(const Arg *arg)
+{
+ Client *c = (Client*)arg->v;
+ if (!c)
+ return;
+ if (c == selmon->sel)
+ hide(c);
+ else {
+ if (HIDDEN(c))
+ show(c);
+ focus(c);
+ restack(c->mon);
+ }
+}
+
+Client *
+prevtiled(Client *c)
+{
+ Client *p, *i;
+ for (p = NULL, i = c->mon->clients; c && i != c; i = i->next)
+ if (ISVISIBLE(i) && !HIDDEN(i))
+ p = i;
+ return p;
+}
+
+void
+showhideclient(const Arg *arg)
+{
+ Client *c = (Client*)arg->v;
+ if (!c)
+ c = selmon->sel;
+ if (!c)
+ return;
+
+ #if WARP_PATCH
+ force_warp = 1;
+ #endif // WARP_PATCH
+ if (HIDDEN(c)) {
+ show(c);
+ focus(c);
+ restack(c->mon);
+ } else {
+ hide(c);
+ }
+}
+
diff --git a/patch/bar_wintitleactions.h b/patch/bar_wintitleactions.h
new file mode 100644
index 0000000..0c8d5f0
--- /dev/null
+++ b/patch/bar_wintitleactions.h
@@ -0,0 +1,6 @@
+static void hide(Client *c);
+static void show(Client *c);
+static void togglewin(const Arg *arg);
+static Client * prevtiled(Client *c);
+static void showhideclient(const Arg *arg);
+
diff --git a/patch/cfacts.c b/patch/cfacts.c
new file mode 100644
index 0000000..e491a41
--- /dev/null
+++ b/patch/cfacts.c
@@ -0,0 +1,24 @@
+void
+setcfact(const Arg *arg)
+{
+ float f;
+ Client *c;
+
+ c = selmon->sel;
+
+ if (!arg || !c || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ if (!arg->f)
+ f = 1.0;
+ else if (arg->f > 4.0) // set fact absolutely
+ f = arg->f - 4.0;
+ else
+ f = arg->f + c->cfact;
+ if (f < 0.25)
+ f = 0.25;
+ else if (f > 4.0)
+ f = 4.0;
+ c->cfact = f;
+ arrange(selmon);
+}
+
diff --git a/patch/cfacts.h b/patch/cfacts.h
new file mode 100644
index 0000000..97f9f1c
--- /dev/null
+++ b/patch/cfacts.h
@@ -0,0 +1,2 @@
+static void setcfact(const Arg *arg);
+
diff --git a/patch/cmdcustomize.c b/patch/cmdcustomize.c
new file mode 100644
index 0000000..9769660
--- /dev/null
+++ b/patch/cmdcustomize.c
@@ -0,0 +1,6 @@
+char*
+help(void)
+{
+ return "usage: dwm [-hv] [-fn font] [-nb color] [-nf color] [-sb color] [-sf color]\n[-df font] [-dnf color] [-dnb color] [-dsf color] [-dsb color]\n";
+}
+
diff --git a/patch/cmdcustomize.h b/patch/cmdcustomize.h
new file mode 100644
index 0000000..46b75cf
--- /dev/null
+++ b/patch/cmdcustomize.h
@@ -0,0 +1,2 @@
+static char* help();
+
diff --git a/patch/combo.c b/patch/combo.c
new file mode 100644
index 0000000..058b1f9
--- /dev/null
+++ b/patch/combo.c
@@ -0,0 +1,50 @@
+static int combo = 0;
+
+#if !BAR_HOLDBAR_PATCH
+void
+keyrelease(XEvent *e)
+{
+ combo = 0;
+}
+#endif // !BAR_HOLDBAR_PATCH
+
+void
+combotag(const Arg *arg)
+{
+ if (selmon->sel && arg->ui & TAGMASK) {
+ #if SWITCHTAG_PATCH
+ if (selmon->sel->switchtag)
+ selmon->sel->switchtag = 0;
+ #endif // SWITCHTAG_PATCH
+ if (combo) {
+ selmon->sel->tags |= arg->ui & TAGMASK;
+ } else {
+ combo = 1;
+ selmon->sel->tags = arg->ui & TAGMASK;
+ }
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+comboview(const Arg *arg)
+{
+ unsigned newtags = arg->ui & TAGMASK;
+ if (combo) {
+ selmon->tagset[selmon->seltags] |= newtags;
+ } else {
+ selmon->seltags ^= 1; /*toggle tagset*/
+ combo = 1;
+ if (newtags) {
+ #if PERTAG_PATCH
+ pertagview(&((Arg) { .ui = newtags }));
+ #else
+ selmon->tagset[selmon->seltags] = newtags;
+ #endif // PERTAG_PATCH
+ }
+ }
+ focus(NULL);
+ arrange(selmon);
+}
+
diff --git a/patch/combo.h b/patch/combo.h
new file mode 100644
index 0000000..0c42136
--- /dev/null
+++ b/patch/combo.h
@@ -0,0 +1,6 @@
+#if !BAR_HOLDBAR_PATCH
+static void keyrelease(XEvent *e);
+#endif // !BAR_HOLDBAR_PATCH
+static void combotag(const Arg *arg);
+static void comboview(const Arg *arg);
+
diff --git a/patch/cool_autostart.c b/patch/cool_autostart.c
new file mode 100644
index 0000000..ffd4ba3
--- /dev/null
+++ b/patch/cool_autostart.c
@@ -0,0 +1,29 @@
+/* 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;
+ 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();
+ 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/cyclelayouts.c b/patch/cyclelayouts.c
new file mode 100644
index 0000000..81339bc
--- /dev/null
+++ b/patch/cyclelayouts.c
@@ -0,0 +1,18 @@
+void
+cyclelayout(const Arg *arg)
+{
+ Layout *l;
+ for (l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++);
+ if (arg->i > 0) {
+ if (l->symbol && (l + 1)->symbol)
+ setlayout(&((Arg) { .v = (l + 1) }));
+ else
+ setlayout(&((Arg) { .v = layouts }));
+ } else {
+ if (l != layouts && (l - 1)->symbol)
+ setlayout(&((Arg) { .v = (l - 1) }));
+ else
+ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] }));
+ }
+}
+
diff --git a/patch/cyclelayouts.h b/patch/cyclelayouts.h
new file mode 100644
index 0000000..3647d88
--- /dev/null
+++ b/patch/cyclelayouts.h
@@ -0,0 +1,2 @@
+static void cyclelayout(const Arg *arg);
+
diff --git a/patch/decorationhints.c b/patch/decorationhints.c
new file mode 100644
index 0000000..78be5ea
--- /dev/null
+++ b/patch/decorationhints.c
@@ -0,0 +1,39 @@
+static Atom motifatom;
+
+void
+updatemotifhints(Client *c)
+{
+ Atom real;
+ int format;
+ unsigned char *p = NULL;
+ unsigned long n, extra;
+ unsigned long *motif;
+ int width, height;
+
+ if (!decorhints)
+ return;
+
+ if (XGetWindowProperty(dpy, c->win, motifatom, 0L, 5L, False, motifatom,
+ &real, &format, &n, &extra, &p) == Success && p != NULL) {
+ motif = (unsigned long*)p;
+ if (motif[MWM_HINTS_FLAGS_FIELD] & MWM_HINTS_DECORATIONS) {
+ width = WIDTH(c);
+ height = HEIGHT(c);
+
+ if (motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_ALL ||
+ motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_BORDER ||
+ motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_TITLE)
+ #if SETBORDERPX_PATCH
+ c->bw = c->oldbw = c->mon->borderpx;
+ #else
+ c->bw = c->oldbw = borderpx;
+ #endif // SETBORDERPX_PATCH
+ else
+ c->bw = c->oldbw = 0;
+
+ resize(c, c->x, c->y, width - (2*c->bw), height - (2*c->bw), 0);
+ }
+ XFree(p);
+ }
+}
+
diff --git a/patch/decorationhints.h b/patch/decorationhints.h
new file mode 100644
index 0000000..e28f507
--- /dev/null
+++ b/patch/decorationhints.h
@@ -0,0 +1,9 @@
+#define MWM_HINTS_FLAGS_FIELD 0
+#define MWM_HINTS_DECORATIONS_FIELD 2
+#define MWM_HINTS_DECORATIONS (1 << 1)
+#define MWM_DECOR_ALL (1 << 0)
+#define MWM_DECOR_BORDER (1 << 1)
+#define MWM_DECOR_TITLE (1 << 3)
+
+static void updatemotifhints(Client *c);
+
diff --git a/patch/distributetags.c b/patch/distributetags.c
new file mode 100644
index 0000000..284b24c
--- /dev/null
+++ b/patch/distributetags.c
@@ -0,0 +1,17 @@
+void
+distributetags(const Arg *arg)
+{
+ unsigned int ui = 1;
+ int i = 0;
+ for (Client *c = selmon->clients; c; c = c->next) {
+ if (HIDDEN(c))
+ continue;
+ if (!(c->tags & TAGMASK))
+ continue;
+ c->tags = (ui << i) & TAGMASK;
+ i = (i + 1) % NUMTAGS;
+ }
+ focus(NULL);
+ arrange(selmon);
+}
+
diff --git a/patch/distributetags.h b/patch/distributetags.h
new file mode 100644
index 0000000..3b276d9
--- /dev/null
+++ b/patch/distributetags.h
@@ -0,0 +1,2 @@
+static void distributetags(const Arg *arg);
+
diff --git a/patch/dragcfact.c b/patch/dragcfact.c
new file mode 100644
index 0000000..1b14513
--- /dev/null
+++ b/patch/dragcfact.c
@@ -0,0 +1,83 @@
+void
+dragcfact(const Arg *arg)
+{
+ int prev_x, prev_y, dist_x, dist_y;
+ float fact;
+ Client *c;
+ XEvent ev;
+ Time lasttime = 0;
+
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfloating) {
+ resizemouse(arg);
+ return;
+ }
+ #if !FAKEFULLSCREEN_PATCH
+ #if FAKEFULLSCREEN_CLIENT_PATCH
+ if (c->isfullscreen && !c->fakefullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ #else
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+ #endif // !FAKEFULLSCREEN_PATCH
+ restack(selmon);
+
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurIronCross]->cursor, CurrentTime) != GrabSuccess)
+ return;
+
+ #if WARP_PATCH
+ ignore_warp = 1;
+ #endif // WARP_PATCH
+
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
+
+ prev_x = prev_y = -999999;
+
+ 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;
+ if (prev_x == -999999) {
+ prev_x = ev.xmotion.x_root;
+ prev_y = ev.xmotion.y_root;
+ }
+
+ dist_x = ev.xmotion.x - prev_x;
+ dist_y = ev.xmotion.y - prev_y;
+
+ if (abs(dist_x) > abs(dist_y)) {
+ fact = (float) 4.0 * dist_x / c->mon->ww;
+ } else {
+ fact = (float) -4.0 * dist_y / c->mon->wh;
+ }
+
+ if (fact)
+ setcfact(&((Arg) { .f = fact }));
+
+ prev_x = ev.xmotion.x;
+ prev_y = ev.xmotion.y;
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+
+ #if WARP_PATCH
+ ignore_warp = 0;
+ #endif // WARP_PATCH
+
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
+
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
diff --git a/patch/dragcfact.h b/patch/dragcfact.h
new file mode 100644
index 0000000..6a29783
--- /dev/null
+++ b/patch/dragcfact.h
@@ -0,0 +1,2 @@
+static void dragcfact(const Arg *arg);
+
diff --git a/patch/dragmfact.c b/patch/dragmfact.c
new file mode 100644
index 0000000..ee0ed9c
--- /dev/null
+++ b/patch/dragmfact.c
@@ -0,0 +1,232 @@
+void
+dragmfact(const Arg *arg)
+{
+ unsigned int n;
+ int py, px; // pointer coordinates
+ int ax, ay, aw, ah; // area position, width and height
+ int center = 0, horizontal = 0, mirror = 0, fixed = 0; // layout configuration
+ double fact;
+ Monitor *m;
+ XEvent ev;
+ Time lasttime = 0;
+
+ m = selmon;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ Client *c;
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ ax = m->wx;
+ ay = m->wy;
+ ah = m->wh;
+ aw = m->ww;
+
+ if (!n)
+ return;
+ #if FLEXTILE_DELUXE_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &flextile) {
+ int layout = m->ltaxis[LAYOUT];
+ if (layout < 0) {
+ mirror = 1;
+ layout *= -1;
+ }
+ if (layout > FLOATING_MASTER) {
+ layout -= FLOATING_MASTER;
+ fixed = 1;
+ }
+
+ if (layout == SPLIT_HORIZONTAL || layout == SPLIT_HORIZONTAL_DUAL_STACK)
+ horizontal = 1;
+ else if (layout == SPLIT_CENTERED_VERTICAL && (fixed || n - m->nmaster > 1))
+ center = 1;
+ else if (layout == FLOATING_MASTER) {
+ center = 1;
+ if (aw < ah)
+ horizontal = 1;
+ }
+ else if (layout == SPLIT_CENTERED_HORIZONTAL) {
+ if (fixed || n - m->nmaster > 1)
+ center = 1;
+ horizontal = 1;
+ }
+ }
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ #if CENTEREDMASTER_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &centeredmaster && (fixed || n - m->nmaster > 1))
+ center = 1;
+ #endif // CENTEREDMASTER_LAYOUT
+ #if CENTEREDFLOATINGMASTER_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &centeredfloatingmaster)
+ center = 1;
+ #endif // CENTEREDFLOATINGMASTER_LAYOUT
+ #if BSTACK_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &bstack)
+ horizontal = 1;
+ #endif // BSTACK_LAYOUT
+ #if BSTACKHORIZ_LAYOUT
+ else if (m->lt[m->sellt]->arrange == &bstackhoriz)
+ horizontal = 1;
+ #endif // BSTACKHORIZ_LAYOUT
+
+ /* do not allow mfact to be modified under certain conditions */
+ if (!m->lt[m->sellt]->arrange // floating layout
+ || (!fixed && m->nmaster && n <= m->nmaster) // no master
+ #if MONOCLE_LAYOUT
+ || m->lt[m->sellt]->arrange == &monocle
+ #endif // MONOCLE_LAYOUT
+ #if GRIDMODE_LAYOUT
+ || m->lt[m->sellt]->arrange == &grid
+ #endif // GRIDMODE_LAYOUT
+ #if HORIZGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &horizgrid
+ #endif // HORIZGRID_LAYOUT
+ #if GAPPLESSGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &gaplessgrid
+ #endif // GAPPLESSGRID_LAYOUT
+ #if NROWGRID_LAYOUT
+ || m->lt[m->sellt]->arrange == &nrowgrid
+ #endif // NROWGRID_LAYOUT
+ #if FLEXTILE_DELUXE_LAYOUT
+ || (m->lt[m->sellt]->arrange == &flextile && m->ltaxis[LAYOUT] == NO_SPLIT)
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ )
+ return;
+
+ #if VANITYGAPS_PATCH
+ ay += oh;
+ ax += ov;
+ aw -= 2*ov;
+ ah -= 2*oh;
+ #endif // VANITYGAPS_PATCH
+
+ if (center) {
+ if (horizontal) {
+ px = ax + aw / 2;
+ #if VANITYGAPS_PATCH
+ py = ay + ah / 2 + (ah - 2*ih) * (m->mfact / 2.0) + ih / 2;
+ #else
+ py = ay + ah / 2 + ah * m->mfact / 2.0;
+ #endif // VANITYGAPS_PATCH
+ } else { // vertical split
+ #if VANITYGAPS_PATCH
+ px = ax + aw / 2 + (aw - 2*iv) * m->mfact / 2.0 + iv / 2;
+ #else
+ px = ax + aw / 2 + aw * m->mfact / 2.0;
+ #endif // VANITYGAPS_PATCH
+ py = ay + ah / 2;
+ }
+ } else if (horizontal) {
+ px = ax + aw / 2;
+ if (mirror)
+ #if VANITYGAPS_PATCH
+ py = ay + (ah - ih) * (1.0 - m->mfact) + ih / 2;
+ #else
+ py = ay + (ah * (1.0 - m->mfact));
+ #endif // VANITYGAPS_PATCH
+ else
+ #if VANITYGAPS_PATCH
+ py = ay + ((ah - ih) * m->mfact) + ih / 2;
+ #else
+ py = ay + (ah * m->mfact);
+ #endif // VANITYGAPS_PATCH
+ } else { // vertical split
+ if (mirror)
+ #if VANITYGAPS_PATCH
+ px = ax + (aw - iv) * (1.0 - m->mfact) + iv / 2;
+ #else
+ px = ax + (aw * m->mfact);
+ #endif // VANITYGAPS_PATCH
+ else
+ #if VANITYGAPS_PATCH
+ px = ax + ((aw - iv) * m->mfact) + iv / 2;
+ #else
+ px = ax + (aw * m->mfact);
+ #endif // VANITYGAPS_PATCH
+ py = ay + ah / 2;
+ }
+
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[horizontal ? CurResizeVertArrow : CurResizeHorzArrow]->cursor, CurrentTime) != GrabSuccess)
+ return;
+
+ #if WARP_PATCH
+ ignore_warp = 1;
+ #endif // WARP_PATCH
+
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, px, py);
+
+ 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 / 40))
+ continue;
+ if (lasttime != 0) {
+ px = ev.xmotion.x;
+ py = ev.xmotion.y;
+ }
+ lasttime = ev.xmotion.time;
+
+ #if VANITYGAPS_PATCH
+ if (center)
+ if (horizontal)
+ if (py - ay > ah / 2)
+ fact = (double) 1.0 - (ay + ah - py - ih / 2) * 2 / (double) (ah - 2*ih);
+ else
+ fact = (double) 1.0 - (py - ay - ih / 2) * 2 / (double) (ah - 2*ih);
+ else
+ if (px - ax > aw / 2)
+ fact = (double) 1.0 - (ax + aw - px - iv / 2) * 2 / (double) (aw - 2*iv);
+ else
+ fact = (double) 1.0 - (px - ax - iv / 2) * 2 / (double) (aw - 2*iv);
+ else
+ if (horizontal)
+ fact = (double) (py - ay - ih / 2) / (double) (ah - ih);
+ else
+ fact = (double) (px - ax - iv / 2) / (double) (aw - iv);
+ #else
+ if (center)
+ if (horizontal)
+ if (py - ay > ah / 2)
+ fact = (double) 1.0 - (ay + ah - py) * 2 / (double) ah;
+ else
+ fact = (double) 1.0 - (py - ay) * 2 / (double) ah;
+ else
+ if (px - ax > aw / 2)
+ fact = (double) 1.0 - (ax + aw - px) * 2 / (double) aw;
+ else
+ fact = (double) 1.0 - (px - ax) * 2 / (double) aw;
+ else
+ if (horizontal)
+ fact = (double) (py - ay) / (double) ah;
+ else
+ fact = (double) (px - ax) / (double) aw;
+ #endif // VANITYGAPS_PATCH
+
+ if (!center && mirror)
+ fact = 1.0 - fact;
+
+ setmfact(&((Arg) { .f = 1.0 + fact }));
+ px = ev.xmotion.x;
+ py = ev.xmotion.y;
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+
+ #if WARP_PATCH
+ ignore_warp = 0;
+ #endif // WARP_PATCH
+
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
diff --git a/patch/dragmfact.h b/patch/dragmfact.h
new file mode 100644
index 0000000..a67432a
--- /dev/null
+++ b/patch/dragmfact.h
@@ -0,0 +1,2 @@
+static void dragmfact(const Arg *arg);
+
diff --git a/patch/dwmc b/patch/dwmc
new file mode 100755
index 0000000..3880428
--- /dev/null
+++ b/patch/dwmc
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+
+signal() {
+ xsetroot -name "fsignal:$*"
+}
+
+case $# in
+1)
+ case $1 in
+ focusurgent) ;&
+ mirrorlayout) ;&
+ mpdcontrol) ;&
+ pushdown) ;&
+ pushup) ;&
+ self_restart) ;&
+ setlayout) ;&
+ setcfact) ;&
+ switchcol) ;&
+ view) ;&
+ viewall) ;&
+ viewtoleft) ;&
+ viewtoright) ;&
+ tagtoleft) ;&
+ tagtoright) ;&
+ tagandviewtoleft) ;&
+ tagandviewtoright) ;&
+ transfer) ;&
+ transferall) ;&
+ togglealttag) ;&
+ togglebar) ;&
+ togglefloating) ;&
+ togglefullscreen) ;&
+ fullscreen) ;&
+ togglefakefullscreen) ;&
+ togglesticky) ;&
+ togglehorizontalmax) ;&
+ toggleverticalmax) ;&
+ togglemax) ;&
+ togglegaps) ;&
+ defaultgaps) ;&
+ unfloatvisible) ;&
+ winview) ;&
+ xrdb) ;&
+ zoom) ;&
+ killclient) ;&
+ quit)
+ signal $1
+ ;;
+ *)
+ echo "Unknown command ($1) or missing one argument."
+ exit 1
+ ;;
+ esac
+ ;;
+2)
+ case $1 in
+ cyclelayout) ;&
+ explace) ;&
+ moveplace) ;&
+ mpdchange) ;&
+ setkeymode) ;&
+ switchtag) ;&
+ togglescratch) ;&
+ view)
+ signal $1 ui $2
+ ;;
+ viewex) ;&
+ toggleviewex) ;&
+ tagallmon) ;&
+ tagswapmon) ;&
+ tagex) ;&
+ toggletagex) ;&
+ setborderpx) ;&
+ setgaps) ;&
+ setlayoutex) ;&
+ setlayoutaxisex) ;&
+ swapfocus) ;&
+ focusstack) ;&
+ pushstack) ;&
+ inplacerotate) ;&
+ rotatestack) ;&
+ rotatelayoutaxis) ;&
+ incnmaster) ;&
+ incnstack) ;&
+ incrgaps) ;&
+ incrigaps) ;&
+ incrogaps) ;&
+ incrihgaps) ;&
+ incrivgaps) ;&
+ incrohgaps) ;&
+ incrovgaps) ;&
+ movestack) ;&
+ shiftview) ;&
+ shiftviewclients) ;&
+ focusmon) ;&
+ tagmon)
+ signal $1 i $2
+ ;;
+ setcfact) ;&
+ setmfact)
+ signal $1 f $2
+ ;;
+ *)
+ echo "Unknown command ($1) or too many arguments"
+ exit 1
+ ;;
+ esac
+ ;;
+5)
+ case $1 in
+ setgaps)
+ # Expects "setgaps oh ov ih iv" where -1 means to keep existing values
+ [ $2 = -1 ] && oh=128 || oh=$2
+ [ $3 = -1 ] && ov=128 || ov=$3
+ [ $4 = -1 ] && ih=128 || ih=$4
+ [ $5 = -1 ] && iv=128 || iv=$5
+ signal $1 i $(((oh << 24) + (ov << 16) + (ih << 8) + iv))
+ ;;
+ *)
+ echo "Unknown command ($1) or too many arguments"
+ exit 1
+ ;;
+ esac
+ ;;
+*)
+ echo "Unknown command ($1) or too many arguments"
+ exit 1
+ ;;
+esac
+
diff --git a/patch/dwmc.c b/patch/dwmc.c
new file mode 100644
index 0000000..b515f87
--- /dev/null
+++ b/patch/dwmc.c
@@ -0,0 +1,101 @@
+void
+setlayoutex(const Arg *arg)
+{
+ setlayout(&((Arg) { .v = &layouts[arg->i] }));
+}
+
+void
+viewex(const Arg *arg)
+{
+ view(&((Arg) { .ui = 1 << arg->ui }));
+}
+
+void
+viewallex(const Arg *arg)
+{
+ #if SCRATCHPADS_PATCH
+ view(&((Arg){.ui = ~SPTAGMASK}));
+ #else
+ view(&((Arg){.ui = ~0}));
+ #endif // SCRATCHPADS_PATCH
+}
+
+void
+toggleviewex(const Arg *arg)
+{
+ toggleview(&((Arg) { .ui = 1 << arg->ui }));
+}
+
+void
+tagex(const Arg *arg)
+{
+ tag(&((Arg) { .ui = 1 << arg->ui }));
+}
+
+void
+toggletagex(const Arg *arg)
+{
+ toggletag(&((Arg) { .ui = 1 << arg->ui }));
+}
+
+void
+tagallex(const Arg *arg)
+{
+ #if SCRATCHPADS_PATCH
+ tag(&((Arg){.ui = ~SPTAGMASK}));
+ #else
+ tag(&((Arg){.ui = ~0}));
+ #endif // SCRATCHPADS_PATCH
+}
+
+int
+fake_signal(void)
+{
+ char fsignal[256];
+ char indicator[9] = "fsignal:";
+ char str_sig[50];
+ char param[16];
+ int i, len_str_sig, n, paramn;
+ size_t len_fsignal, len_indicator = strlen(indicator);
+ Arg arg;
+
+ // Get root name property
+ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) {
+ len_fsignal = strlen(fsignal);
+
+ // Check if this is indeed a fake signal
+ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) {
+ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n);
+
+ if (paramn == 1) arg = (Arg) {0};
+ else if (paramn > 2) return 1;
+ else if (strncmp(param, "i", n - len_str_sig) == 0)
+ #if IPC_PATCH
+ sscanf(fsignal + len_indicator + n, "%li", &(arg.i));
+ #else
+ sscanf(fsignal + len_indicator + n, "%i", &(arg.i));
+ #endif // IPC_PATCH
+ else if (strncmp(param, "ui", n - len_str_sig) == 0)
+ #if IPC_PATCH
+ sscanf(fsignal + len_indicator + n, "%lu", &(arg.ui));
+ #else
+ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui));
+ #endif // IPC_PATCH
+ else if (strncmp(param, "f", n - len_str_sig) == 0)
+ sscanf(fsignal + len_indicator + n, "%f", &(arg.f));
+ else return 1;
+
+ // Check if a signal was found, and if so handle it
+ for (i = 0; i < LENGTH(signals); i++)
+ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func)
+ signals[i].func(&(arg));
+
+ // A fake signal was sent
+ return 1;
+ }
+ }
+
+ // No fake signal was sent, so proceed with update
+ return 0;
+}
+
diff --git a/patch/dwmc.h b/patch/dwmc.h
new file mode 100644
index 0000000..66e23a9
--- /dev/null
+++ b/patch/dwmc.h
@@ -0,0 +1,14 @@
+typedef struct {
+ const char * sig;
+ void (*func)(const Arg *);
+} Signal;
+
+static void setlayoutex(const Arg *arg);
+static void viewex(const Arg *arg);
+static void viewallex(const Arg *arg);
+static void toggleviewex(const Arg *arg);
+static void tagex(const Arg *arg);
+static void toggletagex(const Arg *arg);
+static void tagallex(const Arg *arg);
+static int fake_signal(void);
+
diff --git a/patch/exresize.c b/patch/exresize.c
new file mode 100644
index 0000000..ac3eab7
--- /dev/null
+++ b/patch/exresize.c
@@ -0,0 +1,196 @@
+#define EXPAND_LEFT (1 << 0)
+#define EXPAND_RIGHT (1 << 2)
+#define EXPAND_UP (1 << 4)
+#define EXPAND_DOWN (1 << 6)
+
+#define IS_SET(q, w) ((q & w) != 0)
+#define IS_FORCED(q, w) IS_SET((q << 1), w)
+
+#define EXPANDALL (EXPAND_LEFT | EXPAND_RIGHT | EXPAND_UP | EXPAND_DOWN)
+#define UNEXPAND (EXPANDALL << 1) // Force all directions to 0
+#define FORCE_EXPANDALL ~0 // Force expand in all directions
+
+void
+exresize(const Arg *arg)
+{
+ Client *c;
+ int x, y, nx, ny, nw, nh;
+ c = selmon->sel;
+
+ if (!c || !arg) return;
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+ togglefloating(NULL);
+ if (c->expandmask != 0)
+ expand(UNEXPAND);
+
+ x = ((int *)arg->v)[0];
+ y = ((int *)arg->v)[1];
+
+ nw = MIN(selmon->ww - c->bw*2, c->w + x);
+ nh = MIN(selmon->wh - c->bw*2, c->h + y);
+ nx = c->x - x/2;
+ ny = c->y - y/2;
+
+ if (!((abs(c->x + c->w/2 - (selmon->wx + selmon->ww/2)) < snap))) {
+ if ((nw == selmon->ww) ||
+ (nx < selmon->wx) ||
+ (abs(selmon->wx - c->x) < snap))
+ nx = selmon->wx;
+ else if ((nx+nw > (selmon->wx + selmon->ww)) ||
+ (abs((selmon->wx + selmon->ww) - (c->x + c->w)) < snap))
+ nx = (selmon->wx + selmon->ww) - nw - c->bw*2;
+ } else
+ nx = selmon->wx + selmon->ww/2 - nw/2;
+
+ if (!((abs(c->y + c->h/2 - (selmon->wy + selmon->wh/2)) < snap))) {
+
+ if ((nh == selmon->wh) ||
+ (ny < selmon->wy) ||
+ (abs(selmon->wy - c->y) < snap))
+ ny = selmon->wy;
+ else if ((ny+nh > (selmon->wy + selmon->wh)) ||
+ (abs((selmon->wy + selmon->wh) - (c->y + c->h)) < snap))
+ ny = (selmon->wy + selmon->wh) - nh - c->bw*2;
+ } else
+ ny = selmon->wy + selmon->wh/2 - nh/2;
+
+
+ resizeclient(c, nx, ny, MAX(nw, 32), MAX(nh, 32));
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
+}
+
+void
+explace(const Arg *arg)
+{
+ Client *c;
+ int nx, ny;
+
+ c = selmon->sel;
+ if (!c || (arg->ui >= 9)) return;
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+ togglefloating(NULL);
+
+ nx = (arg->ui % 3) - 1;
+ ny = (arg->ui / 3) - 1;
+
+ if (nx < 0) nx = selmon->wx;
+ else if (nx > 0) nx = selmon->wx + selmon->ww - c->w - c->bw*2;
+ else nx = selmon->wx + selmon->ww/2 - c->w/2;
+
+ if (ny < 0) ny = selmon->wy;
+ else if (ny > 0) ny = selmon->wy + selmon->wh - c->h - c->bw*2;
+ else ny = selmon->wy + selmon->wh/2 - c->h/2;
+
+ resize(c, nx, ny, c->w, c->h, True);
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
+}
+
+int
+calculate_expand(unsigned char mask, unsigned char curmask,
+ unsigned char *newmask, unsigned char key,
+ int *reset_value, int new_reset_value,
+ int max_value, int old_value)
+{
+ if (IS_SET(key, mask) ||
+ (IS_SET(key, curmask) && (!IS_SET(key, mask) && IS_FORCED(key, mask))) ||
+ (!IS_SET(key, curmask) && (IS_SET(key, mask) && IS_FORCED(key, mask)))) {
+
+ if (IS_SET(key, mask) && (!IS_SET(key,curmask) || IS_FORCED(key,mask))) {
+ if (!IS_SET(key, curmask))
+ *reset_value = new_reset_value;
+ *newmask |= key;
+ return max_value;
+ } else if ((IS_SET(key,curmask) && IS_SET(key, mask)) ||
+ (!IS_SET(key, mask) && IS_FORCED(key, mask))) {
+ *newmask &= ~key;
+ return *reset_value;
+ } else {
+ *newmask &= ~key;
+ return old_value;
+ }
+ } else
+ return new_reset_value;
+}
+
+void
+expand(unsigned char mask)
+{
+ XEvent ev;
+ int nx1, ny1, nx2, ny2;
+ #if SETBORDERPX_PATCH
+ int bp = selmon->borderpx;
+ #else
+ int bp = borderpx;
+ #endif // SETBORDERPX_PATCH
+ unsigned char curmask;
+ unsigned char newmask;
+
+ if (!selmon->sel || selmon->sel->isfixed)
+ return;
+ XRaiseWindow(dpy, selmon->sel->win);
+ newmask = curmask = selmon->sel->expandmask;
+
+ if (curmask == 0) {
+ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating)
+ selmon->sel->wasfloating = 1;
+ else {
+ togglefloating(NULL);
+ selmon->sel->wasfloating = 0;
+ }
+ }
+
+ nx1 = calculate_expand(mask, curmask, &newmask,
+ EXPAND_LEFT, &selmon->sel->expandx1,
+ selmon->sel->x,
+ selmon->wx,
+ selmon->sel->oldx);
+ nx2 = calculate_expand(mask, curmask, &newmask,
+ EXPAND_RIGHT, &selmon->sel->expandx2,
+ selmon->sel->x + selmon->sel->w,
+ selmon->wx + selmon->ww - 2*bp,
+ selmon->sel->oldw + selmon->sel->x);
+ ny1 = calculate_expand(mask, curmask, &newmask,
+ EXPAND_UP, &selmon->sel->expandy1,
+ selmon->sel->y,
+ selmon->wy,
+ selmon->sel->oldy);
+ ny2 = calculate_expand(mask, curmask, &newmask,
+ EXPAND_DOWN, &selmon->sel->expandy2,
+ selmon->sel->y + selmon->sel->h,
+ selmon->wy + selmon->wh - 2*bp,
+ selmon->sel->oldh + selmon->sel->y);
+
+
+ resizeclient(selmon->sel, nx1, ny1, MAX(nx2-nx1, 32), MAX(ny2-ny1, 32));
+
+ if ((newmask == 0) && (!selmon->sel->wasfloating))
+ togglefloating(NULL);
+ selmon->sel->expandmask = newmask;
+ drawbar(selmon);
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+void
+togglemaximize(const Arg *arg)
+{
+ if (arg->i > 0) expand(FORCE_EXPANDALL);
+ else if (arg->i < 0) expand(UNEXPAND);
+ else expand(EXPANDALL);
+}
+
+void
+toggleverticalexpand(const Arg *arg)
+{
+ if (arg->i < 0) expand(EXPAND_DOWN);
+ else if (arg->i > 0) expand(EXPAND_UP);
+ else expand(EXPAND_DOWN | EXPAND_UP);
+}
+
+void
+togglehorizontalexpand(const Arg *arg)
+{
+ if (arg->i < 0) expand(EXPAND_LEFT);
+ else if (arg->i > 0) expand(EXPAND_RIGHT);
+ else expand(EXPAND_LEFT | EXPAND_RIGHT);
+}
+
diff --git a/patch/exresize.h b/patch/exresize.h
new file mode 100644
index 0000000..73a636a
--- /dev/null
+++ b/patch/exresize.h
@@ -0,0 +1,9 @@
+enum { EX_NW, EX_N, EX_NE, EX_W, EX_C, EX_E, EX_SW, EX_S, EX_SE };
+
+void expand(unsigned char mask);
+void togglemaximize(const Arg *arg);
+void toggleverticalexpand(const Arg *arg);
+void togglehorizontalexpand(const Arg *arg);
+void exresize(const Arg *arg);
+void explace(const Arg *arg);
+
diff --git a/patch/fakefullscreenclient.c b/patch/fakefullscreenclient.c
new file mode 100644
index 0000000..509211f
--- /dev/null
+++ b/patch/fakefullscreenclient.c
@@ -0,0 +1,19 @@
+void
+togglefakefullscreen(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
+ c->fakefullscreen = 2;
+ setfullscreen(c, 0);
+ } else if (c->fakefullscreen == 1) {
+ setfullscreen(c, 0);
+ c->fakefullscreen = 0;
+ } else {
+ c->fakefullscreen = 1;
+ setfullscreen(c, 1);
+ }
+}
+
diff --git a/patch/fakefullscreenclient.h b/patch/fakefullscreenclient.h
new file mode 100644
index 0000000..889eed6
--- /dev/null
+++ b/patch/fakefullscreenclient.h
@@ -0,0 +1,2 @@
+static void togglefakefullscreen(const Arg *arg);
+
diff --git a/patch/floatpos.c b/patch/floatpos.c
new file mode 100644
index 0000000..f5e83a7
--- /dev/null
+++ b/patch/floatpos.c
@@ -0,0 +1,195 @@
+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);
+
+ #if !FOCUSONCLICK_PATCH
+ XRaiseWindow(dpy, c->win);
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
+ #endif // FOCUSONCLICK_PATCH
+}
+
+void
+setfloatpos(Client *c, const char *floatpos)
+{
+ char xCh, yCh, wCh, hCh;
+ int x, y, w, h, wx, ww, wy, wh;
+ #if FLOATPOS_RESPECT_GAPS_PATCH && VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ unsigned int n;
+ #endif // FLOATPOS_RESPECT_GAPS_PATCH | VANITYGAPS_PATCH
+
+ 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;
+ }
+
+ #if FLOATPOS_RESPECT_GAPS_PATCH && VANITYGAPS_PATCH
+ getgaps(c->mon, &oh, &ov, &ih, &iv, &n);
+ wx = c->mon->wx + ov;
+ wy = c->mon->wy + oh;
+ ww = c->mon->ww - 2*ov;
+ wh = c->mon->wh - 2*oh;
+ #else
+ wx = c->mon->wx;
+ wy = c->mon->wy;
+ ww = c->mon->ww;
+ wh = c->mon->wh;
+ #endif // FLOATPOS_RESPECT_GAPS_PATCH | VANITYGAPS_PATCH
+
+ 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/focusadjacenttag.c b/patch/focusadjacenttag.c
new file mode 100644
index 0000000..1665c18
--- /dev/null
+++ b/patch/focusadjacenttag.c
@@ -0,0 +1,102 @@
+void
+tagtoleft(const Arg *arg)
+{
+ if (selmon->sel != NULL
+ && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] > 1) {
+ selmon->sel->tags >>= 1;
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+tagtoright(const Arg *arg)
+{
+ if (selmon->sel != NULL
+ && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) {
+ selmon->sel->tags <<= 1;
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+viewtoleft(const Arg *arg)
+{
+ if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] > 1) {
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ #if PERTAG_PATCH
+ pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] >> 1 }));
+ #else
+ selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] >> 1;
+ #endif // pertagview
+ focus(NULL);
+ arrange(selmon);
+ #if BAR_EWMHTAGS_PATCH
+ updatecurrentdesktop();
+ #endif // BAR_EWMHTAGS_PATCH
+ }
+}
+
+void
+viewtoright(const Arg *arg)
+{
+ if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) {
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ #if PERTAG_PATCH
+ pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] << 1 }));
+ #else
+ selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] << 1;
+ #endif // pertagview
+ focus(NULL);
+ arrange(selmon);
+ #if BAR_EWMHTAGS_PATCH
+ updatecurrentdesktop();
+ #endif // BAR_EWMHTAGS_PATCH
+ }
+}
+
+void
+tagandviewtoleft(const Arg *arg)
+{
+ if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] > 1) {
+ selmon->sel->tags >>= 1;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ #if PERTAG_PATCH
+ pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] >> 1 }));
+ #else
+ selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] >> 1;
+ #endif // pertagview
+ focus(selmon->sel);
+ arrange(selmon);
+ #if BAR_EWMHTAGS_PATCH
+ updatecurrentdesktop();
+ #endif // BAR_EWMHTAGS_PATCH
+ }
+}
+
+void
+tagandviewtoright(const Arg *arg)
+{
+ if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1
+ && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) {
+ selmon->sel->tags <<= 1;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ #if PERTAG_PATCH
+ pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] << 1 }));
+ #else
+ selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] << 1;
+ #endif // pertagview
+ focus(selmon->sel);
+ arrange(selmon);
+ #if BAR_EWMHTAGS_PATCH
+ updatecurrentdesktop();
+ #endif // BAR_EWMHTAGS_PATCH
+ }
+}
+
diff --git a/patch/focusadjacenttag.h b/patch/focusadjacenttag.h
new file mode 100644
index 0000000..abd7439
--- /dev/null
+++ b/patch/focusadjacenttag.h
@@ -0,0 +1,7 @@
+static void tagtoleft(const Arg *arg);
+static void tagtoright(const Arg *arg);
+static void viewtoleft(const Arg *arg);
+static void viewtoright(const Arg *arg);
+static void tagandviewtoleft(const Arg *arg);
+static void tagandviewtoright(const Arg *arg);
+
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/focusmaster.c b/patch/focusmaster.c
new file mode 100644
index 0000000..13a47e5
--- /dev/null
+++ b/patch/focusmaster.c
@@ -0,0 +1,14 @@
+void
+focusmaster(const Arg *arg)
+{
+ Client *c;
+
+ if (selmon->nmaster < 1)
+ return;
+
+ c = nexttiled(selmon->clients);
+
+ if (c)
+ focus(c);
+}
+
diff --git a/patch/focusmaster.h b/patch/focusmaster.h
new file mode 100644
index 0000000..32e7c7c
--- /dev/null
+++ b/patch/focusmaster.h
@@ -0,0 +1,2 @@
+static void focusmaster(const Arg *arg);
+
diff --git a/patch/focusurgent.c b/patch/focusurgent.c
new file mode 100644
index 0000000..86a918e
--- /dev/null
+++ b/patch/focusurgent.c
@@ -0,0 +1,16 @@
+void
+focusurgent(const Arg *arg)
+{
+ Client *c;
+ int i;
+ for (c = selmon->clients; c && !c->isurgent; c = c->next);
+ if (c) {
+ for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++);
+ if (i < NUMTAGS) {
+ if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags])
+ view(&((Arg) { .ui = 1 << i }));
+ focus(c);
+ }
+ }
+}
+
diff --git a/patch/focusurgent.h b/patch/focusurgent.h
new file mode 100644
index 0000000..854258d
--- /dev/null
+++ b/patch/focusurgent.h
@@ -0,0 +1,2 @@
+static void focusurgent(const Arg *arg);
+
diff --git a/patch/fsignal.c b/patch/fsignal.c
new file mode 100644
index 0000000..b0ce2ea
--- /dev/null
+++ b/patch/fsignal.c
@@ -0,0 +1,41 @@
+int
+fake_signal(void)
+{
+ char fsignal[256];
+ char indicator[9] = "fsignal:";
+ char str_signum[16];
+ int i, v, signum;
+ size_t len_fsignal, len_indicator = strlen(indicator);
+
+ // Get root name property
+ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) {
+ len_fsignal = strlen(fsignal);
+
+ // Check if this is indeed a fake signal
+ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) {
+ memcpy(str_signum, &fsignal[len_indicator], len_fsignal - len_indicator);
+ str_signum[len_fsignal - len_indicator] = '\0';
+
+ // Convert string value into managable integer
+ for (i = signum = 0; i < strlen(str_signum); i++) {
+ v = str_signum[i] - '0';
+ if (v >= 0 && v <= 9) {
+ signum = signum * 10 + v;
+ }
+ }
+
+ // Check if a signal was found, and if so handle it
+ if (signum)
+ for (i = 0; i < LENGTH(signals); i++)
+ if (signum == signals[i].signum && signals[i].func)
+ signals[i].func(&(signals[i].arg));
+
+ // A fake signal was sent
+ return 1;
+ }
+ }
+
+ // No fake signal was sent, so proceed with update
+ return 0;
+}
+
diff --git a/patch/fsignal.h b/patch/fsignal.h
new file mode 100644
index 0000000..55fed6c
--- /dev/null
+++ b/patch/fsignal.h
@@ -0,0 +1,8 @@
+typedef struct {
+ unsigned int signum;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Signal;
+
+static int fake_signal(void);
+
diff --git a/patch/fullscreen.c b/patch/fullscreen.c
new file mode 100644
index 0000000..667cdc9
--- /dev/null
+++ b/patch/fullscreen.c
@@ -0,0 +1,18 @@
+Layout *last_layout;
+
+void
+fullscreen(const Arg *arg)
+{
+ int monocle_pos = 0;
+ if (selmon->showbar || last_layout == NULL) {
+ #if MONOCLE_LAYOUT
+ for (monocle_pos = 0, last_layout = (Layout *)layouts; !last_layout->arrange || last_layout->arrange != &monocle; monocle_pos++, last_layout++ );
+ #endif // MONOCLE_LAYOUT
+ for (last_layout = (Layout *)layouts; last_layout != selmon->lt[selmon->sellt]; last_layout++);
+ setlayout(&((Arg) { .v = &layouts[monocle_pos] }));
+ } else {
+ setlayout(&((Arg) { .v = last_layout }));
+ }
+ togglebar(arg);
+}
+
diff --git a/patch/fullscreen.h b/patch/fullscreen.h
new file mode 100644
index 0000000..72983e1
--- /dev/null
+++ b/patch/fullscreen.h
@@ -0,0 +1,2 @@
+static void fullscreen(const Arg *arg);
+
diff --git a/patch/include.c b/patch/include.c
new file mode 100644
index 0000000..29dac83
--- /dev/null
+++ b/patch/include.c
@@ -0,0 +1,359 @@
+/* Bar functionality */
+#include "bar_indicators.c"
+#include "bar_tagicons.c"
+
+#if BAR_ALPHA_PATCH
+#include "bar_alpha.c"
+#endif
+#if BAR_ALTERNATIVE_TAGS_PATCH
+#include "bar_alternativetags.c"
+#endif
+#if BAR_ANYBAR_PATCH
+#include "bar_anybar.c"
+#endif
+#if BAR_DWMBLOCKS_PATCH && BAR_STATUSCMD_PATCH
+#include "bar_dwmblocks.c"
+#endif
+#if BAR_EWMHTAGS_PATCH
+#include "bar_ewmhtags.c"
+#endif
+#if COMBO_PATCH
+#include "combo.c"
+#endif
+#if BAR_HOLDBAR_PATCH
+#include "bar_holdbar.c"
+#endif
+#if BAR_LTSYMBOL_PATCH
+#include "bar_ltsymbol.c"
+#endif
+#if BAR_POWERLINE_STATUS_PATCH
+#include "bar_powerline_status.c"
+#endif
+#if BAR_POWERLINE_TAGS_PATCH
+#include "bar_powerline_tags.c"
+#endif
+#if BAR_STATUS_PATCH
+#include "bar_status.c"
+#endif
+#if BAR_STATUS2D_PATCH
+#include "bar_status2d.c"
+#endif
+#if BAR_STATUSBUTTON_PATCH
+#include "bar_statusbutton.c"
+#endif
+#if BAR_STATUSCMD_PATCH
+#include "bar_statuscmd.c"
+#endif
+#if BAR_STATUSCOLORS_PATCH
+#include "bar_statuscolors.c"
+#endif
+#if BAR_WINICON_PATCH
+#include "bar_winicon.c"
+#endif
+#if BAR_TABGROUPS_PATCH
+#include "bar_tabgroups.c"
+#endif
+#if BAR_TAGS_PATCH
+#include "bar_tags.c"
+#endif
+#if BAR_TAGGRID_PATCH
+#include "bar_taggrid.c"
+#endif
+#if BAR_WINTITLE_PATCH
+#include "bar_wintitle.c"
+#endif
+#if BAR_FANCYBAR_PATCH
+#include "bar_fancybar.c"
+#endif
+#if BAR_FLEXWINTITLE_PATCH
+#include "bar_flexwintitle.c"
+#if BAR_WINTITLE_FLOATING_PATCH
+#include "bar_wintitle_floating.c"
+#endif
+#if BAR_WINTITLE_HIDDEN_PATCH
+#include "bar_wintitle_hidden.c"
+#endif
+#endif // BAR_FLEXWINTITLE_PATCH
+#if BAR_AWESOMEBAR_PATCH
+#include "bar_awesomebar.c"
+#endif
+#if BAR_SYSTRAY_PATCH
+#include "bar_systray.c"
+#endif
+#if BAR_VTCOLORS_PATCH
+#include "bar_vtcolors.c"
+#endif
+#if BAR_WINTITLEACTIONS_PATCH
+#include "bar_wintitleactions.c"
+#endif
+#if BAR_LAYOUTMENU_PATCH
+#include "bar_layoutmenu.c"
+#endif
+
+/* Other patches */
+#if ASPECTRESIZE_PATCH
+#include "aspectresize.c"
+#endif
+#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
+#include "attachx.c"
+#endif
+#if AUTOSTART_PATCH
+#include "autostart.c"
+#endif
+#if CFACTS_PATCH
+#include "cfacts.c"
+#endif
+#if CMDCUSTOMIZE_PATCH
+#include "cmdcustomize.c"
+#endif
+#if COOL_AUTOSTART_PATCH
+#include "cool_autostart.c"
+#endif
+#if CYCLELAYOUTS_PATCH
+#include "cyclelayouts.c"
+#endif
+#if DECORATION_HINTS_PATCH
+#include "decorationhints.c"
+#endif
+#if DISTRIBUTETAGS_PATCH
+#include "distributetags.c"
+#endif
+#if DRAGCFACT_PATCH && CFACTS_PATCH
+#include "dragcfact.c"
+#endif
+#if DWMC_PATCH
+#include "dwmc.c"
+#elif FSIGNAL_PATCH
+#include "fsignal.c"
+#endif
+#if EXRESIZE_PATCH
+#include "exresize.c"
+#endif
+#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
+#include "fakefullscreenclient.c"
+#endif
+#if FLOATPOS_PATCH
+#include "floatpos.c"
+#endif
+#if FOCUSADJACENTTAG_PATCH
+#include "focusadjacenttag.c"
+#endif
+#if FOCUSDIR_PATCH
+#include "focusdir.c"
+#endif
+#if FOCUSMASTER_PATCH
+#include "focusmaster.c"
+#endif
+#if FOCUSURGENT_PATCH
+#include "focusurgent.c"
+#endif
+#if FULLSCREEN_PATCH
+#include "fullscreen.c"
+#endif
+#if INPLACEROTATE_PATCH
+#include "inplacerotate.c"
+#endif
+#if IPC_PATCH
+#include "ipc.c"
+#ifdef VERSION
+#include "ipc/IPCClient.c"
+#include "ipc/yajl_dumps.c"
+#include "ipc/ipc.c"
+#include "ipc/util.c"
+#endif
+#endif // IPC_PATCH
+#if INSETS_PATCH
+#include "insets.c"
+#endif
+#if KEYMODES_PATCH
+#include "keymodes.c"
+#endif
+#if KILLUNSEL_PATCH
+#include "killunsel.c"
+#endif
+#if MAXIMIZE_PATCH
+#include "maximize.c"
+#endif
+#if MPDCONTROL_PATCH
+#include "mpdcontrol.c"
+#endif
+#if MOVEPLACE_PATCH
+#include "moveplace.c"
+#endif
+#if MOVERESIZE_PATCH
+#include "moveresize.c"
+#endif
+#if MOVESTACK_PATCH
+#include "movestack.c"
+#endif
+#if NO_MOD_BUTTONS_PATCH
+#include "nomodbuttons.c"
+#endif
+#if PERTAG_PATCH
+#include "pertag.c"
+#endif
+#if PLACEMOUSE_PATCH
+#include "placemouse.c"
+#endif
+#if PUSH_NO_MASTER_PATCH
+#include "push_no_master.c"
+#elif PUSH_PATCH
+#include "push.c"
+#endif
+#if REORGANIZETAGS_PATCH
+#include "reorganizetags.c"
+#endif
+#if RESTARTSIG_PATCH
+#include "restartsig.c"
+#endif
+#if RIODRAW_PATCH
+#include "riodraw.c"
+#endif
+#if ROTATESTACK_PATCH
+#include "rotatestack.c"
+#endif
+#if ROUNDED_CORNERS_PATCH
+#include "roundedcorners.c"
+#endif
+#if SCRATCHPADS_PATCH
+#include "scratchpad.c"
+#endif
+#if SCRATCHPAD_ALT_1_PATCH
+#include "scratchpad_alt_1.c"
+#endif
+#if SELFRESTART_PATCH
+#include "selfrestart.c"
+#endif
+#if SETBORDERPX_PATCH
+#include "setborderpx.c"
+#endif
+#if SHIFTVIEW_PATCH
+#include "shiftview.c"
+#endif
+#if SHIFTVIEW_CLIENTS_PATCH
+#include "shiftviewclients.c"
+#endif
+#if SIZEHINTS_RULED_PATCH
+#include "sizehints_ruled.c"
+#endif
+#if SORTSCREENS_PATCH
+#ifdef XINERAMA
+#include "sortscreens.c"
+#endif // XINERAMA
+#endif
+#if STACKER_PATCH
+#include "stacker.c"
+#endif
+#if STICKY_PATCH
+#include "sticky.c"
+#endif
+#if SWALLOW_PATCH
+#include "swallow.c"
+#endif
+#if SWAPFOCUS_PATCH && PERTAG_PATCH
+#include "swapfocus.c"
+#endif
+#if SWAPTAGS_PATCH
+#include "swaptags.c"
+#endif
+#if SWITCHCOL_PATCH
+#include "switchcol.c"
+#endif
+#if TAB_PATCH
+#include "tab.c"
+#endif
+#if TAGALL_PATCH
+#include "tagall.c"
+#endif
+#if TAGALLMON_PATCH
+#include "tagallmon.c"
+#endif
+#if TAGOTHERMONITOR_PATCH
+#include "tagothermonitor.c"
+#endif
+#if TAGSWAPMON_PATCH
+#include "tagswapmon.c"
+#endif
+#if TAPRESIZE_PATCH
+#include "tapresize.c"
+#endif
+#if TOGGLEFULLSCREEN_PATCH
+#include "togglefullscreen.c"
+#endif
+#if TRANSFER_PATCH
+#include "transfer.c"
+#endif
+#if TRANSFER_ALL_PATCH
+#include "transferall.c"
+#endif
+#if UNFLOATVISIBLE_PATCH
+#include "unfloatvisible.c"
+#endif
+#if VANITYGAPS_PATCH
+#include "vanitygaps.c"
+#endif
+#if WARP_PATCH
+#include "warp.c"
+#endif
+#if WINVIEW_PATCH
+#include "winview.c"
+#endif
+#if ZOOMSWAP_PATCH
+#include "zoomswap.c"
+#endif
+#if XKB_PATCH
+#include "xkb.c"
+#endif
+#if XRDB_PATCH && !BAR_VTCOLORS_PATCH
+#include "xrdb.c"
+#endif
+#if DRAGMFACT_PATCH
+#include "dragmfact.c"
+#endif
+/* Layouts */
+#if BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || TILE_LAYOUT
+#include "layout_facts.c"
+#endif
+#if BSTACK_LAYOUT
+#include "layout_bstack.c"
+#endif
+#if BSTACKHORIZ_LAYOUT
+#include "layout_bstackhoriz.c"
+#endif
+#if CENTEREDMASTER_LAYOUT
+#include "layout_centeredmaster.c"
+#endif
+#if CENTEREDFLOATINGMASTER_LAYOUT
+#include "layout_centeredfloatingmaster.c"
+#endif
+#if COLUMNS_LAYOUT
+#include "layout_columns.c"
+#endif
+#if DECK_LAYOUT
+#include "layout_deck.c"
+#endif
+#if FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT
+#include "layout_fibonacci.c"
+#endif
+#if FLEXTILE_DELUXE_LAYOUT
+#include "layout_flextile-deluxe.c"
+#endif
+#if GAPPLESSGRID_LAYOUT
+#include "layout_gapplessgrid.c"
+#endif
+#if GRIDMODE_LAYOUT
+#include "layout_grid.c"
+#endif
+#if HORIZGRID_LAYOUT
+#include "layout_horizgrid.c"
+#endif
+#if MONOCLE_LAYOUT
+#include "layout_monocle.c"
+#endif
+#if NROWGRID_LAYOUT
+#include "layout_nrowgrid.c"
+#endif
+#if TILE_LAYOUT
+#include "layout_tile.c"
+#endif
+
diff --git a/patch/include.h b/patch/include.h
new file mode 100644
index 0000000..d4030a9
--- /dev/null
+++ b/patch/include.h
@@ -0,0 +1,349 @@
+/* Bar functionality */
+#include "bar_indicators.h"
+#include "bar_tagicons.h"
+
+#if BAR_ALPHA_PATCH
+#include "bar_alpha.h"
+#endif
+#if BAR_ALTERNATIVE_TAGS_PATCH
+#include "bar_alternativetags.h"
+#endif
+#if BAR_ANYBAR_PATCH
+#include "bar_anybar.h"
+#endif
+#if BAR_DWMBLOCKS_PATCH && BAR_STATUSCMD_PATCH
+#include "bar_dwmblocks.h"
+#endif
+#if BAR_EWMHTAGS_PATCH
+#include "bar_ewmhtags.h"
+#endif
+#if COMBO_PATCH
+#include "combo.h"
+#endif
+#if BAR_HOLDBAR_PATCH
+#include "bar_holdbar.h"
+#endif
+#if BAR_LTSYMBOL_PATCH
+#include "bar_ltsymbol.h"
+#endif
+#if BAR_POWERLINE_STATUS_PATCH
+#include "bar_powerline_status.h"
+#endif
+#if BAR_POWERLINE_TAGS_PATCH
+#include "bar_powerline_tags.h"
+#endif
+#if BAR_STATUS_PATCH
+#include "bar_status.h"
+#endif
+#if BAR_STATUS2D_PATCH
+#include "bar_status2d.h"
+#endif
+#if BAR_STATUSBUTTON_PATCH
+#include "bar_statusbutton.h"
+#endif
+#if BAR_STATUSCMD_PATCH
+#include "bar_statuscmd.h"
+#endif
+#if BAR_TABGROUPS_PATCH
+#include "bar_tabgroups.h"
+#endif
+#if BAR_WINICON_PATCH
+#include "bar_winicon.h"
+#endif
+#if BAR_TAGS_PATCH
+#include "bar_tags.h"
+#endif
+#if BAR_TAGGRID_PATCH
+#include "bar_taggrid.h"
+#endif
+#if BAR_WINTITLE_PATCH
+#include "bar_wintitle.h"
+#endif
+#if BAR_FANCYBAR_PATCH
+#include "bar_fancybar.h"
+#endif
+#if BAR_FLEXWINTITLE_PATCH
+#include "bar_flexwintitle.h"
+#if BAR_WINTITLE_FLOATING_PATCH
+#include "bar_wintitle_floating.h"
+#endif
+#if BAR_WINTITLE_HIDDEN_PATCH
+#include "bar_wintitle_hidden.h"
+#endif
+#endif // BAR_FLEXWINTITLE_PATCH
+#if BAR_AWESOMEBAR_PATCH
+#include "bar_awesomebar.h"
+#endif
+#if BAR_SYSTRAY_PATCH
+#include "bar_systray.h"
+#endif
+#if BAR_VTCOLORS_PATCH
+#include "bar_vtcolors.h"
+#endif
+#if BAR_WINTITLEACTIONS_PATCH
+#include "bar_wintitleactions.h"
+#endif
+#if BAR_LAYOUTMENU_PATCH
+#include "bar_layoutmenu.h"
+#endif
+
+/* Other patches */
+#if ASPECTRESIZE_PATCH
+#include "aspectresize.h"
+#endif
+#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
+#include "attachx.h"
+#endif
+#if AUTOSTART_PATCH
+#include "autostart.h"
+#endif
+#if CFACTS_PATCH
+#include "cfacts.h"
+#endif
+#if CMDCUSTOMIZE_PATCH
+#include "cmdcustomize.h"
+#endif
+#if COOL_AUTOSTART_PATCH
+#include "cool_autostart.h"
+#endif
+#if CYCLELAYOUTS_PATCH
+#include "cyclelayouts.h"
+#endif
+#if DECORATION_HINTS_PATCH
+#include "decorationhints.h"
+#endif
+#if DISTRIBUTETAGS_PATCH
+#include "distributetags.h"
+#endif
+#if DRAGCFACT_PATCH && CFACTS_PATCH
+#include "dragcfact.h"
+#endif
+#if DRAGMFACT_PATCH
+#include "dragmfact.h"
+#endif
+#if DWMC_PATCH
+#include "dwmc.h"
+#elif FSIGNAL_PATCH
+#include "fsignal.h"
+#endif
+#if EXRESIZE_PATCH
+#include "exresize.h"
+#endif
+#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
+#include "fakefullscreenclient.h"
+#endif
+#if FLOATPOS_PATCH
+#include "floatpos.h"
+#endif
+#if FOCUSDIR_PATCH
+#include "focusdir.h"
+#endif
+#if FOCUSADJACENTTAG_PATCH
+#include "focusadjacenttag.h"
+#endif
+#if FOCUSMASTER_PATCH
+#include "focusmaster.h"
+#endif
+#if FOCUSURGENT_PATCH
+#include "focusurgent.h"
+#endif
+#if FULLSCREEN_PATCH
+#include "fullscreen.h"
+#endif
+#if INPLACEROTATE_PATCH
+#include "inplacerotate.h"
+#endif
+#if IPC_PATCH
+#include "ipc.h"
+#include "ipc/ipc.h"
+#include "ipc/util.h"
+#endif
+#if INSETS_PATCH
+#include "insets.h"
+#endif
+#if KEYMODES_PATCH
+#include "keymodes.h"
+#endif
+#if KILLUNSEL_PATCH
+#include "killunsel.h"
+#endif
+#if MAXIMIZE_PATCH
+#include "maximize.h"
+#endif
+#if MPDCONTROL_PATCH
+#include "mpdcontrol.h"
+#endif
+#if MOVEPLACE_PATCH
+#include "moveplace.h"
+#endif
+#if MOVERESIZE_PATCH
+#include "moveresize.h"
+#endif
+#if MOVESTACK_PATCH
+#include "movestack.h"
+#endif
+#if NO_MOD_BUTTONS_PATCH
+#include "nomodbuttons.h"
+#endif
+#if PERTAG_PATCH
+#include "pertag.h"
+#endif
+#if PLACEMOUSE_PATCH
+#include "placemouse.h"
+#endif
+#if PUSH_NO_MASTER_PATCH
+#include "push_no_master.h"
+#elif PUSH_PATCH
+#include "push.h"
+#endif
+#if REORGANIZETAGS_PATCH
+#include "reorganizetags.h"
+#endif
+#if RESTARTSIG_PATCH
+#include "restartsig.h"
+#endif
+#if RIODRAW_PATCH
+#include "riodraw.h"
+#endif
+#if ROTATESTACK_PATCH
+#include "rotatestack.h"
+#endif
+#if ROUNDED_CORNERS_PATCH
+#include "roundedcorners.h"
+#endif
+#if SCRATCHPADS_PATCH
+#include "scratchpad.h"
+#endif
+#if SCRATCHPAD_ALT_1_PATCH
+#include "scratchpad_alt_1.h"
+#endif
+#if SELFRESTART_PATCH
+#include "selfrestart.h"
+#endif
+#if SETBORDERPX_PATCH
+#include "setborderpx.h"
+#endif
+#if SHIFTVIEW_PATCH
+#include "shiftview.h"
+#endif
+#if SHIFTVIEW_CLIENTS_PATCH
+#include "shiftviewclients.h"
+#endif
+#if SIZEHINTS_RULED_PATCH
+#include "sizehints_ruled.h"
+#endif
+#if SORTSCREENS_PATCH
+#ifdef XINERAMA
+#include "sortscreens.h"
+#endif // XINERAMA
+#endif
+#if STACKER_PATCH
+#include "stacker.h"
+#endif
+#if STICKY_PATCH
+#include "sticky.h"
+#endif
+#if SWALLOW_PATCH
+#include "swallow.h"
+#endif
+#if SWAPFOCUS_PATCH && PERTAG_PATCH
+#include "swapfocus.h"
+#endif
+#if SWAPTAGS_PATCH
+#include "swaptags.h"
+#endif
+#if SWITCHCOL_PATCH
+#include "switchcol.h"
+#endif
+#if TAB_PATCH
+#include "tab.h"
+#endif
+#if TAGALL_PATCH
+#include "tagall.h"
+#endif
+#if TAGALLMON_PATCH
+#include "tagallmon.h"
+#endif
+#if TAGOTHERMONITOR_PATCH
+#include "tagothermonitor.h"
+#endif
+#if TAGSWAPMON_PATCH
+#include "tagswapmon.h"
+#endif
+#if TAPRESIZE_PATCH
+#include "tapresize.h"
+#endif
+#if TOGGLEFULLSCREEN_PATCH
+#include "togglefullscreen.h"
+#endif
+#if TRANSFER_PATCH
+#include "transfer.h"
+#endif
+#if TRANSFER_ALL_PATCH
+#include "transferall.h"
+#endif
+#if UNFLOATVISIBLE_PATCH
+#include "unfloatvisible.h"
+#endif
+#if VANITYGAPS_PATCH
+#include "vanitygaps.h"
+#endif
+#if WARP_PATCH
+#include "warp.h"
+#endif
+#if WINVIEW_PATCH
+#include "winview.h"
+#endif
+#if ZOOMSWAP_PATCH
+#include "zoomswap.h"
+#endif
+#if XKB_PATCH
+#include "xkb.h"
+#endif
+#if XRDB_PATCH && !BAR_VTCOLORS_PATCH
+#include "xrdb.h"
+#endif
+/* Layouts */
+#if BSTACK_LAYOUT
+#include "layout_bstack.h"
+#endif
+#if BSTACKHORIZ_LAYOUT
+#include "layout_bstackhoriz.h"
+#endif
+#if CENTEREDMASTER_LAYOUT
+#include "layout_centeredmaster.h"
+#endif
+#if CENTEREDFLOATINGMASTER_LAYOUT
+#include "layout_centeredfloatingmaster.h"
+#endif
+#if COLUMNS_LAYOUT
+#include "layout_columns.h"
+#endif
+#if DECK_LAYOUT
+#include "layout_deck.h"
+#endif
+#if FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT
+#include "layout_fibonacci.h"
+#endif
+#if FLEXTILE_DELUXE_LAYOUT
+#include "layout_flextile-deluxe.h"
+#endif
+#if GAPPLESSGRID_LAYOUT
+#include "layout_gapplessgrid.h"
+#endif
+#if GRIDMODE_LAYOUT
+#include "layout_grid.h"
+#endif
+#if HORIZGRID_LAYOUT
+#include "layout_horizgrid.h"
+#endif
+#if MONOCLE_LAYOUT
+#include "layout_monocle.h"
+#endif
+#if NROWGRID_LAYOUT
+#include "layout_nrowgrid.h"
+#endif
+#if TILE_LAYOUT
+#include "layout_tile.h"
+#endif
+
diff --git a/patch/inplacerotate.c b/patch/inplacerotate.c
new file mode 100644
index 0000000..b700e04
--- /dev/null
+++ b/patch/inplacerotate.c
@@ -0,0 +1,84 @@
+void
+insertclient(Client *item, Client *insertItem, int after)
+{
+ Client *c;
+ if (item == NULL || insertItem == NULL || item == insertItem)
+ return;
+ detach(insertItem);
+ if (!after && selmon->clients == item) {
+ attach(insertItem);
+ return;
+ }
+ if (after) {
+ c = item;
+ } else {
+ for (c = selmon->clients; c; c = c->next) {
+ if (c->next == item)
+ break;
+ }
+ }
+ insertItem->next = c->next;
+ c->next = insertItem;
+}
+
+void
+inplacerotate(const Arg *arg)
+{
+ if (!selmon->sel || (selmon->sel->isfloating && !arg->f))
+ return;
+
+ unsigned int selidx = 0, i = 0;
+ Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL;
+
+ // Determine positionings for insertclient
+ for (c = selmon->clients; c; c = c->next) {
+ if (ISVISIBLE(c) && !(c->isfloating)) {
+ if (selmon->sel == c)
+ selidx = i;
+ if (i == selmon->nmaster - 1)
+ mtail = c;
+ if (i == selmon->nmaster)
+ shead = c;
+ if (mhead == NULL)
+ mhead = c;
+ stail = c;
+ i++;
+ }
+ }
+
+ switch(arg->i) {
+ case 1:
+ if (selidx >= selmon->nmaster)
+ insertclient(shead, stail, 0);
+ else
+ insertclient(mhead, mtail, 0);
+ break;
+ case -1:
+ if (selidx >= selmon->nmaster)
+ insertclient(stail, shead, 1);
+ else
+ insertclient(mtail, mhead, 1);
+ break;
+ case 2:
+ insertclient(selmon->clients, stail, 0);
+ break;
+ case -2:
+ insertclient(stail, selmon->clients, 1);
+ break;
+ }
+
+ // Restore focus position
+ i = 0;
+ for (c = selmon->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || (c->isfloating))
+ continue;
+ if (i == selidx) {
+ focus(c);
+ break;
+ }
+ i++;
+ }
+ arrange(selmon);
+ focus(c);
+}
+
diff --git a/patch/inplacerotate.h b/patch/inplacerotate.h
new file mode 100644
index 0000000..2669375
--- /dev/null
+++ b/patch/inplacerotate.h
@@ -0,0 +1,2 @@
+static void inplacerotate(const Arg *arg);
+
diff --git a/patch/insets.c b/patch/insets.c
new file mode 100644
index 0000000..8ad99b3
--- /dev/null
+++ b/patch/insets.c
@@ -0,0 +1,19 @@
+void
+setinset(Monitor *m, Inset inset)
+{
+ Bar *bar;
+ m->inset = inset;
+ updatebarpos(m);
+ for (bar = m->bar; bar; bar = bar->next)
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+ arrange(m);
+}
+
+void
+updateinset(const Arg *arg)
+{
+ Inset *inset = (Inset *)arg->v;
+ for (Monitor *m = mons; m; m = m->next)
+ setinset(m, *inset);
+}
+
diff --git a/patch/insets.h b/patch/insets.h
new file mode 100644
index 0000000..54635db
--- /dev/null
+++ b/patch/insets.h
@@ -0,0 +1,3 @@
+static void setinset(Monitor *m, Inset inset);
+static void updateinset(const Arg *arg);
+
diff --git a/patch/ipc.c b/patch/ipc.c
new file mode 100644
index 0000000..f5ec62c
--- /dev/null
+++ b/patch/ipc.c
@@ -0,0 +1,111 @@
+static int epoll_fd;
+static int dpy_fd;
+static Monitor *lastselmon;
+
+int
+handlexevent(struct epoll_event *ev)
+{
+ if (ev->events & EPOLLIN) {
+ XEvent ev;
+ while (running && XPending(dpy)) {
+ XNextEvent(dpy, &ev);
+ #if XKB_PATCH
+ /* Unfortunately the xkbEventType is not constant hence it can't be part of the
+ * normal event handler below */
+ if (ev.type == xkbEventType) {
+ xkbeventnotify(&ev);
+ continue;
+ }
+ #endif // XKB_PATCH
+
+ if (handler[ev.type]) {
+ handler[ev.type](&ev); /* call handler */
+ ipc_send_events(mons, &lastselmon, selmon);
+ }
+ }
+ } else if (ev-> events & EPOLLHUP)
+ return -1;
+
+ return 0;
+}
+
+void
+setlayoutsafe(const Arg *arg)
+{
+ const Layout *ltptr = (Layout *)arg->v;
+ if (ltptr == 0)
+ setlayout(arg);
+ for (int i = 0; i < LENGTH(layouts); i++) {
+ if (ltptr == &layouts[i])
+ setlayout(arg);
+ }
+}
+
+void
+setupepoll(void)
+{
+ epoll_fd = epoll_create1(0);
+ dpy_fd = ConnectionNumber(dpy);
+ struct epoll_event dpy_event;
+
+ // Initialize struct to 0
+ memset(&dpy_event, 0, sizeof(dpy_event));
+
+ DEBUG("Display socket is fd %d\n", dpy_fd);
+
+ if (epoll_fd == -1)
+ fputs("Failed to create epoll file descriptor", stderr);
+
+ dpy_event.events = EPOLLIN;
+ dpy_event.data.fd = dpy_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dpy_fd, &dpy_event)) {
+ fputs("Failed to add display file descriptor to epoll", stderr);
+ close(epoll_fd);
+ exit(1);
+ }
+
+ if (ipc_init(ipcsockpath, epoll_fd, ipccommands, LENGTH(ipccommands)) < 0)
+ fputs("Failed to initialize IPC\n", stderr);
+}
+
+void
+setstatus(const Arg *arg)
+{
+ Monitor *m;
+ #if BAR_EXTRASTATUS_PATCH
+ if (arg->v == NULL) {
+ strcpy(stext, "dwm-"VERSION);
+ estext[0] = '\0';
+ } else {
+ strcpy(rawstext, arg->v);
+ char *e = strchr(rawstext, statussep);
+ if (e) {
+ *e = '\0'; e++;
+ #if BAR_STATUSCMD_PATCH
+ strncpy(rawestext, e, sizeof(estext) - 1);
+ copyvalidchars(estext, rawestext);
+ #else
+ strncpy(estext, e, sizeof(estext) - 1);
+ #endif // BAR_STATUSCMD_PATCH
+ } else {
+ estext[0] = '\0';
+ }
+ #if BAR_STATUSCMD_PATCH
+ copyvalidchars(stext, rawstext);
+ #else
+ strncpy(stext, rawstext, sizeof(stext) - 1);
+ #endif // BAR_STATUSCMD_PATCH
+ }
+ #elif BAR_STATUSCMD_PATCH
+ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
+ strcpy(stext, "dwm-"VERSION);
+ else
+ copyvalidchars(stext, rawstext);
+ #else
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+ strcpy(stext, "dwm-"VERSION);
+ #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
+ for (m = mons; m; m = m->next)
+ drawbar(m);
+}
+
diff --git a/patch/ipc.h b/patch/ipc.h
new file mode 100644
index 0000000..ac8fb73
--- /dev/null
+++ b/patch/ipc.h
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+
+static int handlexevent(struct epoll_event *ev);
+static void setlayoutsafe(const Arg *arg);
+static void setupepoll(void);
+static void setstatus(const Arg *arg);
+
diff --git a/patch/ipc/IPCClient.c b/patch/ipc/IPCClient.c
new file mode 100644
index 0000000..a157513
--- /dev/null
+++ b/patch/ipc/IPCClient.c
@@ -0,0 +1,67 @@
+#include "IPCClient.h"
+
+#include <string.h>
+#include <sys/epoll.h>
+
+#include "util.h"
+
+IPCClient *
+ipc_client_new(int fd)
+{
+ IPCClient *c = (IPCClient *)malloc(sizeof(IPCClient));
+
+ if (c == NULL) return NULL;
+
+ // Initialize struct
+ memset(&c->event, 0, sizeof(struct epoll_event));
+
+ c->buffer_size = 0;
+ c->buffer = NULL;
+ c->fd = fd;
+ c->event.data.fd = fd;
+ c->next = NULL;
+ c->prev = NULL;
+ c->subscriptions = 0;
+
+ return c;
+}
+
+void
+ipc_list_add_client(IPCClientList *list, IPCClient *nc)
+{
+ DEBUG("Adding client with fd %d to list\n", nc->fd);
+
+ if (*list == NULL) {
+ // List is empty, point list at first client
+ *list = nc;
+ } else {
+ IPCClient *c;
+ // Go to last client in list
+ for (c = *list; c && c->next; c = c->next)
+ ;
+ c->next = nc;
+ nc->prev = c;
+ }
+}
+
+void
+ipc_list_remove_client(IPCClientList *list, IPCClient *c)
+{
+ IPCClient *cprev = c->prev;
+ IPCClient *cnext = c->next;
+
+ if (cprev != NULL) cprev->next = c->next;
+ if (cnext != NULL) cnext->prev = c->prev;
+ if (c == *list) *list = c->next;
+}
+
+IPCClient *
+ipc_list_get_client(IPCClientList list, int fd)
+{
+ for (IPCClient *c = list; c; c = c->next) {
+ if (c->fd == fd) return c;
+ }
+
+ return NULL;
+}
+
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/ipc.c b/patch/ipc/ipc.c
new file mode 100644
index 0000000..eae9667
--- /dev/null
+++ b/patch/ipc/ipc.c
@@ -0,0 +1,1202 @@
+#include "ipc.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_tree.h>
+
+#include "util.h"
+#include "yajl_dumps.h"
+
+static struct sockaddr_un sockaddr;
+static struct epoll_event sock_epoll_event;
+static IPCClientList ipc_clients = NULL;
+static int epoll_fd = -1;
+static int sock_fd = -1;
+static IPCCommand *ipc_commands;
+static unsigned int ipc_commands_len;
+// Max size is 1 MB
+static const uint32_t MAX_MESSAGE_SIZE = 1000000;
+static const int IPC_SOCKET_BACKLOG = 5;
+
+/**
+ * Create IPC socket at specified path and return file descriptor to socket.
+ * This initializes the static variable sockaddr.
+ */
+static int
+ipc_create_socket(const char *filename)
+{
+ char *normal_filename;
+ char *parent;
+ const size_t addr_size = sizeof(struct sockaddr_un);
+ const int sock_type = SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
+
+ normalizepath(filename, &normal_filename);
+
+ // In case socket file exists
+ unlink(normal_filename);
+
+ // For portability clear the addr structure, since some implementations have
+ // nonstandard fields in the structure
+ memset(&sockaddr, 0, addr_size);
+
+ parentdir(normal_filename, &parent);
+ // Create parent directories
+ mkdirp(parent);
+ free(parent);
+
+ sockaddr.sun_family = AF_LOCAL;
+ strcpy(sockaddr.sun_path, normal_filename);
+ free(normal_filename);
+
+ sock_fd = socket(AF_LOCAL, sock_type, 0);
+ if (sock_fd == -1) {
+ fputs("Failed to create socket\n", stderr);
+ return -1;
+ }
+
+ DEBUG("Created socket at %s\n", sockaddr.sun_path);
+
+ if (bind(sock_fd, (const struct sockaddr *)&sockaddr, addr_size) == -1) {
+ fputs("Failed to bind socket\n", stderr);
+ return -1;
+ }
+
+ DEBUG("Socket binded\n");
+
+ if (listen(sock_fd, IPC_SOCKET_BACKLOG) < 0) {
+ fputs("Failed to listen for connections on socket\n", stderr);
+ return -1;
+ }
+
+ DEBUG("Now listening for connections on socket\n");
+
+ return sock_fd;
+}
+
+/**
+ * Internal function used to receive IPC messages from a given file descriptor.
+ *
+ * Returns -1 on error reading (could be EAGAIN or EINTR)
+ * Returns -2 if EOF before header could be read
+ * Returns -3 if invalid IPC header
+ * Returns -4 if message length exceeds MAX_MESSAGE_SIZE
+ */
+static int
+ipc_recv_message(int fd, 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) {
+ const ssize_t n = read(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) {
+ // errno will still be set
+ 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);
+
+ if (*reply_size > MAX_MESSAGE_SIZE) {
+ fprintf(stderr, "Message too long: %" PRIu32 " bytes. ", *reply_size);
+ fprintf(stderr, "Maximum message size is: %d\n", MAX_MESSAGE_SIZE);
+ return -4;
+ }
+
+ // Extract message type
+ memcpy(msg_type, walk, sizeof(uint8_t));
+ walk += sizeof(uint8_t);
+
+ if (*reply_size > 0)
+ (*reply) = malloc(*reply_size);
+ else
+ return 0;
+
+ read_bytes = 0;
+ while (read_bytes < *reply_size) {
+ const ssize_t n = read(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) {
+ // TODO: Should we return and wait for another epoll event?
+ // This would require saving the partial read in some way.
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue;
+
+ free(*reply);
+ return -1;
+ }
+
+ read_bytes += n;
+ }
+
+ return 0;
+}
+
+/**
+ * Internal function used to write a buffer to a file descriptor
+ *
+ * Returns number of bytes written if successful write
+ * Returns 0 if no bytes were written due to EAGAIN or EWOULDBLOCK
+ * Returns -1 on unknown error trying to write, errno will carry over from
+ * write() call
+ */
+static ssize_t
+ipc_write_message(int fd, const void *buf, size_t count)
+{
+ size_t written = 0;
+
+ while (written < count) {
+ const ssize_t n = write(fd, (uint8_t *)buf + written, count - written);
+
+ if (n == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return written;
+ else if (errno == EINTR)
+ continue;
+ else
+ return n;
+ }
+
+ written += n;
+ DEBUG("Wrote %zu/%zu to client at fd %d\n", written, count, fd);
+ }
+
+ return written;
+}
+
+/**
+ * Initialization for generic event message. This is used to allocate the yajl
+ * handle, set yajl options, and in the future any other initialization that
+ * should occur for event messages.
+ */
+static void
+ipc_event_init_message(yajl_gen *gen)
+{
+ *gen = yajl_gen_alloc(NULL);
+ yajl_gen_config(*gen, yajl_gen_beautify, 1);
+}
+
+/**
+ * Prepares buffers of IPC subscribers of specified event using buffer from yajl
+ * handle.
+ */
+static void
+ipc_event_prepare_send_message(yajl_gen gen, IPCEvent event)
+{
+ const unsigned char *buffer;
+ size_t len = 0;
+
+ yajl_gen_get_buf(gen, &buffer, &len);
+ len++; // For null char
+
+ for (IPCClient *c = ipc_clients; c; c = c->next) {
+ if (c->subscriptions & event) {
+ DEBUG("Sending selected client change event to fd %d\n", c->fd);
+ ipc_prepare_send_message(c, IPC_TYPE_EVENT, len, (char *)buffer);
+ }
+ }
+
+ // Not documented, but this frees temp_buffer
+ yajl_gen_free(gen);
+}
+
+/**
+ * Initialization for generic reply message. This is used to allocate the yajl
+ * handle, set yajl options, and in the future any other initialization that
+ * should occur for reply messages.
+ */
+static void
+ipc_reply_init_message(yajl_gen *gen)
+{
+ *gen = yajl_gen_alloc(NULL);
+ yajl_gen_config(*gen, yajl_gen_beautify, 1);
+}
+
+/**
+ * Prepares the IPC client's buffer with a message using the buffer of the yajl
+ * handle.
+ */
+static void
+ipc_reply_prepare_send_message(yajl_gen gen, IPCClient *c,
+ IPCMessageType msg_type)
+{
+ const unsigned char *buffer;
+ size_t len = 0;
+
+ yajl_gen_get_buf(gen, &buffer, &len);
+ len++; // For null char
+
+ ipc_prepare_send_message(c, msg_type, len, (const char *)buffer);
+
+ // Not documented, but this frees temp_buffer
+ yajl_gen_free(gen);
+}
+
+/**
+ * Find the IPCCommand with the specified name
+ *
+ * Returns 0 if a command with the specified name was found
+ * Returns -1 if a command with the specified name could not be found
+ */
+static int
+ipc_get_ipc_command(const char *name, IPCCommand *ipc_command)
+{
+ for (int i = 0; i < ipc_commands_len; i++) {
+ if (strcmp(ipc_commands[i].name, name) == 0) {
+ *ipc_command = ipc_commands[i];
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Parse a IPC_TYPE_RUN_COMMAND message from a client. This function extracts
+ * the arguments, argument count, argument types, and command name and returns
+ * the parsed information as an IPCParsedCommand. If this function returns
+ * successfully, the parsed_command must be freed using
+ * ipc_free_parsed_command_members.
+ *
+ * Returns 0 if the message was successfully parsed
+ * Returns -1 otherwise
+ */
+static int
+ipc_parse_run_command(char *msg, IPCParsedCommand *parsed_command)
+{
+ char error_buffer[1000];
+ yajl_val parent = yajl_tree_parse(msg, error_buffer, 1000);
+
+ if (parent == NULL) {
+ fputs("Failed to parse command from client\n", stderr);
+ fprintf(stderr, "%s\n", error_buffer);
+ fprintf(stderr, "Tried to parse: %s\n", msg);
+ return -1;
+ }
+
+ // Format:
+ // {
+ // "command": "<command name>"
+ // "args": [ "arg1", "arg2", ... ]
+ // }
+ const char *command_path[] = {"command", 0};
+ yajl_val command_val = yajl_tree_get(parent, command_path, yajl_t_string);
+
+ if (command_val == NULL) {
+ fputs("No command key found in client message\n", stderr);
+ yajl_tree_free(parent);
+ return -1;
+ }
+
+ const char *command_name = YAJL_GET_STRING(command_val);
+ size_t command_name_len = strlen(command_name);
+ parsed_command->name = (char *)malloc((command_name_len + 1) * sizeof(char));
+ strcpy(parsed_command->name, command_name);
+
+ DEBUG("Received command: %s\n", parsed_command->name);
+
+ const char *args_path[] = {"args", 0};
+ yajl_val args_val = yajl_tree_get(parent, args_path, yajl_t_array);
+
+ if (args_val == NULL) {
+ fputs("No args key found in client message\n", stderr);
+ yajl_tree_free(parent);
+ return -1;
+ }
+
+ unsigned int *argc = &parsed_command->argc;
+ Arg **args = &parsed_command->args;
+ ArgType **arg_types = &parsed_command->arg_types;
+
+ *argc = args_val->u.array.len;
+
+ // If no arguments are specified, make a dummy argument to pass to the
+ // function. This is just the way dwm's void(Arg*) functions are setup.
+ if (*argc == 0) {
+ *args = (Arg *)malloc(sizeof(Arg));
+ *arg_types = (ArgType *)malloc(sizeof(ArgType));
+ (*arg_types)[0] = ARG_TYPE_NONE;
+ (*args)[0].f = 0;
+ (*argc)++;
+ } else if (*argc > 0) {
+ *args = (Arg *)calloc(*argc, sizeof(Arg));
+ *arg_types = (ArgType *)malloc(*argc * sizeof(ArgType));
+
+ for (int i = 0; i < *argc; i++) {
+ yajl_val arg_val = args_val->u.array.values[i];
+
+ if (YAJL_IS_NUMBER(arg_val)) {
+ if (YAJL_IS_INTEGER(arg_val)) {
+ // Any values below 0 must be a signed int
+ if (YAJL_GET_INTEGER(arg_val) < 0) {
+ (*args)[i].i = YAJL_GET_INTEGER(arg_val);
+ (*arg_types)[i] = ARG_TYPE_SINT;
+ DEBUG("i=%ld\n", (*args)[i].i);
+ // Any values above 0 should be an unsigned int
+ } else if (YAJL_GET_INTEGER(arg_val) >= 0) {
+ (*args)[i].ui = YAJL_GET_INTEGER(arg_val);
+ (*arg_types)[i] = ARG_TYPE_UINT;
+ DEBUG("ui=%ld\n", (*args)[i].i);
+ }
+ // If the number is not an integer, it must be a float
+ } else {
+ (*args)[i].f = (float)YAJL_GET_DOUBLE(arg_val);
+ (*arg_types)[i] = ARG_TYPE_FLOAT;
+ DEBUG("f=%f\n", (*args)[i].f);
+ // If argument is not a number, it must be a string
+ }
+ } else if (YAJL_IS_STRING(arg_val)) {
+ char *arg_s = YAJL_GET_STRING(arg_val);
+ size_t arg_s_size = (strlen(arg_s) + 1) * sizeof(char);
+ (*args)[i].v = (char *)malloc(arg_s_size);
+ (*arg_types)[i] = ARG_TYPE_STR;
+ strcpy((char *)(*args)[i].v, arg_s);
+ }
+ }
+ }
+
+ yajl_tree_free(parent);
+
+ return 0;
+}
+
+/**
+ * Free the members of a IPCParsedCommand struct
+ */
+static void
+ipc_free_parsed_command_members(IPCParsedCommand *command)
+{
+ for (int i = 0; i < command->argc; i++) {
+ if (command->arg_types[i] == ARG_TYPE_STR) free((void *)command->args[i].v);
+ }
+ free(command->args);
+ free(command->arg_types);
+ free(command->name);
+}
+
+/**
+ * Check if the given arguments are the correct length and type. Also do any
+ * casting to correct the types.
+ *
+ * Returns 0 if the arguments were the correct length and types
+ * Returns -1 if the argument count doesn't match
+ * Returns -2 if the argument types don't match
+ */
+static int
+ipc_validate_run_command(IPCParsedCommand *parsed, const IPCCommand actual)
+{
+ if (actual.argc != parsed->argc) return -1;
+
+ for (int i = 0; i < parsed->argc; i++) {
+ ArgType ptype = parsed->arg_types[i];
+ ArgType atype = actual.arg_types[i];
+
+ if (ptype != atype) {
+ if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_PTR)
+ // If this argument is supposed to be a void pointer, cast it
+ parsed->args[i].v = (void *)parsed->args[i].ui;
+ else if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_SINT)
+ // If this argument is supposed to be a signed int, cast it
+ parsed->args[i].i = parsed->args[i].ui;
+ else
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Convert event name to their IPCEvent equivalent enum value
+ *
+ * Returns 0 if a valid event name was given
+ * Returns -1 otherwise
+ */
+static int
+ipc_event_stoi(const char *subscription, IPCEvent *event)
+{
+ if (strcmp(subscription, "tag_change_event") == 0)
+ *event = IPC_EVENT_TAG_CHANGE;
+ else if (strcmp(subscription, "client_focus_change_event") == 0)
+ *event = IPC_EVENT_CLIENT_FOCUS_CHANGE;
+ else if (strcmp(subscription, "layout_change_event") == 0)
+ *event = IPC_EVENT_LAYOUT_CHANGE;
+ else if (strcmp(subscription, "monitor_focus_change_event") == 0)
+ *event = IPC_EVENT_MONITOR_FOCUS_CHANGE;
+ else if (strcmp(subscription, "focused_title_change_event") == 0)
+ *event = IPC_EVENT_FOCUSED_TITLE_CHANGE;
+ else if (strcmp(subscription, "focused_state_change_event") == 0)
+ *event = IPC_EVENT_FOCUSED_STATE_CHANGE;
+ else
+ return -1;
+ return 0;
+}
+
+/**
+ * Parse a IPC_TYPE_SUBSCRIBE message from a client. This function extracts the
+ * event name and the subscription action from the message.
+ *
+ * Returns 0 if message was successfully parsed
+ * Returns -1 otherwise
+ */
+static int
+ipc_parse_subscribe(const char *msg, IPCSubscriptionAction *subscribe,
+ IPCEvent *event)
+{
+ char error_buffer[100];
+ yajl_val parent = yajl_tree_parse((char *)msg, error_buffer, 100);
+
+ if (parent == NULL) {
+ fputs("Failed to parse command from client\n", stderr);
+ fprintf(stderr, "%s\n", error_buffer);
+ return -1;
+ }
+
+ // Format:
+ // {
+ // "event": "<event name>"
+ // "action": "<subscribe|unsubscribe>"
+ // }
+ const char *event_path[] = {"event", 0};
+ yajl_val event_val = yajl_tree_get(parent, event_path, yajl_t_string);
+
+ if (event_val == NULL) {
+ fputs("No 'event' key found in client message\n", stderr);
+ return -1;
+ }
+
+ const char *event_str = YAJL_GET_STRING(event_val);
+ DEBUG("Received event: %s\n", event_str);
+
+ if (ipc_event_stoi(event_str, event) < 0) return -1;
+
+ const char *action_path[] = {"action", 0};
+ yajl_val action_val = yajl_tree_get(parent, action_path, yajl_t_string);
+
+ if (action_val == NULL) {
+ fputs("No 'action' key found in client message\n", stderr);
+ return -1;
+ }
+
+ const char *action = YAJL_GET_STRING(action_val);
+
+ if (strcmp(action, "subscribe") == 0)
+ *subscribe = IPC_ACTION_SUBSCRIBE;
+ else if (strcmp(action, "unsubscribe") == 0)
+ *subscribe = IPC_ACTION_UNSUBSCRIBE;
+ else {
+ fputs("Invalid action specified for subscription\n", stderr);
+ return -1;
+ }
+
+ yajl_tree_free(parent);
+
+ return 0;
+}
+
+/**
+ * Parse an IPC_TYPE_GET_DWM_CLIENT message from a client. This function
+ * extracts the window id from the message.
+ *
+ * Returns 0 if message was successfully parsed
+ * Returns -1 otherwise
+ */
+static int
+ipc_parse_get_dwm_client(const char *msg, Window *win)
+{
+ char error_buffer[100];
+
+ yajl_val parent = yajl_tree_parse(msg, error_buffer, 100);
+
+ if (parent == NULL) {
+ fputs("Failed to parse message from client\n", stderr);
+ fprintf(stderr, "%s\n", error_buffer);
+ return -1;
+ }
+
+ // Format:
+ // {
+ // "client_window_id": <client window id>
+ // }
+ const char *win_path[] = {"client_window_id", 0};
+ yajl_val win_val = yajl_tree_get(parent, win_path, yajl_t_number);
+
+ if (win_val == NULL) {
+ fputs("No client window id found in client message\n", stderr);
+ return -1;
+ }
+
+ *win = YAJL_GET_INTEGER(win_val);
+
+ yajl_tree_free(parent);
+
+ return 0;
+}
+
+/**
+ * Called when an IPC_TYPE_RUN_COMMAND message is received from a client. This
+ * function parses, executes the given command, and prepares a reply message to
+ * the client indicating success/failure.
+ *
+ * NOTE: There is currently no check for argument validity beyond the number of
+ * arguments given and types of arguments. There is also no way to check if the
+ * function succeeded based on dwm's void(const Arg*) function types. Pointer
+ * arguments can cause crashes if they are not validated in the function itself.
+ *
+ * Returns 0 if message was successfully parsed
+ * Returns -1 on failure parsing message
+ */
+static int
+ipc_run_command(IPCClient *ipc_client, char *msg)
+{
+ IPCParsedCommand parsed_command;
+ IPCCommand ipc_command;
+
+ // Initialize struct
+ memset(&parsed_command, 0, sizeof(IPCParsedCommand));
+
+ if (ipc_parse_run_command(msg, &parsed_command) < 0) {
+ ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
+ "Failed to parse run command");
+ return -1;
+ }
+
+ if (ipc_get_ipc_command(parsed_command.name, &ipc_command) < 0) {
+ ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
+ "Command %s not found", parsed_command.name);
+ ipc_free_parsed_command_members(&parsed_command);
+ return -1;
+ }
+
+ int res = ipc_validate_run_command(&parsed_command, ipc_command);
+ if (res < 0) {
+ if (res == -1)
+ ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
+ "%u arguments provided, %u expected",
+ parsed_command.argc, ipc_command.argc);
+ else if (res == -2)
+ ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
+ "Type mismatch");
+ ipc_free_parsed_command_members(&parsed_command);
+ return -1;
+ }
+
+ if (parsed_command.argc == 1)
+ ipc_command.func.single_param(parsed_command.args);
+ else if (parsed_command.argc > 1)
+ ipc_command.func.array_param(parsed_command.args, parsed_command.argc);
+
+ DEBUG("Called function for command %s\n", parsed_command.name);
+
+ ipc_free_parsed_command_members(&parsed_command);
+
+ ipc_prepare_reply_success(ipc_client, IPC_TYPE_RUN_COMMAND);
+ return 0;
+}
+
+/**
+ * Called when an IPC_TYPE_GET_MONITORS message is received from a client. It
+ * prepares a reply with the properties of all of the monitors in JSON.
+ */
+static void
+ipc_get_monitors(IPCClient *c, Monitor *mons, Monitor *selmon)
+{
+ yajl_gen gen;
+ ipc_reply_init_message(&gen);
+ dump_monitors(gen, mons, selmon);
+
+ ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_MONITORS);
+}
+
+/**
+ * Called when an IPC_TYPE_GET_TAGS message is received from a client. It
+ * prepares a reply with info about all the tags in JSON.
+ */
+static void
+ipc_get_tags(IPCClient *c, const int tags_len)
+{
+ yajl_gen gen;
+ ipc_reply_init_message(&gen);
+
+ dump_tags(gen, tags_len);
+
+ ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_TAGS);
+}
+
+/**
+ * Called when an IPC_TYPE_GET_LAYOUTS message is received from a client. It
+ * prepares a reply with a JSON array of available layouts
+ */
+static void
+ipc_get_layouts(IPCClient *c, const Layout layouts[], const int layouts_len)
+{
+ yajl_gen gen;
+ ipc_reply_init_message(&gen);
+
+ dump_layouts(gen, layouts, layouts_len);
+
+ ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_LAYOUTS);
+}
+
+/**
+ * Called when an IPC_TYPE_GET_DWM_CLIENT message is received from a client. It
+ * prepares a JSON reply with the properties of the client with the specified
+ * window XID.
+ *
+ * Returns 0 if the message was successfully parsed and if the client with the
+ * specified window XID was found
+ * Returns -1 if the message could not be parsed
+ */
+static int
+ipc_get_dwm_client(IPCClient *ipc_client, const char *msg, const Monitor *mons)
+{
+ Window win;
+
+ if (ipc_parse_get_dwm_client(msg, &win) < 0) return -1;
+
+ // Find client with specified window XID
+ for (const Monitor *m = mons; m; m = m->next)
+ for (Client *c = m->clients; c; c = c->next)
+ if (c->win == win) {
+ yajl_gen gen;
+ ipc_reply_init_message(&gen);
+
+ dump_client(gen, c);
+
+ ipc_reply_prepare_send_message(gen, ipc_client,
+ IPC_TYPE_GET_DWM_CLIENT);
+
+ return 0;
+ }
+
+ ipc_prepare_reply_failure(ipc_client, IPC_TYPE_GET_DWM_CLIENT,
+ "Client with window id %d not found", win);
+ return -1;
+}
+
+/**
+ * Called when an IPC_TYPE_SUBSCRIBE message is received from a client. It
+ * subscribes/unsubscribes the client from the specified event and replies with
+ * the result.
+ *
+ * Returns 0 if the message was successfully parsed.
+ * Returns -1 if the message could not be parsed
+ */
+static int
+ipc_subscribe(IPCClient *c, const char *msg)
+{
+ IPCSubscriptionAction action = IPC_ACTION_SUBSCRIBE;
+ IPCEvent event = 0;
+
+ if (ipc_parse_subscribe(msg, &action, &event)) {
+ ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE, "Event does not exist");
+ return -1;
+ }
+
+ if (action == IPC_ACTION_SUBSCRIBE) {
+ DEBUG("Subscribing client on fd %d to %d\n", c->fd, event);
+ c->subscriptions |= event;
+ } else if (action == IPC_ACTION_UNSUBSCRIBE) {
+ DEBUG("Unsubscribing client on fd %d to %d\n", c->fd, event);
+ c->subscriptions ^= event;
+ } else {
+ ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE,
+ "Invalid subscription action");
+ return -1;
+ }
+
+ ipc_prepare_reply_success(c, IPC_TYPE_SUBSCRIBE);
+ return 0;
+}
+
+int
+ipc_init(const char *socket_path, const int p_epoll_fd, IPCCommand commands[],
+ const int commands_len)
+{
+ // Initialize struct to 0
+ memset(&sock_epoll_event, 0, sizeof(sock_epoll_event));
+
+ int socket_fd = ipc_create_socket(socket_path);
+ if (socket_fd < 0) return -1;
+
+ ipc_commands = commands;
+ ipc_commands_len = commands_len;
+
+ epoll_fd = p_epoll_fd;
+
+ // Wake up to incoming connection requests
+ sock_epoll_event.data.fd = socket_fd;
+ sock_epoll_event.events = EPOLLIN;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &sock_epoll_event)) {
+ fputs("Failed to add sock file descriptor to epoll", stderr);
+ return -1;
+ }
+
+ return socket_fd;
+}
+
+void
+ipc_cleanup()
+{
+ IPCClient *c = ipc_clients;
+ // Free clients and their buffers
+ while (c) {
+ ipc_drop_client(c);
+ c = ipc_clients;
+ }
+
+ // Stop waking up for socket events
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, &sock_epoll_event);
+
+ // Uninitialize all static variables
+ epoll_fd = -1;
+ sock_fd = -1;
+ ipc_commands = NULL;
+ ipc_commands_len = 0;
+ memset(&sock_epoll_event, 0, sizeof(struct epoll_event));
+ memset(&sockaddr, 0, sizeof(struct sockaddr_un));
+
+ // Delete socket
+ unlink(sockaddr.sun_path);
+
+ shutdown(sock_fd, SHUT_RDWR);
+ close(sock_fd);
+}
+
+int
+ipc_get_sock_fd()
+{
+ return sock_fd;
+}
+
+IPCClient *
+ipc_get_client(int fd)
+{
+ return ipc_list_get_client(ipc_clients, fd);
+}
+
+int
+ipc_is_client_registered(int fd)
+{
+ return (ipc_get_client(fd) != NULL);
+}
+
+int
+ipc_accept_client()
+{
+ int fd = -1;
+
+ struct sockaddr_un client_addr;
+ socklen_t len = 0;
+
+ // For portability clear the addr structure, since some implementations
+ // have nonstandard fields in the structure
+ memset(&client_addr, 0, sizeof(struct sockaddr_un));
+
+ fd = accept(sock_fd, (struct sockaddr *)&client_addr, &len);
+ if (fd < 0 && errno != EINTR) {
+ fputs("Failed to accept IPC connection from client", stderr);
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
+ fputs("Failed to set flags on new client fd", stderr);
+ }
+
+ IPCClient *nc = ipc_client_new(fd);
+ if (nc == NULL) return -1;
+
+ // Wake up to messages from this client
+ nc->event.data.fd = fd;
+ nc->event.events = EPOLLIN | EPOLLHUP;
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &nc->event);
+
+ ipc_list_add_client(&ipc_clients, nc);
+
+ DEBUG("%s%d\n", "New client at fd: ", fd);
+
+ return fd;
+}
+
+int
+ipc_drop_client(IPCClient *c)
+{
+ int fd = c->fd;
+ shutdown(fd, SHUT_RDWR);
+ int res = close(fd);
+
+ if (res == 0) {
+ struct epoll_event ev;
+
+ // Stop waking up to messages from this client
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
+ ipc_list_remove_client(&ipc_clients, c);
+
+ free(c->buffer);
+ free(c);
+
+ DEBUG("Successfully removed client on fd %d\n", fd);
+ } else if (res < 0 && res != EINTR) {
+ fprintf(stderr, "Failed to close fd %d\n", fd);
+ }
+
+ return res;
+}
+
+int
+ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size,
+ char **msg)
+{
+ int fd = c->fd;
+ int ret =
+ ipc_recv_message(fd, (uint8_t *)msg_type, msg_size, (uint8_t **)msg);
+
+ if (ret < 0) {
+ // This will happen if these errors occur while reading header
+ if (ret == -1 &&
+ (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
+ return -2;
+
+ fprintf(stderr, "Error reading message: dropping client at fd %d\n", fd);
+ ipc_drop_client(c);
+
+ return -1;
+ }
+
+ // Make sure receive message is null terminated to avoid parsing issues
+ if (*msg_size > 0) {
+ size_t len = *msg_size;
+ nullterminate(msg, &len);
+ *msg_size = len;
+ }
+
+ DEBUG("[fd %d] ", fd);
+ if (*msg_size > 0)
+ DEBUG("Received message: '%.*s' ", *msg_size, *msg);
+ else
+ DEBUG("Received empty message ");
+ DEBUG("Message type: %" PRIu8 " ", (uint8_t)*msg_type);
+ DEBUG("Message size: %" PRIu32 "\n", *msg_size);
+
+ return 0;
+}
+
+ssize_t
+ipc_write_client(IPCClient *c)
+{
+ const ssize_t n = ipc_write_message(c->fd, c->buffer, c->buffer_size);
+
+ if (n < 0) return n;
+
+ // TODO: Deal with client timeouts
+
+ if (n == c->buffer_size) {
+ c->buffer_size = 0;
+ free(c->buffer);
+ // No dangling pointers!
+ c->buffer = NULL;
+ // Stop waking up when client is ready to receive messages
+ if (c->event.events & EPOLLOUT) {
+ c->event.events -= EPOLLOUT;
+ epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event);
+ }
+ return n;
+ }
+
+ // Shift unwritten buffer to beginning of buffer and reallocate
+ c->buffer_size -= n;
+ memmove(c->buffer, c->buffer + n, c->buffer_size);
+ c->buffer = (char *)realloc(c->buffer, c->buffer_size);
+
+ return n;
+}
+
+void
+ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type,
+ const uint32_t msg_size, const char *msg)
+{
+ dwm_ipc_header_t header = {
+ .magic = IPC_MAGIC_ARR, .type = msg_type, .size = msg_size};
+
+ uint32_t header_size = sizeof(dwm_ipc_header_t);
+ uint32_t packet_size = header_size + msg_size;
+
+ if (c->buffer == NULL)
+ c->buffer = (char *)malloc(c->buffer_size + packet_size);
+ else
+ c->buffer = (char *)realloc(c->buffer, c->buffer_size + packet_size);
+
+ // Copy header to end of client buffer
+ memcpy(c->buffer + c->buffer_size, &header, header_size);
+ c->buffer_size += header_size;
+
+ // Copy message to end of client buffer
+ memcpy(c->buffer + c->buffer_size, msg, msg_size);
+ c->buffer_size += msg_size;
+
+ // Wake up when client is ready to receive messages
+ c->event.events |= EPOLLOUT;
+ epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event);
+}
+
+void
+ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type,
+ const char *format, ...)
+{
+ yajl_gen gen;
+ va_list args;
+
+ // Get output size
+ va_start(args, format);
+ size_t len = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+ char *buffer = (char *)malloc((len + 1) * sizeof(char));
+
+ ipc_reply_init_message(&gen);
+
+ va_start(args, format);
+ vsnprintf(buffer, len + 1, format, args);
+ va_end(args);
+ dump_error_message(gen, buffer);
+
+ ipc_reply_prepare_send_message(gen, c, msg_type);
+ fprintf(stderr, "[fd %d] Error: %s\n", c->fd, buffer);
+
+ free(buffer);
+}
+
+void
+ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type)
+{
+ const char *success_msg = "{\"result\":\"success\"}";
+ const size_t msg_len = strlen(success_msg) + 1; // +1 for null char
+
+ ipc_prepare_send_message(c, msg_type, msg_len, success_msg);
+}
+
+void
+ipc_tag_change_event(int mon_num, TagState old_state, TagState new_state)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_tag_event(gen, mon_num, old_state, new_state);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_TAG_CHANGE);
+}
+
+void
+ipc_client_focus_change_event(int mon_num, Client *old_client,
+ Client *new_client)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_client_focus_change_event(gen, old_client, new_client, mon_num);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_CLIENT_FOCUS_CHANGE);
+}
+
+void
+ipc_layout_change_event(const int mon_num, const char *old_symbol,
+ const Layout *old_layout, const char *new_symbol,
+ const Layout *new_layout)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_layout_change_event(gen, mon_num, old_symbol, old_layout, new_symbol,
+ new_layout);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_LAYOUT_CHANGE);
+}
+
+void
+ipc_monitor_focus_change_event(const int last_mon_num, const int new_mon_num)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_monitor_focus_change_event(gen, last_mon_num, new_mon_num);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_MONITOR_FOCUS_CHANGE);
+}
+
+void
+ipc_focused_title_change_event(const int mon_num, const Window client_id,
+ const char *old_name, const char *new_name)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_focused_title_change_event(gen, mon_num, client_id, old_name, new_name);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_TITLE_CHANGE);
+}
+
+void
+ipc_focused_state_change_event(const int mon_num, const Window client_id,
+ const ClientState *old_state,
+ const ClientState *new_state)
+{
+ yajl_gen gen;
+ ipc_event_init_message(&gen);
+ dump_focused_state_change_event(gen, mon_num, client_id, old_state,
+ new_state);
+ ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_STATE_CHANGE);
+}
+
+void
+ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon)
+{
+ for (Monitor *m = mons; m; m = m->next) {
+ unsigned int urg = 0, occ = 0, tagset = 0;
+
+ for (Client *c = m->clients; c; c = c->next) {
+ occ |= c->tags;
+
+ if (c->isurgent) urg |= c->tags;
+ }
+ tagset = m->tagset[m->seltags];
+
+ TagState new_state = {.selected = tagset, .occupied = occ, .urgent = urg};
+
+ if (memcmp(&m->tagstate, &new_state, sizeof(TagState)) != 0) {
+ ipc_tag_change_event(m->num, m->tagstate, new_state);
+ m->tagstate = new_state;
+ }
+
+ if (m->lastsel != m->sel) {
+ ipc_client_focus_change_event(m->num, m->lastsel, m->sel);
+ m->lastsel = m->sel;
+ }
+
+ if (strcmp(m->ltsymbol, m->lastltsymbol) != 0 ||
+ m->lastlt != m->lt[m->sellt]) {
+ ipc_layout_change_event(m->num, m->lastltsymbol, m->lastlt, m->ltsymbol,
+ m->lt[m->sellt]);
+ strcpy(m->lastltsymbol, m->ltsymbol);
+ m->lastlt = m->lt[m->sellt];
+ }
+
+ if (*lastselmon != selmon) {
+ if (*lastselmon != NULL)
+ ipc_monitor_focus_change_event((*lastselmon)->num, selmon->num);
+ *lastselmon = selmon;
+ }
+
+ Client *sel = m->sel;
+ if (!sel) continue;
+ ClientState *o = &m->sel->prevstate;
+ ClientState n = {.oldstate = sel->oldstate,
+ .isfixed = sel->isfixed,
+ .isfloating = sel->isfloating,
+ .isfullscreen = sel->isfullscreen,
+ .isurgent = sel->isurgent,
+ .neverfocus = sel->neverfocus};
+ if (memcmp(o, &n, sizeof(ClientState)) != 0) {
+ ipc_focused_state_change_event(m->num, m->sel->win, o, &n);
+ *o = n;
+ }
+ }
+}
+
+int
+ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons,
+ Monitor **lastselmon, Monitor *selmon, const int tags_len,
+ const Layout *layouts, const int layouts_len)
+{
+ int fd = ev->data.fd;
+ IPCClient *c = ipc_get_client(fd);
+
+ if (ev->events & EPOLLHUP) {
+ DEBUG("EPOLLHUP received from client at fd %d\n", fd);
+ ipc_drop_client(c);
+ } else if (ev->events & EPOLLOUT) {
+ DEBUG("Sending message to client at fd %d...\n", fd);
+ if (c->buffer_size) ipc_write_client(c);
+ } else if (ev->events & EPOLLIN) {
+ IPCMessageType msg_type = 0;
+ uint32_t msg_size = 0;
+ char *msg = NULL;
+
+ DEBUG("Received message from fd %d\n", fd);
+ if (ipc_read_client(c, &msg_type, &msg_size, &msg) < 0) return -1;
+
+ if (msg_type == IPC_TYPE_GET_MONITORS)
+ ipc_get_monitors(c, mons, selmon);
+ else if (msg_type == IPC_TYPE_GET_TAGS)
+ ipc_get_tags(c, tags_len);
+ else if (msg_type == IPC_TYPE_GET_LAYOUTS)
+ ipc_get_layouts(c, layouts, layouts_len);
+ else if (msg_type == IPC_TYPE_RUN_COMMAND) {
+ if (ipc_run_command(c, msg) < 0) return -1;
+ ipc_send_events(mons, lastselmon, selmon);
+ } else if (msg_type == IPC_TYPE_GET_DWM_CLIENT) {
+ if (ipc_get_dwm_client(c, msg, mons) < 0) return -1;
+ } else if (msg_type == IPC_TYPE_SUBSCRIBE) {
+ if (ipc_subscribe(c, msg) < 0) return -1;
+ } else {
+ fprintf(stderr, "Invalid message type received from fd %d", fd);
+ ipc_prepare_reply_failure(c, msg_type, "Invalid message type: %d",
+ msg_type);
+ }
+ free(msg);
+ } else {
+ fprintf(stderr, "Epoll event returned %d from fd %d\n", ev->events, fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ipc_handle_socket_epoll_event(struct epoll_event *ev)
+{
+ if (!(ev->events & EPOLLIN)) return -1;
+
+ // EPOLLIN means incoming client connection request
+ fputs("Received EPOLLIN event on socket\n", stderr);
+ int new_fd = ipc_accept_client();
+
+ return new_fd;
+}
+
diff --git a/patch/ipc/ipc.h b/patch/ipc/ipc.h
new file mode 100644
index 0000000..4a72fb8
--- /dev/null
+++ b/patch/ipc/ipc.h
@@ -0,0 +1,320 @@
+#ifndef IPC_H_
+#define IPC_H_
+
+#include <stdint.h>
+#include <sys/epoll.h>
+#include <yajl/yajl_gen.h>
+
+#include "IPCClient.h"
+
+// clang-format off
+#define IPC_MAGIC "DWM-IPC"
+#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C'}
+#define IPC_MAGIC_LEN 7 // Not including null char
+
+#define IPCCOMMAND(FUNC, ARGC, TYPES) \
+ { #FUNC, {FUNC }, ARGC, (ArgType[ARGC])TYPES }
+// clang-format on
+
+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;
+
+typedef enum IPCEvent {
+ IPC_EVENT_TAG_CHANGE = 1 << 0,
+ IPC_EVENT_CLIENT_FOCUS_CHANGE = 1 << 1,
+ IPC_EVENT_LAYOUT_CHANGE = 1 << 2,
+ IPC_EVENT_MONITOR_FOCUS_CHANGE = 1 << 3,
+ IPC_EVENT_FOCUSED_TITLE_CHANGE = 1 << 4,
+ IPC_EVENT_FOCUSED_STATE_CHANGE = 1 << 5
+} IPCEvent;
+
+typedef enum IPCSubscriptionAction {
+ IPC_ACTION_UNSUBSCRIBE = 0,
+ IPC_ACTION_SUBSCRIBE = 1
+} IPCSubscriptionAction;
+
+/**
+ * Every IPC packet starts with this structure
+ */
+typedef struct dwm_ipc_header {
+ uint8_t magic[IPC_MAGIC_LEN];
+ uint32_t size;
+ uint8_t type;
+} __attribute((packed)) dwm_ipc_header_t;
+
+typedef enum ArgType {
+ ARG_TYPE_NONE = 0,
+ ARG_TYPE_UINT = 1,
+ ARG_TYPE_SINT = 2,
+ ARG_TYPE_FLOAT = 3,
+ ARG_TYPE_PTR = 4,
+ ARG_TYPE_STR = 5
+} ArgType;
+
+/**
+ * An IPCCommand function can have either of these function signatures
+ */
+typedef union ArgFunction {
+ void (*single_param)(const Arg *);
+ void (*array_param)(const Arg *, int);
+} ArgFunction;
+
+typedef struct IPCCommand {
+ char *name;
+ ArgFunction func;
+ unsigned int argc;
+ ArgType *arg_types;
+} IPCCommand;
+
+typedef struct IPCParsedCommand {
+ char *name;
+ Arg *args;
+ ArgType *arg_types;
+ unsigned int argc;
+} IPCParsedCommand;
+
+/**
+ * Initialize the IPC socket and the IPC module
+ *
+ * @param socket_path Path to create the socket at
+ * @param epoll_fd File descriptor for epoll
+ * @param commands Address of IPCCommands array defined in config.h
+ * @param commands_len Length of commands[] array
+ *
+ * @return int The file descriptor of the socket if it was successfully created,
+ * -1 otherwise
+ */
+int ipc_init(const char *socket_path, const int p_epoll_fd,
+ IPCCommand commands[], const int commands_len);
+
+/**
+ * Uninitialize the socket and module. Free allocated memory and restore static
+ * variables to their state before ipc_init
+ */
+void ipc_cleanup();
+
+/**
+ * Get the file descriptor of the IPC socket
+ *
+ * @return int File descriptor of IPC socket, -1 if socket not created.
+ */
+int ipc_get_sock_fd();
+
+/**
+ * Get address to IPCClient with specified file descriptor
+ *
+ * @param fd File descriptor of IPC Client
+ *
+ * @return Address to IPCClient with specified file descriptor, -1 otherwise
+ */
+IPCClient *ipc_get_client(int fd);
+
+/**
+ * Check if an IPC client exists with the specified file descriptor
+ *
+ * @param fd File descriptor
+ *
+ * @return int 1 if client exists, 0 otherwise
+ */
+int ipc_is_client_registered(int fd);
+
+/**
+ * Disconnect an IPCClient from the socket and remove the client from the list
+ * of known connected clients
+ *
+ * @param c Address of IPCClient
+ *
+ * @return 0 if the client's file descriptor was closed successfully, the
+ * result of executing close() on the file descriptor otherwise.
+ */
+int ipc_drop_client(IPCClient *c);
+
+/**
+ * Accept an IPC Client requesting to connect to the socket and add it to the
+ * list of clients
+ *
+ * @return File descriptor of new client, -1 on error
+ */
+int ipc_accept_client();
+
+/**
+ * Read an incoming message from an accepted IPC client
+ *
+ * @param c Address of IPCClient
+ * @param msg_type Address to IPCMessageType variable which will be assigned
+ * the message type of the received message
+ * @param msg_size Address to uint32_t variable which will be assigned the size
+ * of the received message
+ * @param msg Address to char* variable which will be assigned the address of
+ * the received message. This must be freed using free().
+ *
+ * @return 0 on success, -1 on error reading message, -2 if reading the message
+ * resulted in EAGAIN, EINTR, or EWOULDBLOCK.
+ */
+int ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size,
+ char **msg);
+
+/**
+ * Write any pending buffer of the client to the client's socket
+ *
+ * @param c Client whose buffer to write
+ *
+ * @return Number of bytes written >= 0, -1 otherwise. errno will still be set
+ * from the write operation.
+ */
+ssize_t ipc_write_client(IPCClient *c);
+
+/**
+ * Prepare a message in the specified client's buffer.
+ *
+ * @param c Client to prepare message for
+ * @param msg_type Type of message to prepare
+ * @param msg_size Size of the message in bytes. Should not exceed
+ * MAX_MESSAGE_SIZE
+ * @param msg Message to prepare (not including header). This pointer can be
+ * freed after the function invocation.
+ */
+void ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type,
+ const uint32_t msg_size, const char *msg);
+
+/**
+ * Prepare an error message in the specified client's buffer
+ *
+ * @param c Client to prepare message for
+ * @param msg_type Type of message
+ * @param format Format string following vsprintf
+ * @param ... Arguments for format string
+ */
+void ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type,
+ const char *format, ...);
+
+/**
+ * Prepare a success message in the specified client's buffer
+ *
+ * @param c Client to prepare message for
+ * @param msg_type Type of message
+ */
+void ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type);
+
+/**
+ * Send a tag_change_event to all subscribers. Should be called only when there
+ * has been a tag state change.
+ *
+ * @param mon_num The index of the monitor (Monitor.num property)
+ * @param old_state The old tag state
+ * @param new_state The new (now current) tag state
+ */
+void ipc_tag_change_event(const int mon_num, TagState old_state,
+ TagState new_state);
+
+/**
+ * Send a client_focus_change_event to all subscribers. Should be called only
+ * when the client focus changes.
+ *
+ * @param mon_num The index of the monitor (Monitor.num property)
+ * @param old_client The old DWM client selection (Monitor.oldsel)
+ * @param new_client The new (now current) DWM client selection
+ */
+void ipc_client_focus_change_event(const int mon_num, Client *old_client,
+ Client *new_client);
+
+/**
+ * Send a layout_change_event to all subscribers. Should be called only
+ * when there has been a layout change.
+ *
+ * @param mon_num The index of the monitor (Monitor.num property)
+ * @param old_symbol The old layout symbol
+ * @param old_layout Address to the old Layout
+ * @param new_symbol The new (now current) layout symbol
+ * @param new_layout Address to the new Layout
+ */
+void ipc_layout_change_event(const int mon_num, const char *old_symbol,
+ const Layout *old_layout, const char *new_symbol,
+ const Layout *new_layout);
+
+/**
+ * Send a monitor_focus_change_event to all subscribers. Should be called only
+ * when the monitor focus changes.
+ *
+ * @param last_mon_num The index of the previously selected monitor
+ * @param new_mon_num The index of the newly selected monitor
+ */
+void ipc_monitor_focus_change_event(const int last_mon_num,
+ const int new_mon_num);
+
+/**
+ * Send a focused_title_change_event to all subscribers. Should only be called
+ * if a selected client has a title change.
+ *
+ * @param mon_num Index of the client's monitor
+ * @param client_id Window XID of client
+ * @param old_name Old name of the client window
+ * @param new_name New name of the client window
+ */
+void ipc_focused_title_change_event(const int mon_num, const Window client_id,
+ const char *old_name, const char *new_name);
+
+/**
+ * Send a focused_state_change_event to all subscribers. Should only be called
+ * if a selected client has a state change.
+ *
+ * @param mon_num Index of the client's monitor
+ * @param client_id Window XID of client
+ * @param old_state Old state of the client
+ * @param new_state New state of the client
+ */
+void ipc_focused_state_change_event(const int mon_num, const Window client_id,
+ const ClientState *old_state,
+ const ClientState *new_state);
+/**
+ * Check to see if an event has occured and call the *_change_event functions
+ * accordingly
+ *
+ * @param mons Address of Monitor pointing to start of linked list
+ * @param lastselmon Address of pointer to previously selected monitor
+ * @param selmon Address of selected Monitor
+ */
+void ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon);
+
+/**
+ * Handle an epoll event caused by a registered IPC client. Read, process, and
+ * handle any received messages from clients. Write pending buffer to client if
+ * the client is ready to receive messages. Drop clients that have sent an
+ * EPOLLHUP.
+ *
+ * @param ev Associated epoll event returned by epoll_wait
+ * @param mons Address of Monitor pointing to start of linked list
+ * @param selmon Address of selected Monitor
+ * @param lastselmon Address of pointer to previously selected monitor
+ * @param tags Array of tag names
+ * @param tags_len Length of tags array
+ * @param layouts Array of available layouts
+ * @param layouts_len Length of layouts array
+ *
+ * @return 0 if event was successfully handled, -1 on any error receiving
+ * or handling incoming messages or unhandled epoll event.
+ */
+int ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons,
+ Monitor **lastselmon, Monitor *selmon, const int tags_len,
+ const Layout *layouts, const int layouts_len);
+
+/**
+ * Handle an epoll event caused by the IPC socket. This function only handles an
+ * EPOLLIN event indicating a new client requesting to connect to the socket.
+ *
+ * @param ev Associated epoll event returned by epoll_wait
+ *
+ * @return 0, if the event was successfully handled, -1 if not an EPOLLIN event
+ * or if a new IPC client connection request could not be accepted.
+ */
+int ipc_handle_socket_epoll_event(struct epoll_event *ev);
+
+#endif /* IPC_H_ */
+
diff --git a/patch/ipc/util.c b/patch/ipc/util.c
new file mode 100644
index 0000000..7ea425e
--- /dev/null
+++ b/patch/ipc/util.c
@@ -0,0 +1,136 @@
+#include <errno.h>
+#include <sys/stat.h>
+
+int
+normalizepath(const char *path, char **normal)
+{
+ size_t len = strlen(path);
+ *normal = (char *)malloc((len + 1) * sizeof(char));
+ const char *walk = path;
+ const char *match;
+ size_t newlen = 0;
+
+ while ((match = strchr(walk, '/'))) {
+ // Copy everything between match and walk
+ strncpy(*normal + newlen, walk, match - walk);
+ newlen += match - walk;
+ walk += match - walk;
+
+ // Skip all repeating slashes
+ while (*walk == '/')
+ walk++;
+
+ // If not last character in path
+ if (walk != path + len)
+ (*normal)[newlen++] = '/';
+ }
+
+ (*normal)[newlen++] = '\0';
+
+ // Copy remaining path
+ strcat(*normal, walk);
+ newlen += strlen(walk);
+
+ *normal = (char *)realloc(*normal, newlen * sizeof(char));
+
+ return 0;
+}
+
+int
+parentdir(const char *path, char **parent)
+{
+ char *normal;
+ char *walk;
+
+ normalizepath(path, &normal);
+
+ // Pointer to last '/'
+ if (!(walk = strrchr(normal, '/'))) {
+ free(normal);
+ return -1;
+ }
+
+ // Get path up to last '/'
+ size_t len = walk - normal;
+ *parent = (char *)malloc((len + 1) * sizeof(char));
+
+ // Copy path up to last '/'
+ strncpy(*parent, normal, len);
+ // Add null char
+ (*parent)[len] = '\0';
+
+ free(normal);
+
+ return 0;
+}
+
+int
+mkdirp(const char *path)
+{
+ char *normal;
+ char *walk;
+ size_t normallen;
+
+ normalizepath(path, &normal);
+ normallen = strlen(normal);
+ walk = normal;
+
+ while (walk < normal + normallen + 1) {
+ // Get length from walk to next /
+ size_t n = strcspn(walk, "/");
+
+ // Skip path /
+ if (n == 0) {
+ walk++;
+ continue;
+ }
+
+ // Length of current path segment
+ size_t curpathlen = walk - normal + n;
+ char curpath[curpathlen + 1];
+ struct stat s;
+
+ // Copy path segment to stat
+ strncpy(curpath, normal, curpathlen);
+ strcpy(curpath + curpathlen, "");
+ int res = stat(curpath, &s);
+
+ if (res < 0) {
+ if (errno == ENOENT) {
+ DEBUG("Making directory %s\n", curpath);
+ if (mkdir(curpath, 0700) < 0) {
+ fprintf(stderr, "Failed to make directory %s\n", curpath);
+ perror("");
+ free(normal);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Error statting directory %s\n", curpath);
+ perror("");
+ free(normal);
+ return -1;
+ }
+ }
+
+ // Continue to next path segment
+ walk += n;
+ }
+
+ free(normal);
+
+ return 0;
+}
+
+int
+nullterminate(char **str, size_t *len)
+{
+ if ((*str)[*len - 1] == '\0')
+ return 0;
+
+ (*len)++;
+ *str = (char*)realloc(*str, *len * sizeof(char));
+ (*str)[*len - 1] = '\0';
+
+ return 0;
+}
+
diff --git a/patch/ipc/util.h b/patch/ipc/util.h
new file mode 100644
index 0000000..8d2a626
--- /dev/null
+++ b/patch/ipc/util.h
@@ -0,0 +1,5 @@
+int normalizepath(const char *path, char **normal);
+int mkdirp(const char *path);
+int parentdir(const char *path, char **parent);
+int nullterminate(char **str, size_t *len);
+
diff --git a/patch/ipc/yajl_dumps.c b/patch/ipc/yajl_dumps.c
new file mode 100644
index 0000000..b24a429
--- /dev/null
+++ b/patch/ipc/yajl_dumps.c
@@ -0,0 +1,356 @@
+#include "yajl_dumps.h"
+
+#include <stdint.h>
+
+int
+dump_tag(yajl_gen gen, const char *name, const int tag_mask)
+{
+ if (!name)
+ return 0;
+
+ // clang-format off
+ YMAP(
+ YSTR("bit_mask"); YINT(tag_mask);
+ YSTR("name"); YSTR(name);
+ )
+ // clang-format on
+ return 0;
+}
+
+int
+dump_tags(yajl_gen gen, int tags_len)
+{
+ // clang-format off
+ YARR(
+ for (int i = 0; i < tags_len; i++)
+ dump_tag(gen, tagicon(mons, i), 1 << i);
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_client(yajl_gen gen, Client *c)
+{
+ // clang-format off
+ YMAP(
+ YSTR("name"); YSTR(c->name);
+ YSTR("tags"); YINT(c->tags);
+ YSTR("window_id"); YINT(c->win);
+ YSTR("monitor_number"); YINT(c->mon->num);
+
+ YSTR("geometry"); YMAP(
+ YSTR("current"); YMAP (
+ YSTR("x"); YINT(c->x);
+ YSTR("y"); YINT(c->y);
+ YSTR("width"); YINT(c->w);
+ YSTR("height"); YINT(c->h);
+ )
+ YSTR("old"); YMAP(
+ YSTR("x"); YINT(c->oldx);
+ YSTR("y"); YINT(c->oldy);
+ YSTR("width"); YINT(c->oldw);
+ YSTR("height"); YINT(c->oldh);
+ )
+ )
+
+ YSTR("size_hints"); YMAP(
+ YSTR("base"); YMAP(
+ YSTR("width"); YINT(c->basew);
+ YSTR("height"); YINT(c->baseh);
+ )
+ YSTR("step"); YMAP(
+ YSTR("width"); YINT(c->incw);
+ YSTR("height"); YINT(c->inch);
+ )
+ YSTR("max"); YMAP(
+ YSTR("width"); YINT(c->maxw);
+ YSTR("height"); YINT(c->maxh);
+ )
+ YSTR("min"); YMAP(
+ YSTR("width"); YINT(c->minw);
+ YSTR("height"); YINT(c->minh);
+ )
+ YSTR("aspect_ratio"); YMAP(
+ YSTR("min"); YDOUBLE(c->mina);
+ YSTR("max"); YDOUBLE(c->maxa);
+ )
+ )
+
+ YSTR("border_width"); YMAP(
+ YSTR("current"); YINT(c->bw);
+ YSTR("old"); YINT(c->oldbw);
+ )
+
+ YSTR("states"); YMAP(
+ YSTR("is_fixed"); YBOOL(c->isfixed);
+ YSTR("is_floating"); YBOOL(c->isfloating);
+ YSTR("is_urgent"); YBOOL(c->isurgent);
+ YSTR("never_focus"); YBOOL(c->neverfocus);
+ YSTR("old_state"); YBOOL(c->oldstate);
+ YSTR("is_fullscreen"); YBOOL(c->isfullscreen);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_monitor(yajl_gen gen, Monitor *mon, int is_selected)
+{
+ // clang-format off
+ YMAP(
+ YSTR("master_factor"); YDOUBLE(mon->mfact);
+ YSTR("num_master"); YINT(mon->nmaster);
+ YSTR("num"); YINT(mon->num);
+ YSTR("is_selected"); YBOOL(is_selected);
+
+ YSTR("monitor_geometry"); YMAP(
+ YSTR("x"); YINT(mon->mx);
+ YSTR("y"); YINT(mon->my);
+ YSTR("width"); YINT(mon->mw);
+ YSTR("height"); YINT(mon->mh);
+ )
+
+ YSTR("window_geometry"); YMAP(
+ YSTR("x"); YINT(mon->wx);
+ YSTR("y"); YINT(mon->wy);
+ YSTR("width"); YINT(mon->ww);
+ YSTR("height"); YINT(mon->wh);
+ )
+
+ YSTR("tagset"); YMAP(
+ YSTR("current"); YINT(mon->tagset[mon->seltags]);
+ YSTR("old"); YINT(mon->tagset[mon->seltags ^ 1]);
+ )
+
+ YSTR("tag_state"); dump_tag_state(gen, mon->tagstate);
+
+ YSTR("clients"); YMAP(
+ YSTR("selected"); YINT(mon->sel ? mon->sel->win : 0);
+ YSTR("stack"); YARR(
+ for (Client* c = mon->stack; c; c = c->snext)
+ YINT(c->win);
+ )
+ YSTR("all"); YARR(
+ for (Client* c = mon->clients; c; c = c->next)
+ YINT(c->win);
+ )
+ )
+
+ YSTR("layout"); YMAP(
+ YSTR("symbol"); YMAP(
+ YSTR("current"); YSTR(mon->ltsymbol);
+ YSTR("old"); YSTR(mon->lastltsymbol);
+ )
+ YSTR("address"); YMAP(
+ YSTR("current"); YINT((uintptr_t)mon->lt[mon->sellt]);
+ YSTR("old"); YINT((uintptr_t)mon->lt[mon->sellt ^ 1]);
+ )
+ )
+
+ if (mon->bar) {
+ YSTR("bar"); YMAP(
+ YSTR("y"); YINT(mon->bar->by);
+ YSTR("is_shown"); YBOOL(mon->showbar);
+ YSTR("is_top"); YBOOL(mon->bar->topbar);
+ YSTR("window_id"); YINT(mon->bar->win);
+ )
+ }
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon)
+{
+ // clang-format off
+ YARR(
+ for (Monitor *mon = mons; mon; mon = mon->next) {
+ if (mon == selmon)
+ dump_monitor(gen, mon, 1);
+ else
+ dump_monitor(gen, mon, 0);
+ }
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len)
+{
+ // clang-format off
+ YARR(
+ for (int i = 0; i < layouts_len; i++) {
+ YMAP(
+ // Check for a NULL pointer. The cycle layouts patch adds an entry at
+ // the end of the layouts array with a NULL pointer for the symbol
+ YSTR("symbol"); YSTR((layouts[i].symbol ? layouts[i].symbol : ""));
+ YSTR("address"); YINT((uintptr_t)(layouts + i));
+ )
+ }
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_tag_state(yajl_gen gen, TagState state)
+{
+ // clang-format off
+ YMAP(
+ YSTR("selected"); YINT(state.selected);
+ YSTR("occupied"); YINT(state.occupied);
+ YSTR("urgent"); YINT(state.urgent);
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_tag_event(yajl_gen gen, int mon_num, TagState old_state,
+ TagState new_state)
+{
+ // clang-format off
+ YMAP(
+ YSTR("tag_change_event"); YMAP(
+ YSTR("monitor_number"); YINT(mon_num);
+ YSTR("old_state"); dump_tag_state(gen, old_state);
+ YSTR("new_state"); dump_tag_state(gen, new_state);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_client_focus_change_event(yajl_gen gen, Client *old_client,
+ Client *new_client, int mon_num)
+{
+ // clang-format off
+ YMAP(
+ YSTR("client_focus_change_event"); YMAP(
+ YSTR("monitor_number"); YINT(mon_num);
+ YSTR("old_win_id"); old_client == NULL ? YNULL() : YINT(old_client->win);
+ YSTR("new_win_id"); new_client == NULL ? YNULL() : YINT(new_client->win);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+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)
+{
+ // clang-format off
+ YMAP(
+ YSTR("layout_change_event"); YMAP(
+ YSTR("monitor_number"); YINT(mon_num);
+ YSTR("old_symbol"); YSTR(old_symbol);
+ YSTR("old_address"); YINT((uintptr_t)old_layout);
+ YSTR("new_symbol"); YSTR(new_symbol);
+ YSTR("new_address"); YINT((uintptr_t)new_layout);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num,
+ const int new_mon_num)
+{
+ // clang-format off
+ YMAP(
+ YSTR("monitor_focus_change_event"); YMAP(
+ YSTR("old_monitor_number"); YINT(last_mon_num);
+ YSTR("new_monitor_number"); YINT(new_mon_num);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+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)
+{
+ // clang-format off
+ YMAP(
+ YSTR("focused_title_change_event"); YMAP(
+ YSTR("monitor_number"); YINT(mon_num);
+ YSTR("client_window_id"); YINT(client_id);
+ YSTR("old_name"); YSTR(old_name);
+ YSTR("new_name"); YSTR(new_name);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_client_state(yajl_gen gen, const ClientState *state)
+{
+ // clang-format off
+ YMAP(
+ YSTR("old_state"); YBOOL(state->oldstate);
+ YSTR("is_fixed"); YBOOL(state->isfixed);
+ YSTR("is_floating"); YBOOL(state->isfloating);
+ YSTR("is_fullscreen"); YBOOL(state->isfullscreen);
+ YSTR("is_urgent"); YBOOL(state->isurgent);
+ YSTR("never_focus"); YBOOL(state->neverfocus);
+ )
+ // clang-format on
+
+ return 0;
+}
+
+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)
+{
+ // clang-format off
+ YMAP(
+ YSTR("focused_state_change_event"); YMAP(
+ YSTR("monitor_number"); YINT(mon_num);
+ YSTR("client_window_id"); YINT(client_id);
+ YSTR("old_state"); dump_client_state(gen, old_state);
+ YSTR("new_state"); dump_client_state(gen, new_state);
+ )
+ )
+ // clang-format on
+
+ return 0;
+}
+
+int
+dump_error_message(yajl_gen gen, const char *reason)
+{
+ // clang-format off
+ YMAP(
+ YSTR("result"); YSTR("error");
+ YSTR("reason"); YSTR(reason);
+ )
+ // clang-format on
+
+ 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/keymodes.c b/patch/keymodes.c
new file mode 100644
index 0000000..6f2f840
--- /dev/null
+++ b/patch/keymodes.c
@@ -0,0 +1,144 @@
+/* function implementations */
+void
+clearcmd(const Arg *arg)
+{
+ unsigned int i;
+
+ for (i = 0; i < LENGTH(cmdkeysym); i++) {
+ cmdkeysym[i] = 0;
+ cmdmod[i] = 0;
+ }
+}
+
+void
+grabkeys(void)
+{
+ if (keymode == INSERTMODE) {
+ grabdefkeys();
+ } else if (keymode == COMMANDMODE) {
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ XGrabKey(dpy, AnyKey, AnyModifier, root,
+ True, GrabModeAsync, GrabModeAsync);
+ }
+}
+
+int
+isprotodel(Client *c)
+{
+ int n;
+ Atom *protocols;
+ int ret = 0;
+
+ if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+ while (!ret && n--)
+ ret = protocols[n] == wmatom[WMDelete];
+ XFree(protocols);
+ }
+ return ret;
+}
+
+
+void
+keypress(XEvent *e)
+{
+ unsigned int i, j;
+ Arg a = {0};
+ Bool ismatch = False, maybematch = False;
+ KeySym keysym;
+ XKeyEvent *ev;
+
+ if (keymode == INSERTMODE)
+ keydefpress(e);
+ else if (keymode == COMMANDMODE) {
+ ev = &e->xkey;
+ keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ if (keysym < XK_Shift_L || keysym > XK_Hyper_R) {
+ for (i = 0; i < LENGTH(cmdkeys); i++)
+ if (keysym == cmdkeys[i].keysym
+ && CLEANMASK(cmdkeys[i].mod) == CLEANMASK(ev->state)
+ && cmdkeys[i].func) {
+ cmdkeys[i].func(&(cmdkeys[i].arg));
+ ismatch = True;
+ break;
+ }
+ if (!ismatch) {
+ for (j = 0; j < LENGTH(cmdkeysym); j++)
+ if (cmdkeysym[j] == 0) {
+ cmdkeysym[j] = keysym;
+ cmdmod[j] = ev->state;
+ break;
+ }
+ for (i = 0; i < LENGTH(commands); i++) {
+ for (j = 0; j < LENGTH(cmdkeysym); j++) {
+ if (cmdkeysym[j] == commands[i].keysym[j]
+ && CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j]))
+ ismatch = True;
+ else if (cmdkeysym[j] == 0
+ && cmdmod[j] == 0) {
+ ismatch = False;
+ maybematch = True;
+ break;
+ } else {
+ ismatch = False;
+ break;
+ }
+ }
+ if (ismatch) {
+ if (commands[i].func)
+ commands[i].func(&(commands[i].arg));
+ clearcmd(&a);
+ break;
+ }
+
+ }
+ if (!maybematch)
+ clearcmd(&a);
+ }
+ }
+ }
+}
+
+void
+onlyclient(const Arg *arg)
+{
+ Client *c;
+ XEvent ev;
+
+ if (!selmon->sel)
+ return;
+ for (c = selmon->clients; c; c = c->next) {
+ if (c != selmon->sel && ISVISIBLE(c)) {
+ if (isprotodel(c)) {
+ ev.type = ClientMessage;
+ ev.xclient.window = c->win;
+ ev.xclient.message_type = wmatom[WMProtocols];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = wmatom[WMDelete];
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+ }
+ else {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+ XKillClient(dpy, c->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+ }
+ }
+}
+
+void
+setkeymode(const Arg *arg)
+{
+ Arg a = {0};
+
+ if (!arg)
+ return;
+ keymode = arg->ui;
+ clearcmd(&a);
+ grabkeys();
+}
+
diff --git a/patch/keymodes.h b/patch/keymodes.h
new file mode 100644
index 0000000..0a46125
--- /dev/null
+++ b/patch/keymodes.h
@@ -0,0 +1,22 @@
+#define COMMANDMODE 1
+#define INSERTMODE 2
+
+typedef struct {
+ unsigned int mod[4];
+ KeySym keysym[4];
+ void (*func)(const Arg *);
+ const Arg arg;
+} Command;
+
+static void clearcmd(const Arg *arg);
+static void grabkeys(void);
+static int isprotodel(Client *c);
+static void keypress(XEvent *e);
+static void onlyclient(const Arg *arg);
+static void setkeymode(const Arg *arg);
+
+/* variables */
+static unsigned int cmdmod[4];
+static unsigned int keymode = INSERTMODE;
+static KeySym cmdkeysym[4];
+
diff --git a/patch/killunsel.c b/patch/killunsel.c
new file mode 100644
index 0000000..8d7a7b8
--- /dev/null
+++ b/patch/killunsel.c
@@ -0,0 +1,28 @@
+void
+killunsel(const Arg *arg)
+{
+ Client *i = NULL;
+
+ if (!selmon->sel)
+ return;
+
+ for (i = selmon->clients; i; i = i->next) {
+ if (ISVISIBLE(i) && i != selmon->sel) {
+ #if BAR_SYSTRAY_PATCH
+ if (!sendevent(i->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0))
+ #else
+ if (!sendevent(i, wmatom[WMDelete]))
+ #endif // BAR_SYSTRAY_PATCH
+ {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+ XKillClient(dpy, i->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+ }
+ }
+}
+
diff --git a/patch/killunsel.h b/patch/killunsel.h
new file mode 100644
index 0000000..4fc154f
--- /dev/null
+++ b/patch/killunsel.h
@@ -0,0 +1,2 @@
+static void killunsel(const Arg *arg);
+
diff --git a/patch/layout_bstack.c b/patch/layout_bstack.c
new file mode 100644
index 0000000..8989975
--- /dev/null
+++ b/patch/layout_bstack.c
@@ -0,0 +1,75 @@
+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;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
+ sw = m->ww - 2*ov - iv * (n - m->nmaster - 1);
+
+ if (m->nmaster && n > m->nmaster) {
+ sh = (mh - ih) * (1 - m->mfact);
+ mh = (mh - ih) * m->mfact;
+ sx = mx;
+ sy = my + mh + ih;
+ }
+ #else
+ 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;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ 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) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ mx += WIDTH(c) + iv;
+ #else
+ mx += WIDTH(c);
+ #endif
+ } else {
+ #if CFACTS_PATCH
+ resize(c, sx, sy, (sw / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sx += WIDTH(c) + iv;
+ #else
+ sx += WIDTH(c);
+ #endif
+ }
+ }
+}
+
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_bstackhoriz.c b/patch/layout_bstackhoriz.c
new file mode 100644
index 0000000..462301c
--- /dev/null
+++ b/patch/layout_bstackhoriz.c
@@ -0,0 +1,77 @@
+static void
+bstackhoriz(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;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ mh = m->wh - 2*oh;
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
+ sw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sh = (mh - ih) * (1 - m->mfact);
+ mh = (mh - ih) * m->mfact;
+ sy = my + mh + ih;
+ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster);
+ }
+ #else
+ 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;
+ sh = m->wh - mh;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ mx += WIDTH(c) + iv;
+ #else
+ mx += WIDTH(c);
+ #endif
+ } else {
+ #if CFACTS_PATCH
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sy += HEIGHT(c) + ih;
+ #else
+ sy += HEIGHT(c);
+ #endif
+ }
+ }
+}
+
diff --git a/patch/layout_bstackhoriz.h b/patch/layout_bstackhoriz.h
new file mode 100644
index 0000000..a421d6f
--- /dev/null
+++ b/patch/layout_bstackhoriz.h
@@ -0,0 +1,2 @@
+static void bstackhoriz(Monitor *m);
+
diff --git a/patch/layout_centeredfloatingmaster.c b/patch/layout_centeredfloatingmaster.c
new file mode 100644
index 0000000..6d1aff0
--- /dev/null
+++ b/patch/layout_centeredfloatingmaster.c
@@ -0,0 +1,95 @@
+void
+centeredfloatingmaster(Monitor *m)
+{
+ unsigned int i, n;
+ float mfacts, sfacts;
+ int mrest, srest;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ Client *c;
+
+ #if VANITYGAPS_PATCH
+ float mivf = 1.0; // master inner vertical gap factor
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ mw = m->ww - 2*ov - iv*(n - 1);
+ sw = m->ww - 2*ov - iv*(n - m->nmaster - 1);
+
+ if (m->nmaster && n > m->nmaster) {
+ mivf = 0.8;
+ /* go mfact box in the center if more than nmaster clients */
+ if (m->ww > m->wh) {
+ mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1);
+ mh = m->wh * 0.9;
+ } else {
+ mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1);
+ mh = m->wh * m->mfact;
+ }
+ mx = m->wx + (m->ww - mw) / 2;
+ my = m->wy + (m->wh - mh - 2*oh) / 2;
+
+ sx = m->wx + ov;
+ sy = m->wy + oh;
+ sh = m->wh - 2*oh;
+ }
+ #else
+ sx = mx = m->wx;
+ sy = my = m->wy;
+ sh = mh = m->wh;
+ sw = mw = m->ww;
+
+ if (m->nmaster && n > m->nmaster) {
+ /* go mfact box in the center if more than nmaster clients */
+ if (m->ww > m->wh) {
+ mw = m->ww * m->mfact;
+ mh = m->wh * 0.9;
+ } else {
+ mw = m->ww * 0.9;
+ mh = m->wh * m->mfact;
+ }
+ mx = m->wx + (m->ww - mw) / 2;
+ my = m->wy + (m->wh - mh) / 2;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ 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) {
+ /* nmaster clients are stacked horizontally, in the center of the screen */
+ #if CFACTS_PATCH
+ resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ mx += WIDTH(c) + iv*mivf;
+ #else
+ mx += WIDTH(c);
+ #endif
+ } else {
+ /* stack clients are stacked horizontally */
+ #if CFACTS_PATCH
+ resize(c, sx, sy, (sw / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sx += WIDTH(c) + iv;
+ #else
+ sx += WIDTH(c);
+ #endif
+ }
+}
+
diff --git a/patch/layout_centeredfloatingmaster.h b/patch/layout_centeredfloatingmaster.h
new file mode 100644
index 0000000..66b0b0e
--- /dev/null
+++ b/patch/layout_centeredfloatingmaster.h
@@ -0,0 +1,2 @@
+static void centeredfloatingmaster(Monitor *m);
+
diff --git a/patch/layout_centeredmaster.c b/patch/layout_centeredmaster.c
new file mode 100644
index 0000000..39aa67f
--- /dev/null
+++ b/patch/layout_centeredmaster.c
@@ -0,0 +1,160 @@
+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;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ /* initialize areas */
+ #if VANITYGAPS_PATCH
+ mx = m->wx + ov;
+ my = m->wy + oh;
+ mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
+ mw = m->ww - 2*ov;
+ lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1);
+ rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
+
+ 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 - 2*ov - 2*iv) * m->mfact;
+ lw = (m->ww - mw - 2*ov - 2*iv) / 2;
+ mx += lw + iv;
+ } else {
+ /* ||<---M--->|<-S->|| */
+ mw = (mw - iv) * m->mfact;
+ lw = m->ww - mw - iv - 2*ov;
+ }
+ rw = lw;
+ lx = m->wx + ov;
+ ly = m->wy + oh;
+ rx = mx + mw + iv;
+ ry = m->wy + oh;
+ }
+ #else
+ 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;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ /* calculate facts */
+ #if CFACTS_PATCH
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
+ if (!m->nmaster || n < m->nmaster)
+ mfacts += c->cfact; // total factor of master area
+ else if ((n - m->nmaster) % 2)
+ lfacts += c->cfact; // total factor of left hand stack area
+ else
+ rfacts += c->cfact; // 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 * (c->cfact / lfacts);
+ else
+ rtotal += rh * (c->cfact / rfacts);
+ #else
+ 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;
+ #endif // CFACTS_PATCH
+
+ 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 */
+ #if CFACTS_PATCH
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ my += HEIGHT(c) + ih;
+ #else
+ my += HEIGHT(c);
+ #endif
+ } else {
+ /* stack clients are stacked vertically */
+ if ((i - m->nmaster) % 2 ) {
+ #if CFACTS_PATCH
+ resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) * c->cfact + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ ly += HEIGHT(c) + ih;
+ #else
+ ly += HEIGHT(c);
+ #endif
+ } else {
+ #if CFACTS_PATCH
+ resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) * c->cfact + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ ry += HEIGHT(c) + ih;
+ #else
+ ry += HEIGHT(c);
+ #endif
+ }
+ }
+ }
+}
+
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_columns.c b/patch/layout_columns.c
new file mode 100644
index 0000000..8a0e551
--- /dev/null
+++ b/patch/layout_columns.c
@@ -0,0 +1,74 @@
+static void
+col(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;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ mh = m->wh - 2*oh;
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
+ sw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sw = (mw - iv) * (1 - m->mfact);
+ mw = (mw - iv) * m->mfact;
+ sx = mx + mw + iv * m->nmaster;
+ }
+ #else
+ 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;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ mx += WIDTH(c) + iv;
+ #else
+ mx += WIDTH(c);
+ #endif
+ } else {
+ #if CFACTS_PATCH
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sy += HEIGHT(c) + ih;
+ #else
+ sy += HEIGHT(c);
+ #endif
+ }
+}
+
diff --git a/patch/layout_columns.h b/patch/layout_columns.h
new file mode 100644
index 0000000..a589371
--- /dev/null
+++ b/patch/layout_columns.h
@@ -0,0 +1,2 @@
+static void col(Monitor *);
+
diff --git a/patch/layout_deck.c b/patch/layout_deck.c
new file mode 100644
index 0000000..1cabf0e
--- /dev/null
+++ b/patch/layout_deck.c
@@ -0,0 +1,67 @@
+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;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
+ sw = mw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sw = (mw - iv) * (1 - m->mfact);
+ mw = (mw - iv) * m->mfact;
+ sx = mx + mw + iv;
+ sh = m->wh - 2*oh;
+ }
+ #else
+ 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;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ 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) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ my += HEIGHT(c) + ih;
+ #else
+ my += HEIGHT(c);
+ #endif
+ } 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..611e89e
--- /dev/null
+++ b/patch/layout_facts.c
@@ -0,0 +1,52 @@
+#if CFACTS_PATCH
+void
+getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
+{
+ unsigned int n;
+ float mfacts = 0, sfacts = 0;
+ int mtotal = 0, stotal = 0;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+ if (n < m->nmaster)
+ mfacts += c->cfact;
+ else
+ sfacts += c->cfact;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+ if (n < m->nmaster)
+ mtotal += msize * (c->cfact / mfacts);
+ else
+ stotal += ssize * (c->cfact / sfacts);
+
+ *mf = mfacts; // total factor of master area
+ *sf = sfacts; // total factor of stack area
+ *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split
+ *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split
+}
+#else
+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
+}
+#endif // CFACTS_PATCH
+
diff --git a/patch/layout_fibonacci.c b/patch/layout_fibonacci.c
new file mode 100644
index 0000000..4c5eb72
--- /dev/null
+++ b/patch/layout_fibonacci.c
@@ -0,0 +1,191 @@
+#if VANITYGAPS_PATCH
+void
+fibonacci(Monitor *m, int s)
+{
+ unsigned int i, n;
+ int nx, ny, nw, nh;
+ int oh, ov, ih, iv;
+ int nv, hrest = 0, wrest = 0, r = 1;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ nx = m->wx + ov;
+ ny = oh;
+ nw = m->ww - 2*ov;
+ nh = m->wh - 2*oh;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
+ if (r) {
+ if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw))
+ || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) {
+ r = 0;
+ }
+ if (r && i < n - 1) {
+ if (i % 2) {
+ nv = (nh - ih) / 2;
+ hrest = nh - 2*nv - ih;
+ nh = nv;
+ } else {
+ nv = (nw - iv) / 2;
+ wrest = nw - 2*nv - iv;
+ nw = nv;
+ }
+
+ if ((i % 4) == 2 && !s)
+ nx += nw + iv;
+ else if ((i % 4) == 3 && !s)
+ ny += nh + ih;
+ }
+
+ if ((i % 4) == 0) {
+ if (s) {
+ ny += nh + ih;
+ nh += hrest;
+ }
+ else {
+ nh -= hrest;
+ ny -= nh + ih;
+ }
+ }
+ else if ((i % 4) == 1) {
+ nx += nw + iv;
+ nw += wrest;
+ }
+ else if ((i % 4) == 2) {
+ ny += nh + ih;
+ nh += hrest;
+ if (i < n - 1)
+ nw += wrest;
+ }
+ else if ((i % 4) == 3) {
+ if (s) {
+ nx += nw + iv;
+ nw -= wrest;
+ } else {
+ nw -= wrest;
+ nx -= nw + iv;
+ nh += hrest;
+ }
+ }
+ if (i == 0) {
+ if (n != 1) {
+ nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact);
+ wrest = 0;
+ }
+ ny = m->wy + oh;
+ }
+ else if (i == 1)
+ nw = m->ww - nw - iv - 2*ov;
+ i++;
+ }
+
+ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
+ }
+}
+#else
+void
+fibonacci(Monitor *m, int s)
+{
+ unsigned int i, n;
+ int nx, ny, nw, nh;
+ int nv, hrest = 0, wrest = 0, r = 1;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ nx = m->wx;
+ ny = m->wy;
+ nw = m->ww;
+ nh = m->wh;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
+ if (r) {
+ if ((i % 2 && nh / 2 <= (bh + 2*c->bw))
+ || (!(i % 2) && nw / 2 <= (bh + 2*c->bw))) {
+ r = 0;
+ }
+ if (r && i < n - 1) {
+ if (i % 2) {
+ nv = nh / 2;
+ hrest = nh - 2*nv;
+ nh = nv;
+ } else {
+ nv = nw / 2;
+ wrest = nw - 2*nv;
+ nw = nv;
+ }
+
+ if ((i % 4) == 2 && !s)
+ nx += nw;
+ else if ((i % 4) == 3 && !s)
+ ny += nh;
+ }
+
+ if ((i % 4) == 0) {
+ if (s) {
+ ny += nh;
+ nh += hrest;
+ }
+ else {
+ nh -= hrest;
+ ny -= nh;
+ }
+ }
+ else if ((i % 4) == 1) {
+ nx += nw;
+ nw += wrest;
+ }
+ else if ((i % 4) == 2) {
+ ny += nh;
+ nh += hrest;
+ if (i < n - 1)
+ nw += wrest;
+ }
+ else if ((i % 4) == 3) {
+ if (s) {
+ nx += nw;
+ nw -= wrest;
+ } else {
+ nw -= wrest;
+ nx -= nw;
+ nh += hrest;
+ }
+ }
+ if (i == 0) {
+ if (n != 1) {
+ nw = m->ww - m->ww * (1 - m->mfact);
+ wrest = 0;
+ }
+ ny = m->wy;
+ }
+ else if (i == 1)
+ nw = m->ww - nw;
+ i++;
+ }
+
+ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
+ }
+}
+#endif
+
+#if FIBONACCI_DWINDLE_LAYOUT
+static void
+dwindle(Monitor *m)
+{
+ fibonacci(m, 1);
+}
+#endif
+
+#if FIBONACCI_SPIRAL_LAYOUT
+static void
+spiral(Monitor *m)
+{
+ fibonacci(m, 0);
+}
+#endif
+
diff --git a/patch/layout_fibonacci.h b/patch/layout_fibonacci.h
new file mode 100644
index 0000000..3d6f77f
--- /dev/null
+++ b/patch/layout_fibonacci.h
@@ -0,0 +1,8 @@
+#if FIBONACCI_DWINDLE_LAYOUT
+static void dwindle(Monitor *m);
+#endif // FIBONACCI_DWINDLE_LAYOUT
+static void fibonacci(Monitor *m, int s);
+#if FIBONACCI_SPIRAL_LAYOUT
+static void spiral(Monitor *m);
+#endif // FIBONACCI_SPIRAL_LAYOUT
+
diff --git a/patch/layout_flextile-deluxe.c b/patch/layout_flextile-deluxe.c
new file mode 100644
index 0000000..c7429f4
--- /dev/null
+++ b/patch/layout_flextile-deluxe.c
@@ -0,0 +1,891 @@
+typedef struct {
+ void (*arrange)(Monitor *, int, int, int, int, int, int, int);
+} LayoutArranger;
+
+typedef struct {
+ void (*arrange)(Monitor *, int, int, int, int, int, int, int, int, int);
+} TileArranger;
+
+static const LayoutArranger flexlayouts[] = {
+ { layout_no_split },
+ { layout_split_vertical },
+ { layout_split_horizontal },
+ { layout_split_centered_vertical },
+ { layout_split_centered_horizontal },
+ { layout_split_vertical_dual_stack },
+ { layout_split_horizontal_dual_stack },
+ { layout_floating_master },
+ { layout_split_vertical_fixed },
+ { layout_split_horizontal_fixed },
+ { layout_split_centered_vertical_fixed },
+ { layout_split_centered_horizontal_fixed },
+ { layout_split_vertical_dual_stack_fixed },
+ { layout_split_horizontal_dual_stack_fixed },
+ { layout_floating_master_fixed },
+};
+
+static const TileArranger flextiles[] = {
+ { arrange_top_to_bottom },
+ { arrange_left_to_right },
+ { arrange_monocle },
+ { arrange_gapplessgrid },
+ { arrange_gapplessgrid_alt1 },
+ { arrange_gapplessgrid_alt2 },
+ { arrange_gridmode },
+ { arrange_horizgrid },
+ { arrange_dwindle },
+ { arrange_spiral },
+ { arrange_tatami },
+};
+
+static void
+getfactsforrange(Monitor *m, int an, int ai, int size, int *rest, float *fact)
+{
+ int i;
+ float facts;
+ Client *c;
+ int total = 0;
+
+ facts = 0;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i >= ai && i < (ai + an))
+ #if CFACTS_PATCH
+ facts += c->cfact;
+ #else
+ facts += 1;
+ #endif // CFACTS_PATCH
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i >= ai && i < (ai + an))
+ #if CFACTS_PATCH
+ total += size * (c->cfact / facts);
+ #else
+ total += size / facts;
+ #endif // CFACTS_PATCH
+
+ *rest = size - total;
+ *fact = facts;
+}
+
+#if IPC_PATCH || DWMC_PATCH
+static void
+setlayoutaxisex(const Arg *arg)
+{
+ int axis, arr;
+
+ axis = arg->i & 0x3; // lower two bytes indicates layout, master or stack1-2
+ arr = ((arg->i & 0xFC) >> 2); // remaining six upper bytes indicate arrangement
+
+ if ((axis == 0 && abs(arr) > LAYOUT_LAST)
+ || (axis > 0 && (arr > AXIS_LAST || arr < 0)))
+ arr = 0;
+
+ selmon->ltaxis[axis] = arr;
+ #if PERTAG_PATCH
+ selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis];
+ #endif // PERTAG_PATCH
+ arrange(selmon);
+}
+#endif // IPC_PATCH | DWMC_PATCH
+
+static void
+layout_no_split(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ (&flextiles[m->ltaxis[m->nmaster >= n ? MASTER : STACK]])->arrange(m, x, y, h, w, ih, iv, n, n, 0);
+}
+
+static void
+layout_split_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (m->nmaster && n > m->nmaster) {
+ layout_split_vertical_fixed(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sw, sx;
+
+ sw = (w - iv) * (1 - m->mfact);
+ w = (w - iv) * m->mfact;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sx = x;
+ x += sw + iv;
+ } else {
+ sx = x + w + iv;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, n - m->nmaster, m->nmaster);
+}
+
+static void
+layout_split_vertical_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (!m->nmaster || n <= m->nmaster) {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) {
+ layout_split_vertical(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_split_vertical_dual_stack_fixed(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_vertical_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sh, sw, sx, oy, sc;
+
+ if (m->nstack)
+ sc = m->nstack;
+ else
+ sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0);
+
+ sw = (w - iv) * (1 - m->mfact);
+ sh = (h - ih) / 2;
+ w = (w - iv) * m->mfact;
+ oy = y + sh + ih;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sx = x;
+ x += sw + iv;
+ } else {
+ sx = x + w + iv;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, sh, sw, ih, iv, n, sc, m->nmaster);
+ (&flextiles[m->ltaxis[STACK2]])->arrange(m, sx, oy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc);
+}
+
+static void
+layout_split_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (m->nmaster && n > m->nmaster) {
+ layout_split_horizontal_fixed(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sh, sy;
+
+ sh = (h - ih) * (1 - m->mfact);
+ h = (h - ih) * m->mfact;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sy = y;
+ y += sh + ih;
+ } else {
+ sy = y + h + ih;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, n - m->nmaster, m->nmaster);
+}
+
+static void
+layout_split_horizontal_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (!m->nmaster || n <= m->nmaster) {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) {
+ layout_split_horizontal(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_split_horizontal_dual_stack_fixed(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_horizontal_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sh, sy, ox, sc;
+
+ if (m->nstack)
+ sc = m->nstack;
+ else
+ sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0);
+
+ sh = (h - ih) * (1 - m->mfact);
+ h = (h - ih) * m->mfact;
+ sw = (w - iv) / 2;
+ ox = x + sw + iv;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sy = y;
+ y += sh + ih;
+ } else {
+ sy = y + h + ih;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, sw, ih, iv, n, sc, m->nmaster);
+ (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, sy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc);
+}
+
+static void
+layout_split_centered_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (!m->nmaster || n <= m->nmaster) {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) {
+ layout_split_vertical(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_split_centered_vertical_fixed(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_centered_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sw, sx, ox, sc;
+
+ if (m->nstack)
+ sc = m->nstack;
+ else
+ sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0);
+
+ sw = (w - 2*iv) * (1 - m->mfact) / 2;
+ w = (w - 2*iv) * m->mfact;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sx = x;
+ x += sw + iv;
+ ox = x + w + iv;
+ } else {
+ ox = x;
+ x += sw + iv;
+ sx = x + w + iv;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, sc, m->nmaster);
+ (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, y, h, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc);
+}
+
+static void
+layout_split_centered_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (!m->nmaster || n <= m->nmaster) {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) {
+ layout_split_horizontal(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_split_centered_horizontal_fixed(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_split_centered_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int sh, sy, oy, sc;
+
+ if (m->nstack)
+ sc = m->nstack;
+ else
+ sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0);
+
+ sh = (h - 2*ih) * (1 - m->mfact) / 2;
+ h = (h - 2*ih) * m->mfact;
+ if (m->ltaxis[LAYOUT] < 0) { // mirror
+ sy = y;
+ y += sh + ih;
+ oy = y + h + ih;
+ } else {
+ oy = y;
+ y += sh + ih;
+ sy = y + h + ih;
+ }
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0);
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, sc, m->nmaster);
+ (&flextiles[m->ltaxis[STACK2]])->arrange(m, x, oy, sh, w, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc);
+}
+
+static void
+layout_floating_master(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ /* Split master into master + stack if we have enough clients */
+ if (!m->nmaster || n <= m->nmaster) {
+ layout_no_split(m, x, y, h, w, ih, iv, n);
+ } else {
+ layout_floating_master_fixed(m, x, y, h, w, ih, iv, n);
+ }
+}
+
+static void
+layout_floating_master_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n)
+{
+ int mh, mw;
+
+ /* Draw stack area first */
+ (&flextiles[m->ltaxis[STACK]])->arrange(m, x, y, h, w, ih, iv, n, n - m->nmaster, m->nmaster);
+
+ if (w > h) {
+ mw = w * m->mfact;
+ mh = h * 0.9;
+ } else {
+ mw = w * 0.9;
+ mh = h * m->mfact;
+ }
+ x = x + (w - mw) / 2;
+ y = y + (h - mh) / 2;
+
+ (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, mh, mw, ih, iv, n, m->nmaster, 0);
+}
+
+static void
+arrange_left_to_right(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, rest;
+ float facts, fact = 1;
+ Client *c;
+
+ if (ai + an > n)
+ an = n - ai;
+
+ w -= iv * (an - 1);
+ getfactsforrange(m, an, ai, w, &rest, &facts);
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i >= ai && i < (ai + an)) {
+ #if CFACTS_PATCH
+ fact = c->cfact;
+ #endif // CFACTS_PATCH
+ resize(c, x, y, w * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), h - (2*c->bw), 0);
+ x += WIDTH(c) + iv;
+ }
+ }
+}
+
+static void
+arrange_top_to_bottom(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, rest;
+ float facts, fact = 1;
+ Client *c;
+
+ if (ai + an > n)
+ an = n - ai;
+
+ h -= ih * (an - 1);
+ getfactsforrange(m, an, ai, h, &rest, &facts);
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i >= ai && i < (ai + an)) {
+ #if CFACTS_PATCH
+ fact = c->cfact;
+ #endif // CFACTS_PATCH
+ resize(c, x, y, w - (2*c->bw), h * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), 0);
+ y += HEIGHT(c) + ih;
+ }
+ }
+}
+
+static void
+arrange_monocle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i;
+ Client *c;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i >= ai && i < (ai + an))
+ resize(c, x, y, w - (2*c->bw), h - (2*c->bw), 0);
+}
+
+static void
+arrange_gridmode(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, cols, rows, ch, cw, cx, cy, cc, cr, chrest, cwrest; // counters
+ Client *c;
+
+ /* grid dimensions */
+ for (rows = 0; rows <= an/2; rows++)
+ if (rows*rows >= an)
+ break;
+ cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows;
+
+ /* window geoms (cell height/width) */
+ ch = (h - ih * (rows - 1)) / (rows ? rows : 1);
+ cw = (w - iv * (cols - 1)) / (cols ? cols : 1);
+ chrest = h - ih * (rows - 1) - ch * rows;
+ cwrest = w - iv * (cols - 1) - cw * cols;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i >= ai && i < (ai + an)) {
+ cc = ((i - ai) / rows); // client column number
+ cr = ((i - ai) % rows); // client row number
+ cx = x + cc * (cw + iv) + MIN(cc, cwrest);
+ cy = y + cr * (ch + ih) + MIN(cr, chrest);
+ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
+ }
+ }
+}
+
+static void
+arrange_horizgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int ntop, nbottom, rh, rest;
+
+ /* Exception when there is only one client; don't split into two rows */
+ if (an == 1) {
+ arrange_monocle(m, x, y, h, w, ih, iv, n, an, ai);
+ return;
+ }
+
+ ntop = an / 2;
+ nbottom = an - ntop;
+ rh = (h - ih) / 2;
+ rest = h - ih - rh * 2;
+ arrange_left_to_right(m, x, y, rh + rest, w, ih, iv, n, ntop, ai);
+ arrange_left_to_right(m, x, y + rh + ih + rest, rh, w, ih, iv, n, nbottom, ai + ntop);
+}
+
+static void
+arrange_gapplessgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, cols, rows, ch, cw, cn, rn, cc, rrest, crest; // counters
+ Client *c;
+
+ /* grid dimensions */
+ for (cols = 1; cols <= an/2; cols++)
+ if (cols*cols >= an)
+ break;
+ if (an == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
+ cols = 2;
+ rows = an/cols;
+ cn = rn = cc = 0; // reset column no, row no, client count
+
+ ch = (h - ih * (rows - 1)) / rows;
+ rrest = (h - ih * (rows - 1)) - ch * rows;
+ cw = (w - iv * (cols - 1)) / cols;
+ crest = (w - iv * (cols - 1)) - cw * cols;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i >= ai && i < (ai + an)) {
+ if (cc/rows + 1 > cols - an%cols) {
+ rows = an/cols + 1;
+ ch = (h - ih * (rows - 1)) / rows;
+ rrest = (h - ih * (rows - 1)) - ch * rows;
+ }
+ resize(c,
+ x,
+ y + rn*(ch + ih) + MIN(rn, rrest),
+ cw + (cn < crest ? 1 : 0) - 2*c->bw,
+ ch + (rn < rrest ? 1 : 0) - 2*c->bw,
+ 0);
+ rn++;
+ cc++;
+ if (rn >= rows) {
+ rn = 0;
+ x += cw + ih + (cn < crest ? 1 : 0);
+ cn++;
+ }
+ }
+ }
+}
+
+/* This version of gappless grid fills rows first */
+static void
+arrange_gapplessgrid_alt1(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, cols, rows, rest, ch;
+
+ /* grid dimensions */
+ for (cols = 1; cols <= an/2; cols++)
+ if (cols*cols >= an)
+ break;
+ rows = (cols && (cols - 1) * cols >= an) ? cols - 1 : cols;
+ ch = (h - ih * (rows - 1)) / (rows ? rows : 1);
+ rest = (h - ih * (rows - 1)) - ch * rows;
+
+ for (i = 0; i < rows; i++) {
+ arrange_left_to_right(m, x, y, ch + (i < rest ? 1 : 0), w, ih, iv, n, MIN(cols, an - i*cols), ai + i*cols);
+ y += ch + (i < rest ? 1 : 0) + ih;
+ }
+}
+
+/* This version of gappless grid fills columns first */
+static void
+arrange_gapplessgrid_alt2(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ int i, cols, rows, rest, cw;
+
+ /* grid dimensions */
+ for (rows = 0; rows <= an/2; rows++)
+ if (rows*rows >= an)
+ break;
+ cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows;
+ cw = (w - iv * (cols - 1)) / (cols ? cols : 1);
+ rest = (w - iv * (cols - 1)) - cw * cols;
+
+ for (i = 0; i < cols; i++) {
+ arrange_top_to_bottom(m, x, y, h, cw + (i < rest ? 1 : 0), ih, iv, n, MIN(rows, an - i*rows), ai + i*rows);
+ x += cw + (i < rest ? 1 : 0) + iv;
+ }
+}
+
+static void
+arrange_fibonacci(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai, int s)
+{
+ int i, j, nv, hrest = 0, wrest = 0, nx = x, ny = y, nw = w, nh = h, r = 1;
+ Client *c;
+
+ for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) {
+ if (j >= ai && j < (ai + an)) {
+ if (r) {
+ if ((i % 2 && ((nh - ih) / 2) <= (bh + 2*c->bw)) || (!(i % 2) && ((nw - iv) / 2) <= (bh + 2*c->bw))) {
+ r = 0;
+ }
+ if (r && i < an - 1) {
+ if (i % 2) {
+ nv = (nh - ih) / 2;
+ hrest = nh - 2*nv - ih;
+ nh = nv;
+ } else {
+ nv = (nw - iv) / 2;
+ wrest = nw - 2*nv - iv;
+ nw = nv;
+ }
+
+ if ((i % 4) == 2 && !s)
+ nx += nw + iv;
+ else if ((i % 4) == 3 && !s)
+ ny += nh + ih;
+ }
+ if ((i % 4) == 0) {
+ if (s) {
+ ny += nh + ih;
+ nh += hrest;
+ } else {
+ nh -= hrest;
+ ny -= nh + ih;
+ }
+ } else if ((i % 4) == 1) {
+ nx += nw + iv;
+ nw += wrest;
+ } else if ((i % 4) == 2) {
+ ny += nh + ih;
+ nh += hrest;
+ if (i < n - 1)
+ nw += wrest;
+ } else if ((i % 4) == 3) {
+ if (s) {
+ nx += nw + iv;
+ nw -= wrest;
+ } else {
+ nw -= wrest;
+ nx -= nw + iv;
+ nh += hrest;
+ }
+ }
+ if (i == 0) {
+ if (an != 1) {
+ nw = (w - iv) - (w - iv) * (1 - m->mfact);
+ wrest = 0;
+ }
+ ny = y;
+ } else if (i == 1)
+ nw = w - nw - iv;
+ i++;
+ }
+
+ resize(c, nx, ny, nw - 2 * c->bw, nh - 2*c->bw, False);
+ }
+ }
+}
+
+static void
+arrange_dwindle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 1);
+}
+
+static void
+arrange_spiral(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 0);
+}
+
+static void
+arrange_tatami(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai)
+{
+ unsigned int i, j, nx, ny, nw, nh, tnx, tny, tnw, tnh, nhrest, hrest, wrest, areas, mats, cats;
+ Client *c;
+
+ nx = x;
+ ny = y;
+ nw = w;
+ nh = h;
+
+ mats = an / 5;
+ cats = an % 5;
+ hrest = 0;
+ wrest = 0;
+
+ areas = mats + (cats > 0);
+ nh = (h - ih * (areas - 1)) / areas;
+ nhrest = (h - ih * (areas - 1)) % areas;
+
+ for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) {
+ if (j >= ai && j < (ai + an)) {
+
+ tnw = nw;
+ tnx = nx;
+ tnh = nh;
+ tny = ny;
+
+ if (j < ai + cats) {
+ /* Arrange cats (all excess clients that can't be tiled as mats). Cats sleep on mats. */
+
+ switch (cats) {
+ case 1: // fill
+ break;
+ case 2: // up and down
+ if ((i % 5) == 0) //up
+ tnh = (nh - ih) / 2 + (nh - ih) % 2;
+ else if ((i % 5) == 1) { //down
+ tny += (nh - ih) / 2 + (nh - ih) % 2 + ih;
+ tnh = (nh - ih) / 2;
+ }
+ break;
+ case 3: //bottom, up-left and up-right
+ if ((i % 5) == 0) { // up-left
+ tnw = (nw - iv) / 2 + (nw - iv) % 2;
+ tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3;
+ } else if ((i % 5) == 1) { // up-right
+ tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv;
+ tnw = (nw - iv) / 2;
+ tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3;
+ } else if ((i % 5) == 2) { //bottom
+ tnh = (nh - ih) / 3;
+ tny += (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3 + ih;
+ }
+ break;
+ case 4: // bottom, left, right and top
+ if ((i % 5) == 0) { //top
+ hrest = (nh - 2 * ih) % 4;
+ tnh = (nh - 2 * ih) / 4 + (hrest ? 1 : 0);
+ } else if ((i % 5) == 1) { // left
+ tnw = (nw - iv) / 2 + (nw - iv) % 2;
+ tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih;
+ tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0);
+ } else if ((i % 5) == 2) { // right
+ tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv;
+ tnw = (nw - iv) / 2;
+ tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih;
+ tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0);
+ } else if ((i % 5) == 3) { // bottom
+ tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0) + 2 * ih;
+ tnh = (nh - 2 * ih) / 4 + (hrest > 2 ? 1 : 0);
+ }
+ break;
+ }
+
+ } else {
+ /* Arrange mats. One mat is a collection of five clients arranged tatami style */
+
+ if (((i - cats) % 5) == 0) {
+ if ((cats > 0) || ((i - cats) >= 5)) {
+ tny = ny = ny + nh + (nhrest > 0 ? 1 : 0) + ih;
+ --nhrest;
+ }
+ }
+
+ switch ((i - cats) % 5) {
+ case 0: // top-left-vert
+ wrest = (nw - 2 * iv) % 3;
+ hrest = (nh - 2 * ih) % 3;
+ tnw = (nw - 2 * iv) / 3 + (wrest ? 1 : 0);
+ tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv;
+ break;
+ case 1: // top-right-hor
+ tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv;
+ tnw = (nw - 2 * iv) * 2 / 3 + (wrest > 1 ? 1 : 0) + iv;
+ tnh = (nh - 2 * ih) / 3 + (hrest ? 1 : 0);
+ break;
+ case 2: // center
+ tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv;
+ tnw = (nw - 2 * iv) / 3 + (wrest > 1 ? 1 : 0);
+ tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih;
+ tnh = (nh - 2 * ih) / 3 + (hrest > 1 ? 1 : 0);
+ break;
+ case 3: // bottom-right-vert
+ tnx += (nw - 2 * iv) * 2 / 3 + wrest + 2 * iv;
+ tnw = (nw - 2 * iv) / 3;
+ tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih;
+ tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv;
+ break;
+ case 4: // (oldest) bottom-left-hor
+ tnw = (nw - 2 * iv) * 2 / 3 + wrest + iv;
+ tny += (nh - 2 * ih) * 2 / 3 + hrest + 2 * iv;
+ tnh = (nh - 2 * ih) / 3;
+ break;
+ }
+
+ }
+
+ resize(c, tnx, tny, tnw - 2 * c->bw, tnh - 2 * c->bw, False);
+ ++i;
+ }
+ }
+}
+
+static void
+flextile(Monitor *m)
+{
+ unsigned int n;
+ int oh = 0, ov = 0, ih = 0, iv = 0; // gaps outer/inner horizontal/vertical
+
+ #if VANITYGAPS_PATCH
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ Client *c;
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (m->lt[m->sellt]->preset.layout != m->ltaxis[LAYOUT] ||
+ m->lt[m->sellt]->preset.masteraxis != m->ltaxis[MASTER] ||
+ m->lt[m->sellt]->preset.stack1axis != m->ltaxis[STACK] ||
+ m->lt[m->sellt]->preset.stack2axis != m->ltaxis[STACK2])
+ setflexsymbols(m, n);
+ else if (m->lt[m->sellt]->preset.symbolfunc != NULL)
+ m->lt[m->sellt]->preset.symbolfunc(m, n);
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH
+ /* No outer gap if full screen monocle */
+ if (abs(m->ltaxis[MASTER]) == MONOCLE && (abs(m->ltaxis[LAYOUT]) == NO_SPLIT || n <= m->nmaster)) {
+ oh = 0;
+ ov = 0;
+ }
+ #endif // VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH
+
+ (&flexlayouts[abs(m->ltaxis[LAYOUT])])->arrange(m, m->wx + ov, m->wy + oh, m->wh - 2*oh, m->ww - 2*ov, ih, iv, n);
+ return;
+}
+
+static void
+setflexsymbols(Monitor *m, unsigned int n)
+{
+ int l;
+ char sym1, sym2, sym3;
+ Client *c;
+
+ if (n == 0)
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+ l = abs(m->ltaxis[LAYOUT]);
+ if (m->ltaxis[MASTER] == MONOCLE && (l == NO_SPLIT || !m->nmaster || n <= m->nmaster)) {
+ monoclesymbols(m, n);
+ return;
+ }
+
+ if (m->ltaxis[STACK] == MONOCLE && (l == SPLIT_VERTICAL || l == SPLIT_HORIZONTAL_FIXED)) {
+ decksymbols(m, n);
+ return;
+ }
+
+ /* Layout symbols */
+ if (l == NO_SPLIT || !m->nmaster) {
+ sym1 = sym2 = sym3 = (int)tilesymb[m->ltaxis[MASTER]];
+ } else {
+ sym2 = layoutsymb[l];
+ if (m->ltaxis[LAYOUT] < 0) {
+ sym1 = tilesymb[m->ltaxis[STACK]];
+ sym3 = tilesymb[m->ltaxis[MASTER]];
+ } else {
+ sym1 = tilesymb[m->ltaxis[MASTER]];
+ sym3 = tilesymb[m->ltaxis[STACK]];
+ }
+ }
+
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "%c%c%c", sym1, sym2, sym3);
+}
+
+static void
+monoclesymbols(Monitor *m, unsigned int n)
+{
+ if (n > 0)
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
+ else
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[M]");
+}
+
+static void
+decksymbols(Monitor *m, unsigned int n)
+{
+ if (n > m->nmaster)
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[]%d", n);
+ else
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[D]");
+}
+
+/* Mirror layout axis for flextile */
+void
+mirrorlayout(const Arg *arg)
+{
+ if (!selmon->lt[selmon->sellt]->arrange)
+ return;
+ selmon->ltaxis[LAYOUT] *= -1;
+ #if PERTAG_PATCH
+ selmon->pertag->ltaxis[selmon->pertag->curtag][0] = selmon->ltaxis[LAYOUT];
+ #endif // PERTAG_PATCH
+ arrange(selmon);
+}
+
+/* Rotate layout axis for flextile */
+void
+rotatelayoutaxis(const Arg *arg)
+{
+ int incr = (arg->i > 0 ? 1 : -1);
+ int axis = abs(arg->i) - 1;
+
+ if (!selmon->lt[selmon->sellt]->arrange)
+ return;
+ if (axis == LAYOUT) {
+ if (selmon->ltaxis[LAYOUT] >= 0) {
+ selmon->ltaxis[LAYOUT] += incr;
+ if (selmon->ltaxis[LAYOUT] >= LAYOUT_LAST)
+ selmon->ltaxis[LAYOUT] = 0;
+ else if (selmon->ltaxis[LAYOUT] < 0)
+ selmon->ltaxis[LAYOUT] = LAYOUT_LAST - 1;
+ } else {
+ selmon->ltaxis[LAYOUT] -= incr;
+ if (selmon->ltaxis[LAYOUT] <= -LAYOUT_LAST)
+ selmon->ltaxis[LAYOUT] = 0;
+ else if (selmon->ltaxis[LAYOUT] > 0)
+ selmon->ltaxis[LAYOUT] = -LAYOUT_LAST + 1;
+ }
+ } else {
+ selmon->ltaxis[axis] += incr;
+ if (selmon->ltaxis[axis] >= AXIS_LAST)
+ selmon->ltaxis[axis] = 0;
+ else if (selmon->ltaxis[axis] < 0)
+ selmon->ltaxis[axis] = AXIS_LAST - 1;
+ }
+ #if PERTAG_PATCH
+ selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis];
+ #endif // PERTAG_PATCH
+ arrange(selmon);
+ setflexsymbols(selmon, 0);
+}
+
+void
+incnstack(const Arg *arg)
+{
+ #if PERTAG_PATCH
+ selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag] = MAX(selmon->nstack + arg->i, 0);
+ #else
+ selmon->nstack = MAX(selmon->nstack + arg->i, 0);
+ #endif // PERTAG_PATCH
+ arrange(selmon);
+}
+
diff --git a/patch/layout_flextile-deluxe.h b/patch/layout_flextile-deluxe.h
new file mode 100644
index 0000000..92df5c5
--- /dev/null
+++ b/patch/layout_flextile-deluxe.h
@@ -0,0 +1,121 @@
+static void flextile(Monitor *m);
+static void getfactsforrange(Monitor *m, int an, int ai, int size, int *rest, float *fact);
+static void mirrorlayout(const Arg *arg);
+static void rotatelayoutaxis(const Arg *arg);
+#if IPC_PATCH || DWMC_PATCH
+static void setlayoutaxisex(const Arg *arg);
+#endif // IPC_PATCH | DWMC_PATCH
+static void incnstack(const Arg *arg);
+
+/* Symbol handlers */
+static void setflexsymbols(Monitor *m, unsigned int n);
+static void monoclesymbols(Monitor *m, unsigned int n);
+static void decksymbols(Monitor *m, unsigned int n);
+
+/* Layout split */
+static void layout_no_split(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_vertical_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_horizontal_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_centered_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_centered_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_floating_master(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_vertical_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_horizontal_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_centered_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_split_centered_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+static void layout_floating_master_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n);
+
+/* Layout tile arrangements */
+static void arrange_left_to_right(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_top_to_bottom(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_monocle(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_gapplessgrid(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_gapplessgrid_alt1(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_gapplessgrid_alt2(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_gridmode(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_horizgrid(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_dwindle(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_spiral(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+static void arrange_tatami(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai);
+
+/* Named flextile constants */
+enum {
+ LAYOUT, // controls overall layout arrangement / split
+ MASTER, // indicates the tile arrangement for the master area
+ STACK, // indicates the tile arrangement for the stack area
+ STACK2, // indicates the tile arrangement for the secondary stack area
+ LTAXIS_LAST,
+};
+
+/* Layout arrangements */
+enum {
+ NO_SPLIT,
+ SPLIT_VERTICAL, // master stack vertical split
+ SPLIT_HORIZONTAL, // master stack horizontal split
+ SPLIT_CENTERED_VERTICAL, // centered master vertical split
+ SPLIT_CENTERED_HORIZONTAL, // centered master horizontal split
+ SPLIT_VERTICAL_DUAL_STACK, // master stack vertical split with dual stack
+ SPLIT_HORIZONTAL_DUAL_STACK, // master stack vertical split with dual stack
+ FLOATING_MASTER, // (fake) floating master
+ SPLIT_VERTICAL_FIXED, // master stack vertical fixed split
+ SPLIT_HORIZONTAL_FIXED, // master stack horizontal fixed split
+ SPLIT_CENTERED_VERTICAL_FIXED, // centered master vertical fixed split
+ SPLIT_CENTERED_HORIZONTAL_FIXED, // centered master horizontal fixed split
+ SPLIT_VERTICAL_DUAL_STACK_FIXED, // master stack vertical split with fixed dual stack
+ SPLIT_HORIZONTAL_DUAL_STACK_FIXED, // master stack vertical split with fixed dual stack
+ FLOATING_MASTER_FIXED, // (fake) fixed floating master
+ LAYOUT_LAST,
+};
+
+static char layoutsymb[] = {
+ 32, // " ",
+ 124, // "|",
+ 61, // "=",
+ 94, // "^",
+ 126, // "~",
+ 58, // ":",
+ 59, // ";",
+ 43, // "+",
+ 124, // "¦",
+ 61, // "=",
+ 94, // "^",
+ 126, // "~",
+ 58, // ":",
+ 59, // ";",
+ 43, // "+",
+};
+
+/* Tile arrangements */
+enum {
+ TOP_TO_BOTTOM, // clients are arranged vertically
+ LEFT_TO_RIGHT, // clients are arranged horizontally
+ MONOCLE, // clients are arranged in deck / monocle mode
+ GAPPLESSGRID, // clients are arranged in a gappless grid (original formula)
+ GAPPLESSGRID_ALT1, // clients are arranged in a gappless grid (alt. 1, fills rows first)
+ GAPPLESSGRID_ALT2, // clients are arranged in a gappless grid (alt. 2, fills columns first)
+ GRIDMODE, // clients are arranged in a grid
+ HORIZGRID, // clients are arranged in a horizontal grid
+ DWINDLE, // clients are arranged in fibonacci dwindle mode
+ SPIRAL, // clients are arranged in fibonacci spiral mode
+ TATAMI, // clients are arranged as tatami mats
+ AXIS_LAST,
+};
+
+static char tilesymb[] = {
+ 61, // "=",
+ 124, // "|",
+ 68, // "D",
+ 71, // "G",
+ 49, // "1",
+ 50, // "2"
+ 35, // "#",
+ 126, // "~",
+ 92, // "\\",
+ 64, // "@",
+ 84, // "T",
+};
+
diff --git a/patch/layout_gapplessgrid.c b/patch/layout_gapplessgrid.c
new file mode 100644
index 0000000..79f236a
--- /dev/null
+++ b/patch/layout_gapplessgrid.c
@@ -0,0 +1,99 @@
+#if VANITYGAPS_PATCH
+void
+gaplessgrid(Monitor *m)
+{
+ unsigned int i, n;
+ int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
+ int oh, ov, ih, iv;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &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 - 2*oh - ih * (rows - 1)) / rows;
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / cols;
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
+ x = m->wx + ov;
+ y = m->wy + oh;
+
+ 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 - 2*oh - ih * (rows - 1)) / rows;
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ }
+ resize(c,
+ x,
+ y + rn*(ch + ih) + 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 + ih + (cn < crest ? 1 : 0);
+ cn++;
+ }
+ }
+}
+#else
+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++;
+ }
+ }
+}
+#endif
+
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_grid.c b/patch/layout_grid.c
new file mode 100644
index 0000000..7ac832f
--- /dev/null
+++ b/patch/layout_grid.c
@@ -0,0 +1,61 @@
+#if VANITYGAPS_PATCH
+void
+grid(Monitor *m)
+{
+ unsigned int i, n;
+ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
+ int oh, ov, ih, iv;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+
+ /* grid dimensions */
+ for (rows = 0; rows <= n/2; rows++)
+ if (rows*rows >= n)
+ break;
+ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
+
+ /* window geoms (cell height/width) */
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1);
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1);
+ chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ cc = i / rows;
+ cr = i % rows;
+ cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest);
+ cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest);
+ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
+ }
+}
+#else
+void
+grid(Monitor *m)
+{
+ unsigned int i, n;
+ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+ /* grid dimensions */
+ for (rows = 0; rows <= n/2; rows++)
+ if (rows*rows >= n)
+ break;
+ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
+
+ /* window geoms (cell height/width) */
+ ch = m->wh / (rows ? rows : 1);
+ cw = m->ww / (cols ? cols : 1);
+ chrest = m->wh - ch * rows;
+ cwrest = m->ww - cw * cols;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ cc = i / rows;
+ cr = i % rows;
+ cx = m->wx + cc * cw + MIN(cc, cwrest);
+ cy = m->wy + cr * ch + MIN(cr, chrest);
+ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
+ }
+}
+#endif
+
diff --git a/patch/layout_grid.h b/patch/layout_grid.h
new file mode 100644
index 0000000..2c03abb
--- /dev/null
+++ b/patch/layout_grid.h
@@ -0,0 +1,2 @@
+static void grid(Monitor *m);
+
diff --git a/patch/layout_horizgrid.c b/patch/layout_horizgrid.c
new file mode 100644
index 0000000..beb8e0b
--- /dev/null
+++ b/patch/layout_horizgrid.c
@@ -0,0 +1,104 @@
+void
+horizgrid(Monitor *m) {
+ Client *c;
+ unsigned int n, i;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ int ntop;
+ float mfacts = 0, sfacts = 0;
+ int mrest, srest, mtotal = 0, stotal = 0;
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+ if (n == 0)
+ return;
+
+ if (n <= 2)
+ ntop = n;
+ else {
+ ntop = n / 2;
+ }
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ sw = mw = m->ww - 2*ov;
+
+ if (n > ntop) {
+ sh = (mh - ih) / 2;
+ mh = mh - ih - sh;
+ sy = my + mh + ih;
+ mw = m->ww - 2*ov - iv * (ntop - 1);
+ sw = m->ww - 2*ov - iv * (n - ntop - 1);
+ }
+ #else
+ sx = mx = m->wx;
+ sy = my = m->wy;
+ sh = mh = m->wh;
+ sw = mw = m->ww;
+
+ if (n > ntop) {
+ sh = mh / 2;
+ mh = mh - sh;
+ sy = my + mh;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ /* calculate facts */
+ #if CFACTS_PATCH
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop)
+ mfacts += c->cfact;
+ else
+ sfacts += c->cfact;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop)
+ mtotal += mh * (c->cfact / mfacts);
+ else
+ stotal += sw * (c->cfact / sfacts);
+ #else
+ mfacts = ntop;
+ sfacts = n - ntop;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop)
+ mtotal += mh / mfacts;
+ else
+ stotal += sw / sfacts;
+ #endif // CFACTS_PATCH
+
+ mrest = mh - mtotal;
+ srest = sw - stotal;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, mw / mfacts + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ mx += WIDTH(c) + iv;
+ #else
+ mx += WIDTH(c);
+ #endif // VANITYGAPS_PATCH
+ } else {
+ #if CFACTS_PATCH
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, sw / sfacts + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sx += WIDTH(c) + iv;
+ #else
+ sx += WIDTH(c);
+ #endif // VANITYGAPS_PATCH
+ }
+}
+
diff --git a/patch/layout_horizgrid.h b/patch/layout_horizgrid.h
new file mode 100644
index 0000000..799fa9c
--- /dev/null
+++ b/patch/layout_horizgrid.h
@@ -0,0 +1,2 @@
+static void horizgrid(Monitor *m);
+
diff --git a/patch/layout_monocle.c b/patch/layout_monocle.c
new file mode 100644
index 0000000..f7b5bc3
--- /dev/null
+++ b/patch/layout_monocle.c
@@ -0,0 +1,38 @@
+#if VANITYGAPS_PATCH && VANITYGAPS_MONOCLE_PATCH
+void
+monocle(Monitor *m)
+{
+ unsigned int n;
+ int oh, ov, ih, iv;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+
+ #if !MONOCLESYMBOL_PATCH
+ if (n > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
+ #endif // MONOCLESYMBOL_PATCH
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
+ resize(c, m->wx + ov, m->wy + oh, m->ww - 2 * c->bw - 2 * ov, m->wh - 2 * c->bw - 2 * oh, 0);
+}
+#else
+void
+monocle(Monitor *m)
+{
+ #if !MONOCLESYMBOL_PATCH
+ unsigned int n = 0;
+ #endif // MONOCLESYMBOL_PATCH
+ Client *c;
+
+ #if !MONOCLESYMBOL_PATCH
+ 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);
+ #endif // MONOCLESYMBOL_PATCH
+ 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);
+}
+#endif // VANITYGAPS_PATCH
+
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_nrowgrid.c b/patch/layout_nrowgrid.c
new file mode 100644
index 0000000..7fada74
--- /dev/null
+++ b/patch/layout_nrowgrid.c
@@ -0,0 +1,104 @@
+#if VANITYGAPS_PATCH
+void
+nrowgrid(Monitor *m)
+{
+ unsigned int n = 0, i = 0, ri = 0, ci = 0; /* counters */
+ int oh, ov, ih, iv; /* vanitygap settings */
+ unsigned int cx, cy, cw, ch; /* client geometry */
+ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
+ unsigned int cols, rows = m->nmaster + 1;
+ Client *c;
+
+ /* count clients */
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+
+ /* nothing to do here */
+ if (n == 0)
+ return;
+
+ /* force 2 clients to always split vertically */
+ if (FORCE_VSPLIT && n == 2)
+ rows = 1;
+
+ /* never allow empty rows */
+ if (n < rows)
+ rows = n;
+
+ /* define first row */
+ cols = n / rows;
+ uc = cols;
+ cy = m->wy + oh;
+ ch = (m->wh - 2*oh - ih*(rows - 1)) / rows;
+ uh = ch;
+
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, ci++) {
+ if (ci == cols) {
+ uw = 0;
+ ci = 0;
+ ri++;
+
+ /* next row */
+ cols = (n - uc) / (rows - ri);
+ uc += cols;
+ cy = m->wy + oh + uh + ih;
+ uh += ch + ih;
+ }
+
+ cx = m->wx + ov + uw;
+ cw = (m->ww - 2*ov - uw) / (cols - ci);
+ uw += cw + iv;
+
+ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0);
+ }
+}
+#else
+void
+nrowgrid(Monitor *m)
+{
+ unsigned int n = 0, i = 0, ri = 0, ci = 0; /* counters */
+ unsigned int cx, cy, cw, ch; /* client geometry */
+ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
+ unsigned int cols, rows = m->nmaster + 1;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ /* force 2 clients to always split vertically */
+ if (FORCE_VSPLIT && n == 2)
+ rows = 1;
+
+ /* never allow empty rows */
+ if (n < rows)
+ rows = n;
+
+ /* define first row */
+ cols = n / rows;
+ uc = cols;
+ cy = m->wy;
+ ch = m->wh / rows;
+ uh = ch;
+
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, ci++) {
+ if (ci == cols) {
+ uw = 0;
+ ci = 0;
+ ri++;
+
+ /* next row */
+ cols = (n - uc) / (rows - ri);
+ uc += cols;
+ cy = m->wy + uh;
+ uh += ch;
+ }
+
+ cx = m->wx + uw;
+ cw = (m->ww - uw) / (cols - ci);
+ uw += cw;
+
+ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0);
+ }
+}
+#endif
+
diff --git a/patch/layout_nrowgrid.h b/patch/layout_nrowgrid.h
new file mode 100644
index 0000000..9cce593
--- /dev/null
+++ b/patch/layout_nrowgrid.h
@@ -0,0 +1,2 @@
+static void nrowgrid(Monitor *m);
+
diff --git a/patch/layout_tile.c b/patch/layout_tile.c
new file mode 100644
index 0000000..cd4f1ae
--- /dev/null
+++ b/patch/layout_tile.c
@@ -0,0 +1,74 @@
+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;
+
+
+ #if VANITYGAPS_PATCH
+ int oh, ov, ih, iv;
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ #else
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ #endif // VANITYGAPS_PATCH
+
+ if (n == 0)
+ return;
+
+ #if VANITYGAPS_PATCH
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
+ sw = mw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sw = (mw - iv) * (1 - m->mfact);
+ mw = (mw - iv) * m->mfact;
+ sx = mx + mw + iv;
+ }
+ #else
+ 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;
+ }
+ #endif // VANITYGAPS_PATCH
+
+ 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) {
+ #if CFACTS_PATCH
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ my += HEIGHT(c) + ih;
+ #else
+ my += HEIGHT(c);
+ #endif
+ } else {
+ #if CFACTS_PATCH
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #else
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ #endif // CFACTS_PATCH
+ #if VANITYGAPS_PATCH
+ sy += HEIGHT(c) + ih;
+ #else
+ sy += HEIGHT(c);
+ #endif
+ }
+}
+
diff --git a/patch/layout_tile.h b/patch/layout_tile.h
new file mode 100644
index 0000000..78cafc8
--- /dev/null
+++ b/patch/layout_tile.h
@@ -0,0 +1,2 @@
+static void tile(Monitor *);
+
diff --git a/patch/layoutmenu.sh b/patch/layoutmenu.sh
new file mode 100755
index 0000000..0bb0456
--- /dev/null
+++ b/patch/layoutmenu.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+cat <<EOF | xmenu
+[]= Tiled Layout 0
+><> Floating Layout 1
+[M] Monocle Layout 2
+EOF
+
diff --git a/patch/maximize.c b/patch/maximize.c
new file mode 100644
index 0000000..c89dbda
--- /dev/null
+++ b/patch/maximize.c
@@ -0,0 +1,70 @@
+void
+maximize(int x, int y, int w, int h)
+{
+ XEvent ev;
+
+ if (!selmon->sel || selmon->sel->isfixed)
+ return;
+ XRaiseWindow(dpy, selmon->sel->win);
+ if (!selmon->sel->ismax) {
+ if (!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating)
+ selmon->sel->wasfloating = True;
+ else {
+ togglefloating(NULL);
+ selmon->sel->wasfloating = False;
+ }
+ selmon->sel->oldx = selmon->sel->x;
+ selmon->sel->oldy = selmon->sel->y;
+ selmon->sel->oldw = selmon->sel->w;
+ selmon->sel->oldh = selmon->sel->h;
+ resize(selmon->sel, x, y, w, h, True);
+ selmon->sel->ismax = True;
+ }
+ else {
+ resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, True);
+ if (!selmon->sel->wasfloating)
+ togglefloating(NULL);
+ selmon->sel->ismax = False;
+ }
+ drawbar(selmon);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+#if SETBORDERPX_PATCH
+void
+togglemax(const Arg *arg)
+{
+ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * selmon->borderpx, selmon->wh - 2 * selmon->borderpx);
+}
+
+void
+toggleverticalmax(const Arg *arg)
+{
+ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * selmon->borderpx);
+}
+
+void
+togglehorizontalmax(const Arg *arg)
+{
+ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * selmon->borderpx, selmon->sel->h);
+}
+#else
+void
+togglemax(const Arg *arg)
+{
+ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx);
+}
+
+void
+toggleverticalmax(const Arg *arg)
+{
+ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx);
+}
+
+void
+togglehorizontalmax(const Arg *arg)
+{
+ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h);
+}
+#endif // SETBORDERPX_PATCH
+
diff --git a/patch/maximize.h b/patch/maximize.h
new file mode 100644
index 0000000..f3c6c9a
--- /dev/null
+++ b/patch/maximize.h
@@ -0,0 +1,5 @@
+static void maximize(int x, int y, int w, int h);
+static void togglemax(const Arg *arg);
+static void toggleverticalmax(const Arg *arg);
+static void togglehorizontalmax(const Arg *arg);
+
diff --git a/patch/moveplace.c b/patch/moveplace.c
new file mode 100644
index 0000000..7211417
--- /dev/null
+++ b/patch/moveplace.c
@@ -0,0 +1,30 @@
+void
+moveplace(const Arg *arg)
+{
+ Client *c;
+ int nh, nw, nx, ny;
+ c = selmon->sel;
+ if (!c || (arg->ui >= 9))
+ return;
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+ togglefloating(NULL);
+ nh = (selmon->wh / 3) - (c->bw * 2);
+ nw = (selmon->ww / 3) - (c->bw * 2);
+ nx = (arg->ui % 3) -1;
+ ny = (arg->ui / 3) -1;
+ if (nx < 0)
+ nx = selmon->wx;
+ else if (nx > 0)
+ nx = selmon->wx + selmon->ww - nw - c->bw*2;
+ else
+ nx = selmon->wx + selmon->ww/2 - nw/2 - c->bw;
+ if (ny <0)
+ ny = selmon->wy;
+ else if (ny > 0)
+ ny = selmon->wy + selmon->wh - nh - c->bw*2;
+ else
+ ny = selmon->wy + selmon->wh/2 - nh/2 - c->bw;
+ resize(c, nx, ny, nw, nh, True);
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, nw/2, nh/2);
+}
+
diff --git a/patch/moveplace.h b/patch/moveplace.h
new file mode 100644
index 0000000..57bc924
--- /dev/null
+++ b/patch/moveplace.h
@@ -0,0 +1,4 @@
+enum { WIN_NW, WIN_N, WIN_NE, WIN_W, WIN_C, WIN_E, WIN_SW, WIN_S, WIN_SE };
+
+static void moveplace(const Arg *arg);
+
diff --git a/patch/moveresize.c b/patch/moveresize.c
new file mode 100644
index 0000000..75d58e2
--- /dev/null
+++ b/patch/moveresize.c
@@ -0,0 +1,65 @@
+void
+moveresize(const Arg *arg) {
+ /* only floating windows can be moved */
+ Client *c;
+ c = selmon->sel;
+ int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh;
+ char xAbs, yAbs, wAbs, hAbs;
+ int msx, msy, dx, dy, nmx, nmy;
+ unsigned int dui;
+ Window dummy;
+
+ if (!c || !arg)
+ return;
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
+ return;
+ if (sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8)
+ return;
+
+ /* compute new window position; prevent window from be positioned outside the current monitor */
+ nw = c->w + w;
+ if (wAbs == 'W')
+ nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw;
+
+ nh = c->h + h;
+ if (hAbs == 'H')
+ nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw;
+
+ nx = c->x + x;
+ if (xAbs == 'X') {
+ if (x < selmon->mx)
+ nx = selmon->mx;
+ else if (x > selmon->mx + selmon->mw)
+ nx = selmon->mx + selmon->mw - nw - 2 * c->bw;
+ else
+ nx = x;
+ }
+
+ ny = c->y + y;
+ if (yAbs == 'Y') {
+ if (y < selmon->my)
+ ny = selmon->my;
+ else if (y > selmon->my + selmon->mh)
+ ny = selmon->my + selmon->mh - nh - 2 * c->bw;
+ else
+ ny = y;
+ }
+
+ ox = c->x;
+ oy = c->y;
+ ow = c->w;
+ oh = c->h;
+
+ XRaiseWindow(dpy, c->win);
+ Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui);
+ resize(c, nx, ny, nw, nh, True);
+
+ /* move cursor along with the window to avoid problems caused by the sloppy focus */
+ if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy)
+ {
+ nmx = c->x - ox + c->w - ow;
+ nmy = c->y - oy + c->h - oh;
+ XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy);
+ }
+}
+
diff --git a/patch/moveresize.h b/patch/moveresize.h
new file mode 100644
index 0000000..919ebad
--- /dev/null
+++ b/patch/moveresize.h
@@ -0,0 +1,2 @@
+static void moveresize(const Arg *arg);
+
diff --git a/patch/movestack.c b/patch/movestack.c
new file mode 100644
index 0000000..fe97f1d
--- /dev/null
+++ b/patch/movestack.c
@@ -0,0 +1,51 @@
+void
+movestack(const Arg *arg)
+{
+ Client *c = NULL, *p = NULL, *pc = NULL, *i;
+ if (arg->i > 0) {
+ if (!selmon->sel)
+ return;
+ /* 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);
+ }
+}
+
diff --git a/patch/movestack.h b/patch/movestack.h
new file mode 100644
index 0000000..25f198f
--- /dev/null
+++ b/patch/movestack.h
@@ -0,0 +1,2 @@
+static void movestack(const Arg *arg);
+
diff --git a/patch/mpdcontrol.c b/patch/mpdcontrol.c
new file mode 100644
index 0000000..fc81e07
--- /dev/null
+++ b/patch/mpdcontrol.c
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <regex.h>
+
+#include <mpd/client.h>
+
+#define MPDHOST "localhost"
+#define MPDPORT 6600
+
+struct mpd_connection *get_conn()
+{
+ struct mpd_connection *conn;
+
+ conn = mpd_connection_new(MPDHOST, MPDPORT, 1000);
+
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
+ fprintf(stderr, "Could not connect to mpd: %s\n", mpd_connection_get_error_message(conn));
+
+ mpd_connection_free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+void mpdchange(const Arg *direction)
+{
+ struct mpd_connection *conn;
+
+ conn = get_conn();
+
+ if (conn == NULL) {
+ return;
+ }
+
+ if (direction->i > 0) {
+ mpd_run_next(conn);
+ }
+ else {
+ mpd_run_previous(conn);
+ }
+
+ mpd_connection_free(conn);
+}
+
+char *get_regerror(int errcode, regex_t *compiled)
+{
+ size_t length = regerror(errcode, compiled, NULL, 0);
+ char *buffer = malloc(length);
+ (void) regerror(errcode, compiled, buffer, length);
+
+ return buffer;
+}
+
+void mpdcontrol()
+{
+ struct mpd_connection *conn;
+ struct mpd_status *status;
+ struct mpd_song *song;
+ enum mpd_state state;
+
+ const char *filename;
+
+ regex_t expr;
+
+ conn = get_conn();
+
+ if (conn == NULL) {
+ return;
+ }
+
+ status = mpd_run_status(conn);
+
+ if (status == NULL) {
+ fprintf(stderr, "Could not get mpd status: %s\n", mpd_status_get_error(status));
+
+ mpd_status_free(status);
+ mpd_connection_free(conn);
+ return;
+ }
+
+ state = mpd_status_get_state(status);
+
+ if (state == MPD_STATE_STOP || state == MPD_STATE_PAUSE) {
+ mpd_run_play(conn);
+ mpd_status_free(status);
+ mpd_connection_free(conn);
+ }
+ else if (state != MPD_STATE_UNKNOWN) { //playing some music
+ song = mpd_run_current_song(conn);
+
+ if (song == NULL){
+ fprintf(stderr, "Error fetching current song!\n");
+
+ mpd_song_free(song);
+ mpd_status_free(status);
+ mpd_connection_free(conn);
+ return;
+ }
+
+ filename = mpd_song_get_uri(song);
+
+ int errcode = regcomp(&expr, "^[[:alnum:]]+://", REG_EXTENDED|REG_NOSUB);
+ if (errcode != 0) {
+ char *err = get_regerror(errcode, &expr);
+ fprintf(stderr, "Could not compile regexp: %s\n", err);
+
+ mpd_song_free(song);
+ mpd_status_free(status);
+ mpd_connection_free(conn);
+ free(err);
+ regfree(&expr);
+ return;
+ }
+
+ int matchcode = regexec(&expr, filename, 0, NULL, 0);
+
+ if (matchcode == 0) {
+ if (strstr(filename, "file://") == filename) { //match just at the start of the filename
+ //this means that mpd is playing a file outside the music_dir,
+ //but on disk, so we can safely pause
+ mpd_run_toggle_pause(conn);
+ }
+ else {
+ mpd_run_stop(conn);
+ }
+ }
+ else if (matchcode == REG_NOMATCH) {
+ mpd_run_toggle_pause(conn);
+ }
+ else {
+ char *err = get_regerror(matchcode, &expr);
+ fprintf(stderr, "Error while matching regexp: %s\n", err);
+
+ free(err);
+ }
+
+ regfree(&expr);
+ mpd_song_free(song);
+ mpd_status_free(status);
+ mpd_connection_free(conn);
+ }
+}
+
diff --git a/patch/mpdcontrol.h b/patch/mpdcontrol.h
new file mode 100644
index 0000000..1ce304e
--- /dev/null
+++ b/patch/mpdcontrol.h
@@ -0,0 +1,3 @@
+static void mpdchange(const Arg *direction);
+static void mpdcontrol();
+
diff --git a/patch/nomodbuttons.c b/patch/nomodbuttons.c
new file mode 100644
index 0000000..9c196de
--- /dev/null
+++ b/patch/nomodbuttons.c
@@ -0,0 +1,8 @@
+void
+togglenomodbuttons(const Arg *arg)
+{
+ nomodbuttons = !nomodbuttons;
+ if (selmon->sel)
+ grabbuttons(selmon->sel, 1);
+}
+
diff --git a/patch/nomodbuttons.h b/patch/nomodbuttons.h
new file mode 100644
index 0000000..a613ed4
--- /dev/null
+++ b/patch/nomodbuttons.h
@@ -0,0 +1,2 @@
+static void togglenomodbuttons(const Arg *arg);
+
diff --git a/patch/pertag.c b/patch/pertag.c
new file mode 100644
index 0000000..f534023
--- /dev/null
+++ b/patch/pertag.c
@@ -0,0 +1,78 @@
+struct Pertag {
+ unsigned int curtag, prevtag; /* current and previous tag */
+ int nmasters[NUMTAGS + 1]; /* number of windows in master area */
+ #if FLEXTILE_DELUXE_LAYOUT
+ int nstacks[NUMTAGS + 1]; /* number of windows in primary stack area */
+ int ltaxis[NUMTAGS + 1][LTAXIS_LAST];
+ const Layout *ltidxs[NUMTAGS + 1][3]; /* matrix of tags and layouts indexes */
+ #else
+ const Layout *ltidxs[NUMTAGS + 1][2]; /* matrix of tags and layouts indexes */
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ float mfacts[NUMTAGS + 1]; /* mfacts per tag */
+ unsigned int sellts[NUMTAGS + 1]; /* selected layouts */
+ #if PERTAGBAR_PATCH
+ int showbars[NUMTAGS + 1]; /* display bar for the current tag */
+ #endif // PERTAGBAR_PATCH
+ #if SWAPFOCUS_PATCH
+ Client *prevclient[NUMTAGS + 1];
+ #endif // SWAPFOCUS_PATCH
+ #if ZOOMSWAP_PATCH
+ Client *prevzooms[NUMTAGS + 1]; /* store zoom information */
+ #endif // ZOOMSWAP_PATCH
+ #if PERTAG_VANITYGAPS_PATCH && VANITYGAPS_PATCH
+ int enablegaps[NUMTAGS + 1];
+ unsigned int gaps[NUMTAGS + 1];
+ #endif // PERTAG_VANITYGAPS_PATCH | VANITYGAPS_PATCH
+};
+
+void
+pertagview(const Arg *arg)
+{
+ int i;
+ unsigned int tmptag;
+ if (arg->ui & TAGMASK) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ #if SCRATCHPADS_PATCH
+ if (arg->ui == ~SPTAGMASK)
+ #else
+ if (arg->ui == ~0)
+ #endif // SCRATCHPADS_PATCH
+ 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];
+ #if FLEXTILE_DELUXE_LAYOUT
+ selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag];
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ 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 PERTAG_VANITYGAPS_PATCH && VANITYGAPS_PATCH
+ selmon->gappoh = (selmon->pertag->gaps[selmon->pertag->curtag] & 0xff) >> 0;
+ selmon->gappov = (selmon->pertag->gaps[selmon->pertag->curtag] & 0xff00) >> 8;
+ selmon->gappih = (selmon->pertag->gaps[selmon->pertag->curtag] & 0xff0000) >> 16;
+ selmon->gappiv = (selmon->pertag->gaps[selmon->pertag->curtag] & 0xff000000) >> 24;
+ #endif // PERTAG_VANITYGAPS_PATCH | VANITYGAPS_PATCH
+
+ #if FLEXTILE_DELUXE_LAYOUT
+ selmon->ltaxis[LAYOUT] = selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT];
+ selmon->ltaxis[MASTER] = selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER];
+ selmon->ltaxis[STACK] = selmon->pertag->ltaxis[selmon->pertag->curtag][STACK];
+ selmon->ltaxis[STACK2] = selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2];
+ #endif // FLEXTILE_DELUXE_LAYOUT
+ #if PERTAGBAR_PATCH
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+ #endif // PERTAGBAR_PATCH
+}
+
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/placemouse.c b/patch/placemouse.c
new file mode 100644
index 0000000..0208baf
--- /dev/null
+++ b/patch/placemouse.c
@@ -0,0 +1,153 @@
+void
+moveorplace(const Arg *arg) {
+ if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)))
+ movemouse(arg);
+ else
+ placemouse(arg);
+}
+
+void
+placemouse(const Arg *arg)
+{
+ int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0;
+ Client *c, *r = NULL, *at, *prevr;
+ Monitor *m;
+ XEvent ev;
+ XWindowAttributes wa;
+ Time lasttime = 0;
+ int attachmode, prevattachmode;
+ attachmode = prevattachmode = -1;
+
+ if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */
+ return;
+ if (c->isfullscreen) /* no support placing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ prevr = c;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ return;
+
+ c->isfloating = 0;
+ c->beingmoved = 1;
+
+ XGetWindowAttributes(dpy, c->win, &wa);
+ ocx = wa.x;
+ ocy = wa.y;
+
+ if (arg->i == 2) // warp cursor to client center
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2);
+
+ if (!getrootptr(&x, &y))
+ return;
+
+ 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 (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap))
+ freemove = 1;
+
+ if (freemove)
+ XMoveWindow(dpy, c->win, nx, ny);
+
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon)
+ selmon = m;
+
+ if (arg->i == 1) { // tiled position is relative to the client window center point
+ px = nx + wa.width / 2;
+ py = ny + wa.height / 2;
+ } else { // tiled position is relative to the mouse cursor
+ px = ev.xmotion.x;
+ py = ev.xmotion.y;
+ }
+
+ r = recttoclient(px, py, 1, 1);
+
+ if (!r || r == c)
+ break;
+
+ if ((((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)
+ && (abs(r->y - py) < r->h / 2)) || (abs(r->x - px) < r->w / 2))
+ attachmode = 1; // above
+ else
+ attachmode = 0; // below
+
+ if ((r && r != prevr) || (attachmode != prevattachmode)) {
+ detachstack(c);
+ detach(c);
+ if (c->mon != r->mon)
+ arrangemon(c->mon);
+
+ c->mon = r->mon;
+ r->mon->sel = r;
+
+ if (attachmode) {
+ if (r == r->mon->clients)
+ attach(c);
+ else {
+ for (at = r->mon->clients; at->next != r; at = at->next);
+ c->next = at->next;
+ at->next = c;
+ }
+ } else {
+ c->next = r->next;
+ r->next = c;
+ }
+
+ attachstack(c);
+ arrangemon(r->mon);
+ prevr = r;
+ prevattachmode = attachmode;
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) {
+ detach(c);
+ detachstack(c);
+ arrangemon(c->mon);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags];
+ attach(c);
+ attachstack(c);
+ selmon = m;
+ }
+
+ focus(c);
+ c->beingmoved = 0;
+
+ if (nx != -9999)
+ resize(c, nx, ny, c->w, c->h, 0);
+ arrangemon(c->mon);
+}
+
+Client *
+recttoclient(int x, int y, int w, int h)
+{
+ Client *c, *r = NULL;
+ int a, area = 0;
+
+ for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) {
+ if ((a = INTERSECTC(x, y, w, h, c)) > area) {
+ area = a;
+ r = c;
+ }
+ }
+ return r;
+}
+
diff --git a/patch/placemouse.h b/patch/placemouse.h
new file mode 100644
index 0000000..20c3eca
--- /dev/null
+++ b/patch/placemouse.h
@@ -0,0 +1,7 @@
+#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \
+ * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y)))
+
+static void moveorplace(const Arg *arg);
+static void placemouse(const Arg *arg);
+static Client *recttoclient(int x, int y, int w, int h);
+
diff --git a/patch/push.c b/patch/push.c
new file mode 100644
index 0000000..9410e61
--- /dev/null
+++ b/patch/push.c
@@ -0,0 +1,72 @@
+static Client *
+nextc(Client *c, float f)
+{
+ if (!f)
+ return nexttiled(c);
+
+ for (; c && !ISVISIBLE(c); c = c->next);
+ return c;
+}
+
+static Client *
+prevc(Client *c, float f)
+{
+ Client *p, *r;
+
+ for (p = selmon->clients, r = NULL; c && p && p != c; p = p->next)
+ if ((f || !p->isfloating) && ISVISIBLE(p))
+ r = p;
+ return r;
+}
+
+static void
+pushup(const Arg *arg)
+{
+ Client *sel = selmon->sel;
+ Client *c;
+
+ if (!sel || (sel->isfloating && !arg->f))
+ return;
+ if ((c = prevc(sel, arg->f))) {
+ /* attach before c */
+ detach(sel);
+ sel->next = c;
+ if (selmon->clients == c)
+ selmon->clients = sel;
+ else {
+ for (c = selmon->clients; c->next != sel->next; c = c->next);
+ c->next = sel;
+ }
+ } else {
+ /* move to the end */
+ for (c = sel; c->next; c = c->next);
+ detach(sel);
+ sel->next = NULL;
+ c->next = sel;
+ }
+ focus(sel);
+ arrange(selmon);
+}
+
+static void
+pushdown(const Arg *arg)
+{
+ Client *sel = selmon->sel;
+ Client *c;
+
+ if (!sel || (sel->isfloating && !arg->f))
+ return;
+ if ((c = nextc(sel->next, arg->f))) {
+ /* attach after c */
+ detach(sel);
+ sel->next = c->next;
+ c->next = sel;
+ } else {
+ /* move to the front */
+ detach(sel);
+ attach(sel);
+ }
+ focus(sel);
+ arrange(selmon);
+}
+
diff --git a/patch/push.h b/patch/push.h
new file mode 100644
index 0000000..6415f80
--- /dev/null
+++ b/patch/push.h
@@ -0,0 +1,5 @@
+static Client * nextc(Client *c, float f);
+static Client * prevc(Client *c, float f);
+static void pushup(const Arg *arg);
+static void pushdown(const Arg *arg);
+
diff --git a/patch/push_no_master.c b/patch/push_no_master.c
new file mode 100644
index 0000000..2d78cf4
--- /dev/null
+++ b/patch/push_no_master.c
@@ -0,0 +1,44 @@
+Client *
+prevt(Client *c)
+{
+ Client *p, *r;
+
+ for (p = selmon->clients, r = NULL; p && p != c; p = p->next)
+ if (!p->isfloating && ISVISIBLE(p))
+ r = p;
+ return r;
+}
+
+void
+pushup(const Arg *arg)
+{
+ Client *sel = selmon->sel, *c;
+
+ if (!sel || sel->isfloating)
+ return;
+ if ((c = prevt(sel)) && c != nexttiled(selmon->clients)) {
+ detach(sel);
+ sel->next = c;
+ for (c = selmon->clients; c->next != sel->next; c = c->next);
+ c->next = sel;
+ }
+ focus(sel);
+ arrange(selmon);
+}
+
+void
+pushdown(const Arg *arg)
+{
+ Client *sel = selmon->sel, *c;
+
+ if (!sel || sel->isfloating || sel == nexttiled(selmon->clients))
+ return;
+ if ((c = nexttiled(sel->next))) {
+ detach(sel);
+ sel->next = c->next;
+ c->next = sel;
+ }
+ focus(sel);
+ arrange(selmon);
+}
+
diff --git a/patch/push_no_master.h b/patch/push_no_master.h
new file mode 100644
index 0000000..6904fb0
--- /dev/null
+++ b/patch/push_no_master.h
@@ -0,0 +1,4 @@
+Client * prevt(Client *c);
+static void pushup(const Arg *arg);
+static void pushdown(const Arg *arg);
+
diff --git a/patch/reorganizetags.c b/patch/reorganizetags.c
new file mode 100644
index 0000000..1aff54a
--- /dev/null
+++ b/patch/reorganizetags.c
@@ -0,0 +1,28 @@
+void
+reorganizetags(const Arg *arg)
+{
+ Client *c;
+ unsigned int occ, unocc, i;
+ unsigned int tagdest[NUMTAGS];
+
+ occ = 0;
+ for (c = selmon->clients; c; c = c->next)
+ occ |= (1 << (ffs(c->tags)-1));
+ unocc = 0;
+ for (i = 0; i < NUMTAGS; ++i) {
+ while (unocc < i && (occ & (1 << unocc)))
+ unocc++;
+ if (occ & (1 << i)) {
+ tagdest[i] = unocc;
+ occ &= ~(1 << i);
+ occ |= 1 << unocc;
+ }
+ }
+
+ for (c = selmon->clients; c; c = c->next)
+ c->tags = 1 << tagdest[ffs(c->tags)-1];
+ if (selmon->sel)
+ selmon->tagset[selmon->seltags] = selmon->sel->tags;
+ arrange(selmon);
+}
+
diff --git a/patch/reorganizetags.h b/patch/reorganizetags.h
new file mode 100644
index 0000000..c4917af
--- /dev/null
+++ b/patch/reorganizetags.h
@@ -0,0 +1,2 @@
+static void reorganizetags(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/riodraw.c b/patch/riodraw.c
new file mode 100644
index 0000000..c430f5c
--- /dev/null
+++ b/patch/riodraw.c
@@ -0,0 +1,104 @@
+/* drag out an area using slop and resize the selected window to it. */
+int
+riodraw(Client *c, const char slopstyle[])
+{
+ int i;
+ char str[100];
+ char strout[100];
+ char tmpstring[30] = {0};
+ char slopcmd[100] = "slop -f x%xx%yx%wx%hx ";
+ int firstchar = 0;
+ int counter = 0;
+
+ strcat(slopcmd, slopstyle);
+ FILE *fp = popen(slopcmd, "r");
+
+ while (fgets(str, 100, fp) != NULL)
+ strcat(strout, str);
+
+ pclose(fp);
+
+ if (strlen(strout) < 6)
+ return 0;
+
+ for (i = 0; i < strlen(strout); i++){
+ if (!firstchar) {
+ if (strout[i] == 'x')
+ firstchar = 1;
+ continue;
+ }
+
+ if (strout[i] != 'x')
+ tmpstring[strlen(tmpstring)] = strout[i];
+ else {
+ riodimensions[counter] = atoi(tmpstring);
+ counter++;
+ memset(tmpstring,0,strlen(tmpstring));
+ }
+ }
+
+ if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) {
+ riodimensions[3] = -1;
+ return 0;
+ }
+
+ if (c) {
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+rioposition(Client *c, int x, int y, int w, int h)
+{
+ Monitor *m;
+ if ((m = recttomon(x, y, w, h)) && m != c->mon) {
+ detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags];
+ attach(c);
+ attachstack(c);
+ selmon = m;
+ focus(c);
+ }
+
+ c->isfloating = 1;
+ if (riodraw_borders)
+ resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2));
+ else
+ resizeclient(c, x - c->bw, y - c->bw, w, h);
+ drawbar(c->mon);
+ arrange(c->mon);
+
+ riodimensions[3] = -1;
+ riopid = 0;
+}
+
+/* drag out an area using slop and resize the selected window to it */
+void
+rioresize(const Arg *arg)
+{
+ Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel);
+ if (c)
+ riodraw(c, slopresizestyle);
+}
+
+/* Spawn a new window and drag out an area using slop to position it while the window is
+ * initialising in the background. */
+void
+riospawn(const Arg *arg)
+{
+ riopid = spawncmd(arg);
+ riodraw(NULL, slopspawnstyle);
+}
+
+void
+riospawnsync(const Arg *arg)
+{
+ if (riodraw(NULL, slopspawnstyle))
+ riopid = spawncmd(arg);
+}
+
diff --git a/patch/riodraw.h b/patch/riodraw.h
new file mode 100644
index 0000000..7756aeb
--- /dev/null
+++ b/patch/riodraw.h
@@ -0,0 +1,6 @@
+static int riodraw(Client *c, const char slopstyle[]);
+static void rioposition(Client *c, int x, int y, int w, int h);
+static void rioresize(const Arg *arg);
+static void riospawn(const Arg *arg);
+static void riospawnsync(const Arg *arg);
+
diff --git a/patch/rotatestack.c b/patch/rotatestack.c
new file mode 100644
index 0000000..41df8b1
--- /dev/null
+++ b/patch/rotatestack.c
@@ -0,0 +1,53 @@
+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
+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);
+ focus(f);
+ restack(selmon);
+ }
+}
+
diff --git a/patch/rotatestack.h b/patch/rotatestack.h
new file mode 100644
index 0000000..ea64e68
--- /dev/null
+++ b/patch/rotatestack.h
@@ -0,0 +1,4 @@
+static void enqueue(Client *c);
+static void enqueuestack(Client *c);
+static void rotatestack(const Arg *arg);
+
diff --git a/patch/roundedcorners.c b/patch/roundedcorners.c
new file mode 100644
index 0000000..881dbab
--- /dev/null
+++ b/patch/roundedcorners.c
@@ -0,0 +1,51 @@
+#include <X11/extensions/shape.h>
+
+void drawroundedcorners(Client *c)
+{
+ if (corner_radius <= 0 || !c || c->isfullscreen)
+ return;
+
+ Window win;
+ win = c->win;
+ if (!win)
+ return;
+
+ XWindowAttributes win_attr;
+ if (!XGetWindowAttributes(dpy, win, &win_attr))
+ return;
+
+ int dia = 2 * corner_radius;
+ int w = c->w;
+ int h = c->h;
+ if (w < dia || h < dia)
+ return;
+
+ Pixmap mask;
+ mask = XCreatePixmap(dpy, win, w, h, 1);
+ if (!mask)
+ return;
+
+ XGCValues xgcv;
+ GC shape_gc;
+ shape_gc = XCreateGC(dpy, mask, 0, &xgcv);
+
+ if (!shape_gc) {
+ XFreePixmap(dpy, mask);
+ free(shape_gc);
+ return;
+ }
+
+ XSetForeground(dpy, shape_gc, 0);
+ XFillRectangle(dpy, mask, shape_gc, 0, 0, w, h);
+ XSetForeground(dpy, shape_gc, 1);
+ XFillArc(dpy, mask, shape_gc, 0, 0, dia, dia, 0, 23040);
+ XFillArc(dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 23040);
+ XFillArc(dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 23040);
+ XFillArc(dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 23040);
+ XFillRectangle(dpy, mask, shape_gc, corner_radius, 0, w-dia, h);
+ XFillRectangle(dpy, mask, shape_gc, 0, corner_radius, w, h-dia);
+ XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, mask, ShapeSet);
+ XFreePixmap(dpy, mask);
+ XFreeGC(dpy, shape_gc);
+}
+
diff --git a/patch/roundedcorners.h b/patch/roundedcorners.h
new file mode 100644
index 0000000..31a1f31
--- /dev/null
+++ b/patch/roundedcorners.h
@@ -0,0 +1,2 @@
+static void drawroundedcorners(Client *c);
+
diff --git a/patch/scratchpad.c b/patch/scratchpad.c
new file mode 100644
index 0000000..9e24ff6
--- /dev/null
+++ b/patch/scratchpad.c
@@ -0,0 +1,77 @@
+void
+removescratch(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+ unsigned int scratchtag = SPTAG(arg->ui);
+ c->tags = c->mon->tagset[c->mon->seltags] ^ scratchtag;
+ arrange(c->mon);
+}
+
+void
+setscratch(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+ unsigned int scratchtag = SPTAG(arg->ui);
+ c->tags = scratchtag;
+ arrange(c->mon);
+}
+
+void
+togglescratch(const Arg *arg)
+{
+ Client *c = NULL, *next = NULL, *found = NULL;
+ Monitor *mon;
+ unsigned int scratchtag = SPTAG(arg->ui);
+ unsigned int newtagset = 0;
+ int nh = 0, nw = 0;
+ Arg sparg = {.v = scratchpads[arg->ui].cmd};
+
+ for (mon = mons; mon; mon = mon->next) {
+ for (c = mon->clients; c; c = next) {
+ next = c->next;
+ if (!(c->tags & scratchtag))
+ continue;
+
+ found = c;
+
+ if (HIDDEN(c)) {
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+ newtagset = 0;
+ } else
+ newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
+
+ if (c->mon != selmon) {
+ if (c->mon->tagset[c->mon->seltags] & SPTAGMASK)
+ c->mon->tagset[c->mon->seltags] ^= scratchtag;
+ if (c->w > selmon->ww)
+ nw = selmon->ww - c->bw * 2;
+ if (c->h > selmon->wh)
+ nh = selmon->wh - c->bw * 2;
+ if (nw > 0 || nh > 0)
+ resizeclient(c, c->x, c->y, nw ? nw : c->w, nh ? nh : c->h);
+ sendmon(c, selmon);
+ }
+ }
+ }
+
+ if (found) {
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
+ focus(NULL);
+ arrange(selmon);
+ }
+ if (ISVISIBLE(found)) {
+ focus(found);
+ restack(selmon);
+ }
+ } else {
+ selmon->tagset[selmon->seltags] |= scratchtag;
+ spawn(&sparg);
+ }
+}
+
diff --git a/patch/scratchpad.h b/patch/scratchpad.h
new file mode 100644
index 0000000..6230266
--- /dev/null
+++ b/patch/scratchpad.h
@@ -0,0 +1,9 @@
+typedef struct {
+ const char *name;
+ const void *cmd;
+} Sp;
+
+static void removescratch(const Arg *arg);
+static void setscratch(const Arg *arg);
+static void togglescratch(const Arg *arg);
+
diff --git a/patch/scratchpad_alt_1.c b/patch/scratchpad_alt_1.c
new file mode 100644
index 0000000..6724d5c
--- /dev/null
+++ b/patch/scratchpad_alt_1.c
@@ -0,0 +1,72 @@
+static Client * scratchpad_last_showed = NULL;
+
+void
+scratchpad_hide()
+{
+ if (selmon->sel) {
+ selmon->sel->tags = SCRATCHPAD_MASK;
+ selmon->sel->isfloating = 1;
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+_Bool
+scratchpad_last_showed_is_killed(void)
+{
+ Client *c;
+ for (c = selmon->clients; c && c != scratchpad_last_showed; c = c->next);
+ return (c == NULL);
+}
+
+void
+scratchpad_remove()
+{
+ if (selmon->sel && scratchpad_last_showed != NULL && selmon->sel == scratchpad_last_showed)
+ scratchpad_last_showed = NULL;
+}
+
+void
+scratchpad_show()
+{
+ if (scratchpad_last_showed == NULL || scratchpad_last_showed_is_killed()) {
+ scratchpad_show_first();
+ return;
+ }
+
+ if (scratchpad_last_showed->tags != SCRATCHPAD_MASK) {
+ scratchpad_last_showed->tags = SCRATCHPAD_MASK;
+ focus(NULL);
+ arrange(selmon);
+ return;
+ }
+
+ Client *c;
+
+ for (c = selmon->clients; c && c != scratchpad_last_showed; c = c->next);
+ for (c = (c ? c->next : NULL); c && c->tags != SCRATCHPAD_MASK; c = c->next);
+
+ if (c)
+ scratchpad_show_client(c);
+ else
+ scratchpad_show_first();
+}
+
+void
+scratchpad_show_client(Client* c)
+{
+ scratchpad_last_showed = c;
+ c->tags = selmon->tagset[selmon->seltags];
+ focus(c);
+ arrange(selmon);
+}
+
+void
+scratchpad_show_first(void)
+{
+ Client *c;
+ for (c = selmon->clients; c && c->tags != SCRATCHPAD_MASK; c = c->next);
+ if (c)
+ scratchpad_show_client(c);
+}
+
diff --git a/patch/scratchpad_alt_1.h b/patch/scratchpad_alt_1.h
new file mode 100644
index 0000000..4e25f11
--- /dev/null
+++ b/patch/scratchpad_alt_1.h
@@ -0,0 +1,9 @@
+#define SCRATCHPAD_MASK (1u << NUMTAGS)
+
+static void scratchpad_hide();
+static _Bool scratchpad_last_showed_is_killed(void);
+static void scratchpad_remove();
+static void scratchpad_show();
+static void scratchpad_show_client(Client *c);
+static void scratchpad_show_first(void);
+
diff --git a/patch/selfrestart.c b/patch/selfrestart.c
new file mode 100644
index 0000000..f733867
--- /dev/null
+++ b/patch/selfrestart.c
@@ -0,0 +1,69 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Magically finds the current's executable path
+ *
+ * I'm doing the do{}while(); trick because Linux (what I'm running) is not
+ * POSIX compilant and so lstat() cannot be trusted on /proc entries
+ *
+ * @return char* the path of the current executable
+ */
+char *get_dwm_path()
+{
+ struct stat s;
+ int r, length, rate = 42;
+ char *path = NULL;
+
+ if (lstat("/proc/self/exe", &s) == -1) {
+ perror("lstat:");
+ return NULL;
+ }
+
+ length = s.st_size + 1 - rate;
+
+ do
+ {
+ length+=rate;
+
+ free(path);
+ path = malloc(sizeof(char) * length);
+
+ if (path == NULL){
+ perror("malloc:");
+ return NULL;
+ }
+
+ r = readlink("/proc/self/exe", path, length);
+
+ if (r == -1){
+ perror("readlink:");
+ return NULL;
+ }
+ } while (r >= length);
+
+ path[r] = '\0';
+
+ return path;
+}
+
+/**
+ * self-restart
+ *
+ * Initially inspired by: Yu-Jie Lin
+ * https://sites.google.com/site/yjlnotes/notes/dwm
+ */
+void self_restart(const Arg *arg)
+{
+ char *const argv[] = {get_dwm_path(), NULL};
+
+ if (argv[0] == NULL) {
+ return;
+ }
+
+ execv(argv[0], argv);
+}
+
diff --git a/patch/selfrestart.h b/patch/selfrestart.h
new file mode 100644
index 0000000..3fd0b81
--- /dev/null
+++ b/patch/selfrestart.h
@@ -0,0 +1,3 @@
+char *get_dwm_path();
+void self_restart(const Arg *arg);
+
diff --git a/patch/setborderpx.c b/patch/setborderpx.c
new file mode 100644
index 0000000..948d6f6
--- /dev/null
+++ b/patch/setborderpx.c
@@ -0,0 +1,45 @@
+void
+setborderpx(const Arg *arg)
+{
+ Client *c;
+ int prev_borderpx = selmon->borderpx;
+
+ if (arg->i == 0)
+ selmon->borderpx = borderpx;
+ else if (selmon->borderpx + arg->i < 0)
+ selmon->borderpx = 0;
+ else
+ selmon->borderpx += arg->i;
+
+ #if BAR_BORDER_PATCH
+ for (bar = selmon->bar; bar; bar = bar->next) {
+ bar->bh = bar->bh - 2 * bar->borderpx + 2 * selmon->borderpx;
+ bar->borderpx = selmon->borderpx;
+ }
+ updatebarpos(selmon);
+ for (bar = selmon->bar; bar; bar = bar->next)
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
+ #endif // BAR_BORDER_PATCH
+
+ for (c = selmon->clients; c; c = c->next)
+ {
+ if (c->bw + arg->i < 0)
+ c->bw = 0;
+ else
+ c->bw = selmon->borderpx;
+
+ if (c->isfloating || !selmon->lt[selmon->sellt]->arrange)
+ {
+ if (arg->i != 0 && prev_borderpx + arg->i >= 0)
+ resize(c, c->x, c->y, c->w-(arg->i*2), c->h-(arg->i*2), 0);
+ else if (arg->i != 0)
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ else if (prev_borderpx > borderpx)
+ resize(c, c->x, c->y, c->w + 2*(prev_borderpx - borderpx), c->h + 2*(prev_borderpx - borderpx), 0);
+ else if (prev_borderpx < borderpx)
+ resize(c, c->x, c->y, c->w - 2*(borderpx - prev_borderpx), c->h - 2*(borderpx - prev_borderpx), 0);
+ }
+ }
+ arrange(selmon);
+}
+
diff --git a/patch/setborderpx.h b/patch/setborderpx.h
new file mode 100644
index 0000000..a92ae0b
--- /dev/null
+++ b/patch/setborderpx.h
@@ -0,0 +1,2 @@
+static void setborderpx(const Arg *arg);
+
diff --git a/patch/shiftview.c b/patch/shiftview.c
new file mode 100644
index 0000000..423d74b
--- /dev/null
+++ b/patch/shiftview.c
@@ -0,0 +1,19 @@
+void
+shiftview(const Arg *arg)
+{
+ Arg shifted;
+ #if SCRATCHPADS_PATCH
+ unsigned int seltagset = selmon->tagset[selmon->seltags] & ~SPTAGMASK;
+ #else
+ unsigned int seltagset = selmon->tagset[selmon->seltags];
+ #endif // SCRATCHPADS_PATCH
+ if (arg->i > 0) // left circular shift
+ shifted.ui = (seltagset << arg->i)
+ | (seltagset >> (NUMTAGS - arg->i));
+ else // right circular shift
+ shifted.ui = seltagset >> -arg->i
+ | seltagset << (NUMTAGS + arg->i);
+
+ view(&shifted);
+}
+
diff --git a/patch/shiftview.h b/patch/shiftview.h
new file mode 100644
index 0000000..1d7fd1f
--- /dev/null
+++ b/patch/shiftview.h
@@ -0,0 +1,2 @@
+static void shiftview(const Arg *arg);
+
diff --git a/patch/shiftviewclients.c b/patch/shiftviewclients.c
new file mode 100644
index 0000000..1bf9de8
--- /dev/null
+++ b/patch/shiftviewclients.c
@@ -0,0 +1,43 @@
+void
+shiftviewclients(const Arg *arg)
+{
+ Arg shifted;
+ Client *c;
+ unsigned int tagmask = 0;
+
+ for (c = selmon->clients; c; c = c->next)
+ #if SCRATCHPADS_PATCH
+ if (!(c->tags & SPTAGMASK))
+ tagmask = tagmask | c->tags;
+ #elif SCRATCHPAD_ALT_1_PATCH
+ if (!(c->tags & SCRATCHPAD_MASK))
+ tagmask = tagmask | c->tags;
+ #else
+ tagmask = tagmask | c->tags;
+ #endif // SCRATCHPADS_PATCH
+
+ #if SCRATCHPADS_PATCH
+ shifted.ui = selmon->tagset[selmon->seltags] & ~SPTAGMASK;
+ #else
+ shifted.ui = selmon->tagset[selmon->seltags];
+ #endif // SCRATCHPADS_PATCH
+ if (arg->i > 0) // left circular shift
+ do {
+ shifted.ui = (shifted.ui << arg->i)
+ | (shifted.ui >> (NUMTAGS - arg->i));
+ #if SCRATCHPADS_PATCH
+ shifted.ui &= ~SPTAGMASK;
+ #endif // SCRATCHPADS_PATCH
+ } while (tagmask && !(shifted.ui & tagmask));
+ else // right circular shift
+ do {
+ shifted.ui = (shifted.ui >> (- arg->i)
+ | shifted.ui << (NUMTAGS + arg->i));
+ #if SCRATCHPADS_PATCH
+ shifted.ui &= ~SPTAGMASK;
+ #endif // SCRATCHPADS_PATCH
+ } while (tagmask && !(shifted.ui & tagmask));
+
+ view(&shifted);
+}
+
diff --git a/patch/shiftviewclients.h b/patch/shiftviewclients.h
new file mode 100644
index 0000000..49aeb51
--- /dev/null
+++ b/patch/shiftviewclients.h
@@ -0,0 +1,2 @@
+static void shiftviewclients(const Arg *arg);
+
diff --git a/patch/sizehints_ruled.c b/patch/sizehints_ruled.c
new file mode 100644
index 0000000..99c7e62
--- /dev/null
+++ b/patch/sizehints_ruled.c
@@ -0,0 +1,25 @@
+void
+checkfloatingrules(Client *c)
+{
+ const char *class, *instance;
+ 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;
+
+ 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->instance || strstr(instance, r->instance)))
+ 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/sortscreens.c b/patch/sortscreens.c
new file mode 100644
index 0000000..538e2c1
--- /dev/null
+++ b/patch/sortscreens.c
@@ -0,0 +1,16 @@
+void
+sortscreens(XineramaScreenInfo *screens, int n)
+{
+ int i, j;
+ XineramaScreenInfo *screen = ecalloc(1, sizeof(XineramaScreenInfo));
+
+ for (i = 0; i < n; i++)
+ for (j = i + 1; j < n; j++)
+ if (RIGHTOF(screens[i], screens[j])) {
+ memcpy(&screen[0], &screens[i], sizeof(XineramaScreenInfo));
+ memcpy(&screens[i], &screens[j], sizeof(XineramaScreenInfo));
+ memcpy(&screens[j], &screen[0], sizeof(XineramaScreenInfo));
+ }
+ XFree(screen);
+}
+
diff --git a/patch/sortscreens.h b/patch/sortscreens.h
new file mode 100644
index 0000000..82915f4
--- /dev/null
+++ b/patch/sortscreens.h
@@ -0,0 +1,4 @@
+#define RIGHTOF(a,b) (a.y_org > b.y_org) || ((a.y_org == b.y_org) && (a.x_org > b.x_org))
+
+static void sortscreens(XineramaScreenInfo *screens, int n);
+
diff --git a/patch/stacker.c b/patch/stacker.c
new file mode 100644
index 0000000..ed8b76b
--- /dev/null
+++ b/patch/stacker.c
@@ -0,0 +1,113 @@
+void
+focusstack(const Arg *arg)
+{
+ int i = stackpos(arg);
+ Client *c, *p;
+
+ if (i < 0)
+ return;
+
+ #if LOSEFULLSCREEN_PATCH
+ if (!selmon->sel)
+ return;
+ #elif FAKEFULLSCREEN_CLIENT_PATCH
+ if (!selmon->sel || (selmon->sel->isfullscreen && !selmon->sel->fakefullscreen))
+ return;
+ #else
+ if (!selmon->sel || selmon->sel->isfullscreen)
+ return;
+ #endif // LOSEFULLSCREEN_PATCH
+
+ #if BAR_WINTITLEACTIONS_PATCH
+ for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c) || HIDDEN(c));
+ i -= (ISVISIBLE(c) && !HIDDEN(c) ? 1 : 0), p = c, c = c->next);
+ #else
+ for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c));
+ i -= (ISVISIBLE(c) ? 1 : 0), p = c, c = c->next);
+ #endif // BAR_WINTITLEACTIONS_PATCH
+ 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 BAR_WINTITLEACTIONS_PATCH
+ if (!(i -= (ISVISIBLE(c) && !HIDDEN(c) && c != sel)))
+ #else
+ if (!(i -= (ISVISIBLE(c) && c != sel)))
+ #endif // BAR_WINTITLEACTIONS_PATCH
+ 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 BAR_WINTITLEACTIONS_PATCH
+ if (arg->i == PREVSEL) {
+ for (l = selmon->stack; l && (!ISVISIBLE(l) || HIDDEN(l) || l == selmon->sel); l = l->snext);
+ if (!l)
+ return -1;
+ for (i = 0, c = selmon->clients; c != l; i += (ISVISIBLE(c) && !HIDDEN(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) && !HIDDEN(c) ? 1 : 0), c = c->next);
+ for (n = i; c; n += (ISVISIBLE(c) && !HIDDEN(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) && !HIDDEN(c) ? 1 : 0), c = c->next);
+ return MAX(i + arg->i, 0);
+ }
+ else
+ return arg->i;
+ #else // !BAR_WINTITLEACTIONS_PATCH
+ 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;
+ #endif // BAR_WINTITLEACTIONS_PATCH
+}
+
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/sticky.c b/patch/sticky.c
new file mode 100644
index 0000000..420c3e0
--- /dev/null
+++ b/patch/sticky.c
@@ -0,0 +1,9 @@
+void
+togglesticky(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ selmon->sel->issticky = !selmon->sel->issticky;
+ arrange(selmon);
+}
+
diff --git a/patch/sticky.h b/patch/sticky.h
new file mode 100644
index 0000000..277bb34
--- /dev/null
+++ b/patch/sticky.h
@@ -0,0 +1,2 @@
+static void togglesticky(const Arg *arg);
+
diff --git a/patch/swallow.c b/patch/swallow.c
new file mode 100644
index 0000000..824ca83
--- /dev/null
+++ b/patch/swallow.c
@@ -0,0 +1,206 @@
+#include <X11/Xlib-xcb.h>
+#include <xcb/res.h>
+#ifdef __OpenBSD__
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif /* __OpenBSD__ */
+
+static int scanner;
+static xcb_connection_t *xcon;
+
+int
+swallow(Client *p, Client *c)
+{
+ Client *s;
+
+ if (c->noswallow > 0 || c->isterminal)
+ return 0;
+ if (c->noswallow < 0 && !swallowfloating && c->isfloating)
+ return 0;
+
+ XMapWindow(dpy, c->win);
+
+ detach(c);
+ detachstack(c);
+
+ setclientstate(c, WithdrawnState);
+ XUnmapWindow(dpy, p->win);
+
+ p->swallowing = c;
+ c->mon = p->mon;
+
+ Window w = p->win;
+ p->win = c->win;
+ c->win = w;
+
+ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(p->win), 1);
+
+ updatetitle(p);
+ s = scanner ? c : p;
+ #if BAR_EWMHTAGS_PATCH
+ setfloatinghint(s);
+ #endif // BAR_EWMHTAGS_PATCH
+ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h);
+ arrange(p->mon);
+ configure(p);
+ updateclientlist();
+
+ return 1;
+}
+
+void
+unswallow(Client *c)
+{
+ c->win = c->swallowing->win;
+
+ free(c->swallowing);
+ c->swallowing = NULL;
+
+ XDeleteProperty(dpy, c->win, netatom[NetClientList]);
+
+ /* unfullscreen the client */
+ setfullscreen(c, 0);
+ updatetitle(c);
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ #if BAR_EWMHTAGS_PATCH
+ setfloatinghint(c);
+ #endif // BAR_EWMHTAGS_PATCH
+ setclientstate(c, NormalState);
+ focus(NULL);
+ arrange(c->mon);
+}
+
+pid_t
+winpid(Window w)
+{
+ pid_t result = 0;
+
+ #ifdef __linux__
+ xcb_res_client_id_spec_t spec = {0};
+ spec.client = w;
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
+
+ xcb_generic_error_t *e = NULL;
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
+
+ if (!r)
+ return (pid_t)0;
+
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
+ spec = i.data->spec;
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
+ result = *t;
+ break;
+ }
+ }
+
+ free(r);
+
+ if (result == (pid_t)-1)
+ result = 0;
+
+ #endif /* __linux__ */
+ #ifdef __OpenBSD__
+ Atom type;
+ int format;
+ unsigned long len, bytes;
+ unsigned char *prop;
+ pid_t ret;
+
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
+ return 0;
+
+ ret = *(pid_t*)prop;
+ XFree(prop);
+ result = ret;
+ #endif /* __OpenBSD__ */
+
+ return result;
+}
+
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+
+#ifdef __linux__
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return (pid_t)0;
+
+ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1)
+ v = (pid_t)0;
+ fclose(f);
+#endif /* __linux__ */
+#ifdef __OpenBSD__
+ int n;
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
+ if (!kd)
+ return 0;
+
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
+ v = kp->p_ppid;
+#endif /* __OpenBSD__ */
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(const Client *w)
+{
+ Client *c;
+ Monitor *m;
+
+ if (!w->pid || w->isterminal)
+ return NULL;
+
+ c = selmon->sel;
+ if (c && c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+Client *
+swallowingclient(Window w)
+{
+ Client *c;
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->swallowing && c->swallowing->win == w)
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/patch/swallow.h b/patch/swallow.h
new file mode 100644
index 0000000..529fea9
--- /dev/null
+++ b/patch/swallow.h
@@ -0,0 +1,8 @@
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static int swallow(Client *p, Client *c);
+static Client *swallowingclient(Window w);
+static Client *termforwin(const Client *c);
+static void unswallow(Client *c);
+static pid_t winpid(Window w);
+
diff --git a/patch/swapfocus.c b/patch/swapfocus.c
new file mode 100644
index 0000000..ec85c2e
--- /dev/null
+++ b/patch/swapfocus.c
@@ -0,0 +1,22 @@
+void
+swapfocus(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ if (selmon->pertag->prevclient[selmon->pertag->curtag] != NULL
+ && ISVISIBLE(selmon->pertag->prevclient[selmon->pertag->curtag])) {
+ focus(selmon->pertag->prevclient[selmon->pertag->curtag]);
+ restack(selmon->pertag->prevclient[selmon->pertag->curtag]->mon);
+ }
+ else {
+ Client *c = NULL;
+ for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
+ if (!c)
+ for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+ if (c) {
+ focus(c);
+ restack(selmon);
+ }
+ }
+}
+
diff --git a/patch/swapfocus.h b/patch/swapfocus.h
new file mode 100644
index 0000000..e547d2f
--- /dev/null
+++ b/patch/swapfocus.h
@@ -0,0 +1,2 @@
+static void swapfocus(const Arg *arg);
+
diff --git a/patch/swaptags.c b/patch/swaptags.c
new file mode 100644
index 0000000..d6a72d7
--- /dev/null
+++ b/patch/swaptags.c
@@ -0,0 +1,23 @@
+void
+swaptags(const Arg *arg)
+{
+ unsigned int newtag = arg->ui & TAGMASK;
+ unsigned int curtag = selmon->tagset[selmon->seltags];
+
+ if (newtag == curtag || !curtag || (curtag & (curtag-1)))
+ return;
+
+ for (Client *c = selmon->clients; c != NULL; c = c->next) {
+ if ((c->tags & newtag) || (c->tags & curtag))
+ c->tags ^= curtag ^ newtag;
+
+ if (!c->tags)
+ c->tags = newtag;
+ }
+
+ selmon->tagset[selmon->seltags] = newtag;
+
+ focus(NULL);
+ arrange(selmon);
+}
+
diff --git a/patch/swaptags.h b/patch/swaptags.h
new file mode 100644
index 0000000..fdadf3a
--- /dev/null
+++ b/patch/swaptags.h
@@ -0,0 +1,2 @@
+static void swaptags(const Arg *arg);
+
diff --git a/patch/switchcol.c b/patch/switchcol.c
new file mode 100644
index 0000000..6caf8ba
--- /dev/null
+++ b/patch/switchcol.c
@@ -0,0 +1,29 @@
+void
+switchcol(const Arg *arg)
+{
+ Client *c, *t;
+ int col = 0;
+ int i;
+
+ if (!selmon->sel)
+ return;
+ for (i = 0, c = nexttiled(selmon->clients); c ;
+ c = nexttiled(c->next), i++) {
+ if (c == selmon->sel)
+ col = (i + 1) > selmon->nmaster;
+ }
+ if (i <= selmon->nmaster)
+ return;
+ for (c = selmon->stack; c; c = c->snext) {
+ if (!ISVISIBLE(c))
+ continue;
+ for (i = 0, t = nexttiled(selmon->clients); t && t != c;
+ t = nexttiled(t->next), i++);
+ if (t && (i + 1 > selmon->nmaster) != col) {
+ focus(c);
+ restack(selmon);
+ break;
+ }
+ }
+}
+
diff --git a/patch/switchcol.h b/patch/switchcol.h
new file mode 100644
index 0000000..8c7cded
--- /dev/null
+++ b/patch/switchcol.h
@@ -0,0 +1,2 @@
+static void switchcol(const Arg *arg);
+
diff --git a/patch/tab.c b/patch/tab.c
new file mode 100644
index 0000000..30a14d1
--- /dev/null
+++ b/patch/tab.c
@@ -0,0 +1,133 @@
+static int th = 0; /* tab bar geometry */
+
+void
+drawtabs(void)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next)
+ drawtab(m);
+}
+
+static int
+cmpint(const void *p1, const void *p2)
+{
+ /* The actual arguments to this function are "pointers to
+ pointers to char", but strcmp(3) arguments are "pointers
+ to char", hence the following cast plus dereference */
+ return *((int*) p1) > * (int*) p2;
+}
+
+void
+drawtab(Monitor *m)
+{
+ Client *c;
+ int i;
+ int itag = -1;
+ char view_info[50];
+ int view_info_w = 0;
+ int sorted_label_widths[MAXTABS];
+ int tot_width;
+ int maxsize = bh;
+ int x = 0;
+ int w = 0;
+
+ // view_info: indicate the tag which is displayed in the view
+ for (i = 0; i < NUMTAGS; ++i) {
+ if ((selmon->tagset[selmon->seltags] >> i) & 1) {
+ if (itag >=0) { // more than one tag selected
+ itag = -1;
+ break;
+ }
+ itag = i;
+ }
+ }
+
+ if (0 <= itag && itag < NUMTAGS) {
+ snprintf(view_info, sizeof view_info, "[%s]", tagicon(m, itag));
+ } else {
+ strncpy(view_info, "[...]", sizeof view_info);
+ }
+ view_info[sizeof(view_info) - 1 ] = 0;
+ view_info_w = TEXTW(view_info);
+ tot_width = view_info_w;
+
+ /* Calculates number of labels and their width */
+ m->ntabs = 0;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ m->tab_widths[m->ntabs] = TEXTW(c->name);
+ tot_width += m->tab_widths[m->ntabs];
+ ++m->ntabs;
+ if (m->ntabs >= MAXTABS)
+ break;
+ }
+
+ if (tot_width > m->ww) { // not enough space to display the labels, they need to be truncated
+ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
+ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
+ tot_width = view_info_w;
+ for (i = 0; i < m->ntabs; ++i) {
+ if (tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
+ break;
+ tot_width += sorted_label_widths[i];
+ }
+ maxsize = (m->ww - tot_width) / (m->ntabs - i);
+ } else {
+ maxsize = m->ww;
+ }
+ i = 0;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ if (i >= m->ntabs)
+ break;
+ if (m->tab_widths[i] > maxsize)
+ m->tab_widths[i] = maxsize;
+ w = m->tab_widths[i];
+ drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, th, 0, c->name, 0, False);
+ x += w;
+ ++i;
+ }
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+
+ /* cleans interspace between window names and current viewed tag label */
+ w = m->ww - view_info_w - x;
+ drw_text(drw, x, 0, w, th, 0, "", 0, False);
+
+ /* view info */
+ x += w;
+ w = view_info_w;
+ drw_text(drw, x, 0, w, th, 0, view_info, 0, False);
+
+ drw_map(drw, m->tabwin, 0, 0, m->ww, th);
+}
+
+void
+focuswin(const Arg* arg)
+{
+ int iwin = arg->i;
+ Client* c = NULL;
+ for (c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next) {
+ if (ISVISIBLE(c) && !HIDDEN(c))
+ --iwin;
+ };
+ if (c) {
+ focus(c);
+ restack(selmon);
+ }
+}
+
+void
+tabmode(const Arg *arg)
+{
+ if (arg && arg->i >= 0)
+ selmon->showtab = arg->ui % showtab_nmodes;
+ else
+ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
+ arrange(selmon);
+}
+
diff --git a/patch/tab.h b/patch/tab.h
new file mode 100644
index 0000000..44161d7
--- /dev/null
+++ b/patch/tab.h
@@ -0,0 +1,5 @@
+static void drawtab(Monitor *m);
+static void drawtabs(void);
+static void focuswin(const Arg* arg);
+static void tabmode(const Arg *arg);
+
diff --git a/patch/tagall.c b/patch/tagall.c
new file mode 100644
index 0000000..7abe7cc
--- /dev/null
+++ b/patch/tagall.c
@@ -0,0 +1,26 @@
+void
+tagall(const Arg *arg)
+{
+ if (!selmon->clients)
+ return;
+ /* if parameter starts with F, just move floating windows */
+ int floating_only = (char *)arg->v && ((char *)arg->v)[0] == 'F' ? 1 : 0;
+ int tag = (char *)arg->v ? atoi(((char *)arg->v) + floating_only) : 0;
+ int j;
+ Client* c;
+ if (tag >= 0 && tag < NUMTAGS)
+ for (c = selmon->clients; c; c = c->next)
+ {
+ if (!floating_only || c->isfloating)
+ for (j = 0; j < NUMTAGS; j++)
+ {
+ if (c->tags & 1 << j && selmon->tagset[selmon->seltags] & 1 << j)
+ {
+ c->tags = c->tags ^ (1 << j & TAGMASK);
+ c->tags = c->tags | 1 << (tag-1);
+ }
+ }
+ }
+ arrange(selmon);
+}
+
diff --git a/patch/tagall.h b/patch/tagall.h
new file mode 100644
index 0000000..f36c9f8
--- /dev/null
+++ b/patch/tagall.h
@@ -0,0 +1,2 @@
+static void tagall(const Arg *arg);
+
diff --git a/patch/tagallmon.c b/patch/tagallmon.c
new file mode 100644
index 0000000..d6b879a
--- /dev/null
+++ b/patch/tagallmon.c
@@ -0,0 +1,49 @@
+void
+tagallmon(const Arg *arg)
+{
+ Monitor *m;
+ Client *c, *last, *slast, *next;
+
+ if (!mons->next)
+ return;
+
+ m = dirtomon(arg->i);
+ for (last = m->clients; last && last->next; last = last->next);
+ for (slast = m->stack; slast && slast->snext; slast = slast->snext);
+
+ for (c = selmon->clients; c; c = next) {
+ next = c->next;
+ if (!ISVISIBLE(c))
+ continue;
+ unfocus(c, 1, NULL);
+ detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ c->next = NULL;
+ c->snext = NULL;
+ if (last)
+ last = last->next = c;
+ else
+ m->clients = last = c;
+ if (slast)
+ slast = slast->snext = c;
+ else
+ m->stack = slast = c;
+ if (c->isfullscreen) {
+ #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
+ if (c->fakefullscreen != 1) {
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ }
+ #elif !FAKEFULLSCREEN_PATCH
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+ }
+ }
+
+ focus(NULL);
+ arrange(NULL);
+}
+
diff --git a/patch/tagallmon.h b/patch/tagallmon.h
new file mode 100644
index 0000000..9abf535
--- /dev/null
+++ b/patch/tagallmon.h
@@ -0,0 +1,2 @@
+static void tagallmon(const Arg *arg);
+
diff --git a/patch/tagothermonitor.c b/patch/tagothermonitor.c
new file mode 100644
index 0000000..d12f6ff
--- /dev/null
+++ b/patch/tagothermonitor.c
@@ -0,0 +1,44 @@
+#if IPC_PATCH || DWMC_PATCH
+void
+tagnextmonex(const Arg *arg)
+{
+ tagnextmon(&((Arg) { .ui = 1 << arg->ui }));
+}
+
+void
+tagprevmonex(const Arg *arg)
+{
+ tagprevmon(&((Arg) { .ui = 1 << arg->ui }));
+}
+#endif // IPC_PATCH | DWMC_PATCH
+
+void
+tagnextmon(const Arg *arg)
+{
+ tagothermon(arg, 1);
+}
+
+void
+tagprevmon(const Arg *arg)
+{
+ tagothermon(arg, -1);
+}
+
+void
+tagothermon(const Arg *arg, int dir)
+{
+ Client *sel;
+ Monitor *newmon;
+
+ if (!selmon->sel || !mons->next)
+ return;
+ sel = selmon->sel;
+ newmon = dirtomon(dir);
+ sendmon(sel, newmon);
+ if (arg->ui & TAGMASK) {
+ sel->tags = arg->ui & TAGMASK;
+ focus(NULL);
+ arrange(newmon);
+ }
+}
+
diff --git a/patch/tagothermonitor.h b/patch/tagothermonitor.h
new file mode 100644
index 0000000..8ebe975
--- /dev/null
+++ b/patch/tagothermonitor.h
@@ -0,0 +1,9 @@
+#if IPC_PATCH || DWMC_PATCH
+static void tagnextmonex(const Arg *arg);
+static void tagprevmonex(const Arg *arg);
+#endif // IPC_PATCH | DWMC_PATCH
+
+static void tagnextmon(const Arg *arg);
+static void tagprevmon(const Arg *arg);
+static void tagothermon(const Arg *arg, int dir);
+
diff --git a/patch/tagswapmon.c b/patch/tagswapmon.c
new file mode 100644
index 0000000..4719b8c
--- /dev/null
+++ b/patch/tagswapmon.c
@@ -0,0 +1,75 @@
+void
+tagswapmon(const Arg *arg)
+{
+ Monitor *m;
+ Client *c, *sc = NULL, *mc = NULL, *next;
+
+ if (!mons->next)
+ return;
+
+ m = dirtomon(arg->i);
+
+ for (c = selmon->clients; c; c = next) {
+ next = c->next;
+ if (!ISVISIBLE(c))
+ continue;
+ unfocus(c, 1, NULL);
+ detach(c);
+ detachstack(c);
+ c->next = sc;
+ sc = c;
+ }
+
+ for (c = m->clients; c; c = next) {
+ next = c->next;
+ if (!ISVISIBLE(c))
+ continue;
+ unfocus(c, 1, NULL);
+ detach(c);
+ detachstack(c);
+ c->next = mc;
+ mc = c;
+ }
+
+ for (c = sc; c; c = next) {
+ next = c->next;
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ attach(c);
+ attachstack(c);
+ if (c->isfullscreen) {
+ #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
+ if (c->fakefullscreen != 1) {
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ }
+ #elif !FAKEFULLSCREEN_PATCH
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+ }
+ }
+
+ for (c = mc; c; c = next) {
+ next = c->next;
+ c->mon = selmon;
+ c->tags = selmon->tagset[selmon->seltags]; /* assign tags of target monitor */
+ attach(c);
+ attachstack(c);
+ if (c->isfullscreen) {
+ #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
+ if (c->fakefullscreen != 1) {
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ }
+ #elif !FAKEFULLSCREEN_PATCH
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+ }
+ }
+
+ focus(NULL);
+ arrange(NULL);
+}
+
diff --git a/patch/tagswapmon.h b/patch/tagswapmon.h
new file mode 100644
index 0000000..949f591
--- /dev/null
+++ b/patch/tagswapmon.h
@@ -0,0 +1,2 @@
+static void tagswapmon(const Arg *arg);
+
diff --git a/patch/tapresize.c b/patch/tapresize.c
new file mode 100644
index 0000000..c236b5d
--- /dev/null
+++ b/patch/tapresize.c
@@ -0,0 +1,39 @@
+void
+resizemousescroll(const Arg *arg)
+{
+ int nw, nh;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+ int dw = *((int*)arg->v + 1);
+ int dh = *(int*)arg->v;
+
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ return;
+ nw = MAX(c->w + dw, 1);
+ nh = MAX(c->h + dh, 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))
+ togglefloating(NULL);
+ }
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+ resize(c, c->x, c->y, nw, nh, 1);
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ 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);
+ }
+}
+
diff --git a/patch/tapresize.h b/patch/tapresize.h
new file mode 100644
index 0000000..fe6d227
--- /dev/null
+++ b/patch/tapresize.h
@@ -0,0 +1,2 @@
+static void resizemousescroll(const Arg *arg);
+
diff --git a/patch/togglefullscreen.c b/patch/togglefullscreen.c
new file mode 100644
index 0000000..18857f5
--- /dev/null
+++ b/patch/togglefullscreen.c
@@ -0,0 +1,18 @@
+void
+togglefullscreen(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+
+ #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
+ c->fakefullscreen = 2;
+ setfullscreen(c, 1);
+ } else
+ setfullscreen(c, !c->isfullscreen);
+ #else
+ setfullscreen(c, !c->isfullscreen);
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
+}
+
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/transfer.c b/patch/transfer.c
new file mode 100644
index 0000000..ce64319
--- /dev/null
+++ b/patch/transfer.c
@@ -0,0 +1,34 @@
+void
+transfer(const Arg *arg)
+{
+ Client *c, *mtail = selmon->clients, *stail = NULL, *insertafter;
+ int transfertostack = 0, i, nmasterclients;
+
+ for (i = 0, c = selmon->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || c->isfloating) continue;
+ if (selmon->sel == c) { transfertostack = i < selmon->nmaster && selmon->nmaster != 0; }
+ if (i < selmon->nmaster) { nmasterclients++; mtail = c; }
+ stail = c;
+ i++;
+ }
+ if (!selmon->sel || selmon->sel->isfloating || i == 0) {
+ return;
+ } else if (transfertostack) {
+ selmon->nmaster = MIN(i, selmon->nmaster) - 1;
+ insertafter = stail;
+ } else {
+ selmon->nmaster = selmon->nmaster + 1;
+ insertafter = mtail;
+ }
+ if (insertafter != selmon->sel) {
+ detach(selmon->sel);
+ if (selmon->nmaster == 1 && !transfertostack) {
+ attach(selmon->sel); // Head prepend case
+ } else {
+ selmon->sel->next = insertafter->next;
+ insertafter->next = selmon->sel;
+ }
+ }
+ arrange(selmon);
+}
+
diff --git a/patch/transfer.h b/patch/transfer.h
new file mode 100644
index 0000000..e887dae
--- /dev/null
+++ b/patch/transfer.h
@@ -0,0 +1,2 @@
+static void transfer(const Arg *arg);
+
diff --git a/patch/transferall.c b/patch/transferall.c
new file mode 100644
index 0000000..ee823b1
--- /dev/null
+++ b/patch/transferall.c
@@ -0,0 +1,26 @@
+void
+transferall(const Arg *arg)
+{
+ Client *c, *n = selmon->clients, *attachfrom = NULL;
+ int i = 0, nstackclients = 0;
+ while (n) {
+ c = n;
+ n = c->next;
+ if (!ISVISIBLE(c) || c->isfloating) continue;
+ if (i >= selmon->nmaster) {
+ detach(c);
+ if (!attachfrom) {
+ attach(c);
+ } else {
+ c->next = attachfrom->next;
+ attachfrom->next = c;
+ }
+ attachfrom = c;
+ nstackclients++;
+ }
+ i++;
+ }
+ selmon->nmaster = nstackclients;
+ arrange(selmon);
+}
+
diff --git a/patch/transferall.h b/patch/transferall.h
new file mode 100644
index 0000000..a424ec8
--- /dev/null
+++ b/patch/transferall.h
@@ -0,0 +1,2 @@
+static void transferall(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/patch/vanitygaps.c b/patch/vanitygaps.c
new file mode 100644
index 0000000..be2ef08
--- /dev/null
+++ b/patch/vanitygaps.c
@@ -0,0 +1,199 @@
+/* Settings */
+#if !PERTAG_VANITYGAPS_PATCH
+static int enablegaps = 1;
+#endif // PERTAG_VANITYGAPS_PATCH
+
+static void
+setgaps(int oh, int ov, int ih, int iv)
+{
+ if (oh < 0) oh = 0;
+ if (ov < 0) ov = 0;
+ if (ih < 0) ih = 0;
+ if (iv < 0) iv = 0;
+
+ selmon->gappoh = oh;
+ selmon->gappov = ov;
+ selmon->gappih = ih;
+ selmon->gappiv = iv;
+
+ #if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
+ selmon->pertag->gaps[selmon->pertag->curtag] =
+ ((oh & 0xFF) << 0) | ((ov & 0xFF) << 8) | ((ih & 0xFF) << 16) | ((iv & 0xFF) << 24);
+ #endif // PERTAG_VANITYGAPS_PATCH
+
+ arrange(selmon);
+}
+
+#if IPC_PATCH || DWMC_PATCH
+/* External function that takes one integer and splits it
+ * into four gap values:
+ * - outer horizontal (oh)
+ * - outer vertical (ov)
+ * - inner horizontal (ih)
+ * - inner vertical (iv)
+ *
+ * Each value is represented as one byte with the uppermost
+ * bit of each byte indicating whether or not to keep the
+ * current value.
+ *
+ * Example:
+ *
+ * 10000000 10000000 00001111 00001111
+ * | | | |
+ * + keep oh + keep ov + ih 15px + iv 15px
+ *
+ * This gives an int of:
+ * 10000000100000000000111100001111 = 2155876111
+ *
+ * Thus this command should set inner gaps to 15:
+ * xsetroot -name "fsignal:setgaps i 2155876111"
+ */
+static void
+setgapsex(const Arg *arg)
+{
+ int oh = selmon->gappoh;
+ int ov = selmon->gappov;
+ int ih = selmon->gappih;
+ int iv = selmon->gappiv;
+
+ if (!(arg->i & (1 << 31)))
+ oh = (arg->i & 0x7f000000) >> 24;
+ if (!(arg->i & (1 << 23)))
+ ov = (arg->i & 0x7f0000) >> 16;
+ if (!(arg->i & (1 << 15)))
+ ih = (arg->i & 0x7f00) >> 8;
+ if (!(arg->i & (1 << 7)))
+ iv = (arg->i & 0x7f);
+
+ /* Auto enable gaps if disabled */
+ #if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
+ if (!selmon->pertag->enablegaps[selmon->pertag->curtag])
+ selmon->pertag->enablegaps[selmon->pertag->curtag] = 1;
+ #else
+ if (!enablegaps)
+ enablegaps = 1;
+ #endif // PERTAG_VANITYGAPS_PATCH
+
+ setgaps(oh, ov, ih, iv);
+}
+#endif // IPC_PATCH | DWMC_PATCH
+
+static void
+togglegaps(const Arg *arg)
+{
+ #if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
+ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag];
+ #else
+ enablegaps = !enablegaps;
+ #endif // PERTAG_VANITYGAPS_PATCH
+ arrange(NULL);
+}
+
+static void
+defaultgaps(const Arg *arg)
+{
+ setgaps(gappoh, gappov, gappih, gappiv);
+}
+
+static void
+incrgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov + arg->i,
+ selmon->gappih + arg->i,
+ selmon->gappiv + arg->i
+ );
+}
+
+static void
+incrigaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih + arg->i,
+ selmon->gappiv + arg->i
+ );
+}
+
+static void
+incrogaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov + arg->i,
+ selmon->gappih,
+ selmon->gappiv
+ );
+}
+
+static void
+incrohgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov,
+ selmon->gappih,
+ selmon->gappiv
+ );
+}
+
+static void
+incrovgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov + arg->i,
+ selmon->gappih,
+ selmon->gappiv
+ );
+}
+
+static void
+incrihgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih + arg->i,
+ selmon->gappiv
+ );
+}
+
+static void
+incrivgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih,
+ selmon->gappiv + arg->i
+ );
+}
+
+#if DRAGMFACT_PATCH || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT || GAPPLESSGRID_LAYOUT || NROWGRID_LAYOUT || HORIZGRID_LAYOUT || BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || GRIDMODE_LAYOUT || FLEXTILE_DELUXE_LAYOUT || TILE_LAYOUT || (VANITYGAPS_MONOCLE_PATCH && MONOCLE_LAYOUT)
+static void
+getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
+{
+ unsigned int n, oe, ie;
+ #if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
+ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag];
+ #else
+ oe = ie = enablegaps;
+ #endif // PERTAG_VANITYGAPS_PATCH
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 1) {
+ oe *= smartgaps_fact; // outer gaps disabled or multiplied when only one client
+ }
+
+ *oh = m->gappoh*oe; // outer horizontal gap
+ *ov = m->gappov*oe; // outer vertical gap
+ *ih = m->gappih*ie; // inner horizontal gap
+ *iv = m->gappiv*ie; // inner vertical gap
+ *nc = n; // number of clients
+}
+#endif
+
diff --git a/patch/vanitygaps.h b/patch/vanitygaps.h
new file mode 100644
index 0000000..b8f2109
--- /dev/null
+++ b/patch/vanitygaps.h
@@ -0,0 +1,20 @@
+/* Key binding functions */
+static void defaultgaps(const Arg *arg);
+static void incrgaps(const Arg *arg);
+static void incrigaps(const Arg *arg);
+static void incrogaps(const Arg *arg);
+static void incrohgaps(const Arg *arg);
+static void incrovgaps(const Arg *arg);
+static void incrihgaps(const Arg *arg);
+static void incrivgaps(const Arg *arg);
+static void togglegaps(const Arg *arg);
+
+/* Internals */
+#if DRAGMFACT_PATCH || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT || GAPPLESSGRID_LAYOUT || NROWGRID_LAYOUT || HORIZGRID_LAYOUT || BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || GRIDMODE_LAYOUT || FLEXTILE_DELUXE_LAYOUT || TILE_LAYOUT || (VANITYGAPS_MONOCLE_PATCH && MONOCLE_LAYOUT)
+static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
+#endif
+static void setgaps(int oh, int ov, int ih, int iv);
+#if IPC_PATCH || DWMC_PATCH
+static void setgapsex(const Arg *arg);
+#endif // IPC_PATCH | DWMC_PATCH
+
diff --git a/patch/warp.c b/patch/warp.c
new file mode 100644
index 0000000..16f1605
--- /dev/null
+++ b/patch/warp.c
@@ -0,0 +1,38 @@
+void
+warp(const Client *c)
+{
+ Monitor *m;
+ Bar *bar;
+ int x, y;
+
+ if (ignore_warp)
+ return;
+
+ if (!c) {
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2);
+ return;
+ }
+
+ if (!getrootptr(&x, &y))
+ return;
+
+ if (!force_warp &&
+ (x > c->x - c->bw &&
+ y > c->y - c->bw &&
+ x < c->x + c->w + c->bw*2 &&
+ y < c->y + c->h + c->bw*2))
+ return;
+
+ force_warp = 0;
+
+ for (m = mons; m; m = m->next)
+ for (bar = m->bar; bar; bar = bar->next)
+ if (x > bar->bx &&
+ x < bar->bx + bar->bw &&
+ y > bar->by &&
+ y < bar->by + bar->bh)
+ return;
+
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2);
+}
+
diff --git a/patch/warp.h b/patch/warp.h
new file mode 100644
index 0000000..d79d75f
--- /dev/null
+++ b/patch/warp.h
@@ -0,0 +1,2 @@
+static void warp(const Client *c);
+
diff --git a/patch/winview.c b/patch/winview.c
new file mode 100644
index 0000000..f54c20c
--- /dev/null
+++ b/patch/winview.c
@@ -0,0 +1,21 @@
+/* Selects for the view of the focused window. The list of tags */
+/* to be displayed is matched to the focused window tag list. */
+void
+winview(const Arg* arg)
+{
+ Window win, win_r, win_p, *win_c;
+ unsigned nc;
+ int unused;
+ Client* c;
+ Arg a;
+
+ if (!XGetInputFocus(dpy, &win, &unused)) return;
+ while (XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc)
+ && win_p != win_r) win = win_p;
+
+ if (!(c = wintoclient(win))) return;
+
+ a.ui = c->tags;
+ view(&a);
+}
+
diff --git a/patch/winview.h b/patch/winview.h
new file mode 100644
index 0000000..9c2ec97
--- /dev/null
+++ b/patch/winview.h
@@ -0,0 +1,2 @@
+static void winview(const Arg* arg);
+
diff --git a/patch/xkb.c b/patch/xkb.c
new file mode 100644
index 0000000..d779733
--- /dev/null
+++ b/patch/xkb.c
@@ -0,0 +1,68 @@
+static XkbInfo xkbGlobal;
+static XkbInfo *xkbSaved = NULL;
+
+static XkbInfo *
+createxkb(Window w)
+{
+ XkbInfo *xkb;
+
+ xkb = malloc(sizeof *xkb);
+ if (xkb == NULL)
+ die("fatal: could not malloc() %u bytes\n", sizeof *xkb);
+ xkb->group = xkbGlobal.group;
+ xkb->w = w;
+ xkb->next = xkbSaved;
+ if (xkbSaved != NULL)
+ xkbSaved->prev = xkb;
+ xkb->prev = NULL;
+ xkbSaved = xkb;
+
+ return xkb;
+}
+
+XkbInfo *
+findxkb(Window w)
+{
+ XkbInfo *xkb;
+ for (xkb = xkbSaved; xkb != NULL; xkb = xkb->next)
+ if (xkb->w == w)
+ return xkb;
+ return NULL;
+}
+
+void
+xkbeventnotify(XEvent *e)
+{
+ XkbEvent *ev;
+
+ ev = (XkbEvent *) e;
+ switch (ev->any.xkb_type) {
+ case XkbStateNotify:
+ xkbGlobal.group = ev->state.locked_group;
+ if (selmon != NULL && selmon->sel != NULL)
+ selmon->sel->xkb->group = xkbGlobal.group;
+ drawbars();
+ break;
+ }
+}
+
+/* xkb bar module */
+int
+width_xkb(Bar *bar, BarArg *a)
+{
+ return TEXTW(xkb_layouts[xkbGlobal.group]);
+}
+
+int
+draw_xkb(Bar *bar, BarArg *a)
+{
+ drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, xkb_layouts[xkbGlobal.group], 0, False);
+ return 1;
+}
+
+int
+click_xkb(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkXKB;
+}
+
diff --git a/patch/xkb.h b/patch/xkb.h
new file mode 100644
index 0000000..2c6d33a
--- /dev/null
+++ b/patch/xkb.h
@@ -0,0 +1,8 @@
+static XkbInfo *createxkb(Window w);
+static XkbInfo *findxkb(Window w);
+static void xkbeventnotify(XEvent *e);
+
+static int width_xkb(Bar *bar, BarArg *a);
+static int draw_xkb(Bar *bar, BarArg *a);
+static int click_xkb(Bar *bar, Arg *arg, BarArg *a);
+
diff --git a/patch/xrdb.c b/patch/xrdb.c
new file mode 100644
index 0000000..1490ace
--- /dev/null
+++ b/patch/xrdb.c
@@ -0,0 +1,128 @@
+void
+loadxrdb()
+{
+ Display *display;
+ char * resm;
+ XrmDatabase xrdb;
+ char *type;
+ XrmValue value;
+
+ display = XOpenDisplay(NULL);
+
+ if (display != NULL) {
+ resm = XResourceManagerString(display);
+
+ if (resm != NULL) {
+ xrdb = XrmGetStringDatabase(resm);
+
+ if (xrdb != NULL) {
+ XRDB_LOAD_COLOR("dwm.normfgcolor", normfgcolor);
+ XRDB_LOAD_COLOR("dwm.normbgcolor", normbgcolor);
+ XRDB_LOAD_COLOR("dwm.normbordercolor", normbordercolor);
+ XRDB_LOAD_COLOR("dwm.normfloatcolor", normfloatcolor);
+ XRDB_LOAD_COLOR("dwm.selfgcolor", selfgcolor);
+ XRDB_LOAD_COLOR("dwm.selbgcolor", selbgcolor);
+ XRDB_LOAD_COLOR("dwm.selbordercolor", selbordercolor);
+ XRDB_LOAD_COLOR("dwm.selfloatcolor", selfloatcolor);
+ XRDB_LOAD_COLOR("dwm.titlenormfgcolor", titlenormfgcolor);
+ XRDB_LOAD_COLOR("dwm.titlenormbgcolor", titlenormbgcolor);
+ XRDB_LOAD_COLOR("dwm.titlenormbordercolor", titlenormbordercolor);
+ XRDB_LOAD_COLOR("dwm.titlenormfloatcolor", titlenormfloatcolor);
+ XRDB_LOAD_COLOR("dwm.titleselfgcolor", titleselfgcolor);
+ XRDB_LOAD_COLOR("dwm.titleselbgcolor", titleselbgcolor);
+ XRDB_LOAD_COLOR("dwm.titleselbordercolor", titleselbordercolor);
+ XRDB_LOAD_COLOR("dwm.titleselfloatcolor", titleselfloatcolor);
+ XRDB_LOAD_COLOR("dwm.tagsnormfgcolor", tagsnormfgcolor);
+ XRDB_LOAD_COLOR("dwm.tagsnormbgcolor", tagsnormbgcolor);
+ XRDB_LOAD_COLOR("dwm.tagsnormbordercolor", tagsnormbordercolor);
+ XRDB_LOAD_COLOR("dwm.tagsnormfloatcolor", tagsnormfloatcolor);
+ XRDB_LOAD_COLOR("dwm.tagsselfgcolor", tagsselfgcolor);
+ XRDB_LOAD_COLOR("dwm.tagsselbgcolor", tagsselbgcolor);
+ XRDB_LOAD_COLOR("dwm.tagsselbordercolor", tagsselbordercolor);
+ XRDB_LOAD_COLOR("dwm.tagsselfloatcolor", tagsselfloatcolor);
+ XRDB_LOAD_COLOR("dwm.hidnormfgcolor", hidnormfgcolor);
+ XRDB_LOAD_COLOR("dwm.hidnormbgcolor", hidnormbgcolor);
+ XRDB_LOAD_COLOR("dwm.hidselfgcolor", hidselfgcolor);
+ XRDB_LOAD_COLOR("dwm.hidselbgcolor", hidselbgcolor);
+ XRDB_LOAD_COLOR("dwm.urgfgcolor", urgfgcolor);
+ XRDB_LOAD_COLOR("dwm.urgbgcolor", urgbgcolor);
+ XRDB_LOAD_COLOR("dwm.urgbordercolor", urgbordercolor);
+ XRDB_LOAD_COLOR("dwm.urgfloatcolor", urgfloatcolor);
+ #if BAR_FLEXWINTITLE_PATCH
+ XRDB_LOAD_COLOR("dwm.normTTBbgcolor", normTTBbgcolor);
+ XRDB_LOAD_COLOR("dwm.normLTRbgcolor", normLTRbgcolor);
+ XRDB_LOAD_COLOR("dwm.normMONObgcolor", normMONObgcolor);
+ XRDB_LOAD_COLOR("dwm.normGRIDbgcolor", normGRIDbgcolor);
+ XRDB_LOAD_COLOR("dwm.normGRD1bgcolor", normGRD1bgcolor);
+ XRDB_LOAD_COLOR("dwm.normGRD2bgcolor", normGRD2bgcolor);
+ XRDB_LOAD_COLOR("dwm.normGRDMbgcolor", normGRDMbgcolor);
+ XRDB_LOAD_COLOR("dwm.normHGRDbgcolor", normHGRDbgcolor);
+ XRDB_LOAD_COLOR("dwm.normDWDLbgcolor", normDWDLbgcolor);
+ XRDB_LOAD_COLOR("dwm.normSPRLbgcolor", normSPRLbgcolor);
+ XRDB_LOAD_COLOR("dwm.normfloatbgcolor", normfloatbgcolor);
+ XRDB_LOAD_COLOR("dwm.actTTBbgcolor", actTTBbgcolor);
+ XRDB_LOAD_COLOR("dwm.actLTRbgcolor", actLTRbgcolor);
+ XRDB_LOAD_COLOR("dwm.actMONObgcolor", actMONObgcolor);
+ XRDB_LOAD_COLOR("dwm.actGRIDbgcolor", actGRIDbgcolor);
+ XRDB_LOAD_COLOR("dwm.actGRD1bgcolor", actGRD1bgcolor);
+ XRDB_LOAD_COLOR("dwm.actGRD2bgcolor", actGRD2bgcolor);
+ XRDB_LOAD_COLOR("dwm.actGRDMbgcolor", actGRDMbgcolor);
+ XRDB_LOAD_COLOR("dwm.actHGRDbgcolor", actHGRDbgcolor);
+ XRDB_LOAD_COLOR("dwm.actDWDLbgcolor", actDWDLbgcolor);
+ XRDB_LOAD_COLOR("dwm.actSPRLbgcolor", actSPRLbgcolor);
+ XRDB_LOAD_COLOR("dwm.actfloatbgcolor", actfloatbgcolor);
+ XRDB_LOAD_COLOR("dwm.selTTBbgcolor", selTTBbgcolor);
+ XRDB_LOAD_COLOR("dwm.selLTRbgcolor", selLTRbgcolor);
+ XRDB_LOAD_COLOR("dwm.selMONObgcolor", selMONObgcolor);
+ XRDB_LOAD_COLOR("dwm.selGRIDbgcolor", selGRIDbgcolor);
+ XRDB_LOAD_COLOR("dwm.selGRD1bgcolor", selGRD1bgcolor);
+ XRDB_LOAD_COLOR("dwm.selGRD2bgcolor", selGRD2bgcolor);
+ XRDB_LOAD_COLOR("dwm.selGRDMbgcolor", selGRDMbgcolor);
+ XRDB_LOAD_COLOR("dwm.selHGRDbgcolor", selHGRDbgcolor);
+ XRDB_LOAD_COLOR("dwm.selDWDLbgcolor", selDWDLbgcolor);
+ XRDB_LOAD_COLOR("dwm.selSPRLbgcolor", selSPRLbgcolor);
+ XRDB_LOAD_COLOR("dwm.selfloatbgcolor", selfloatbgcolor);
+ #endif // BAR_FLEXWINTITLE_PATCH
+ #if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH && BAR_STATUS2D_PATCH
+ XRDB_LOAD_COLOR("color0", termcol0);
+ XRDB_LOAD_COLOR("color1", termcol1);
+ XRDB_LOAD_COLOR("color2", termcol2);
+ XRDB_LOAD_COLOR("color3", termcol3);
+ XRDB_LOAD_COLOR("color4", termcol4);
+ XRDB_LOAD_COLOR("color5", termcol5);
+ XRDB_LOAD_COLOR("color6", termcol6);
+ XRDB_LOAD_COLOR("color7", termcol7);
+ XRDB_LOAD_COLOR("color8", termcol8);
+ XRDB_LOAD_COLOR("color9", termcol9);
+ XRDB_LOAD_COLOR("color10", termcol10);
+ XRDB_LOAD_COLOR("color11", termcol11);
+ XRDB_LOAD_COLOR("color12", termcol12);
+ XRDB_LOAD_COLOR("color13", termcol13);
+ XRDB_LOAD_COLOR("color14", termcol14);
+ XRDB_LOAD_COLOR("color15", termcol15);
+ #endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH
+
+ XrmDestroyDatabase(xrdb);
+ }
+ }
+ }
+
+ XCloseDisplay(display);
+}
+
+void
+xrdb(const Arg *arg)
+{
+ loadxrdb();
+ int i;
+ for (i = 0; i < LENGTH(colors); i++)
+ scheme[i] = drw_scm_create(drw, colors[i],
+ #if BAR_ALPHA_PATCH
+ alphas[i],
+ #endif // BAR_ALPHA_PATCH
+ ColCount
+ );
+ focus(NULL);
+ arrange(NULL);
+}
+
diff --git a/patch/xrdb.h b/patch/xrdb.h
new file mode 100644
index 0000000..3787bec
--- /dev/null
+++ b/patch/xrdb.h
@@ -0,0 +1,22 @@
+#include <X11/Xresource.h>
+
+#define XRDB_LOAD_COLOR(R,V) if (XrmGetResource(xrdb, R, NULL, &type, &value) == True) { \
+ if (value.addr != NULL && strnlen(value.addr, 8) == 7 && value.addr[0] == '#') { \
+ int i = 1; \
+ for (; i <= 6; i++) { \
+ if (value.addr[i] < 48) break; \
+ if (value.addr[i] > 57 && value.addr[i] < 65) break; \
+ if (value.addr[i] > 70 && value.addr[i] < 97) break; \
+ if (value.addr[i] > 102) break; \
+ } \
+ if (i == 7) { \
+ strncpy(V, value.addr, 7); \
+ V[7] = '\0'; \
+ } \
+ } \
+ }
+
+static void loadxrdb(void);
+static void xrdb(const Arg *arg);
+
+
diff --git a/patch/zoomswap.c b/patch/zoomswap.c
new file mode 100644
index 0000000..58ee9d4
--- /dev/null
+++ b/patch/zoomswap.c
@@ -0,0 +1,14 @@
+
+#if !PERTAG_PATCH
+static Client *prevzoom = NULL;
+#endif // PERTAG_PATCH
+
+Client *
+findbefore(Client *c) {
+ Client *p;
+ if (!c || c == c->mon->clients)
+ return NULL;
+ for (p = c->mon->clients; p && p->next != c; p = p->next);
+ return p;
+}
+
diff --git a/patch/zoomswap.h b/patch/zoomswap.h
new file mode 100644
index 0000000..22c752a
--- /dev/null
+++ b/patch/zoomswap.h
@@ -0,0 +1,2 @@
+static Client *findbefore(Client *c);
+