Last active
November 18, 2021 20:50
-
-
Save ahauser31/f30c8cb6fe5ae50476ea3dc0e9330927 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/config.def.h b/config.def.h | |
index 1c0b587..12a99d7 100644 | |
--- a/config.def.h | |
+++ b/config.def.h | |
@@ -1,8 +1,15 @@ | |
/* See LICENSE file for copyright and license details. */ | |
+#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */ | |
+ | |
/* appearance */ | |
static const unsigned int borderpx = 1; /* border pixel of windows */ | |
static const unsigned int snap = 32; /* snap pixel */ | |
+static const unsigned int gappih = 20; /* horiz inner gap between windows */ | |
+static const unsigned int gappiv = 20; /* vert inner gap between windows */ | |
+static const unsigned int gappoh = 20; /* horiz outer gap between windows and screen edge */ | |
+static const unsigned int gappov = 20; /* vert outer gap between windows and screen edge */ | |
+static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ | |
static const int showbar = 1; /* 0 means no bar */ | |
static const int topbar = 1; /* 0 means bottom bar */ | |
static const char *fonts[] = { "monospace:size=10" }; | |
@@ -16,11 +23,27 @@ static const char *colors[][3] = { | |
/* fg bg border */ | |
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | |
[SchemeSel] = { col_gray4, col_cyan, col_cyan }, | |
+ [SchemeStatus] = { col_gray3, col_gray1, "#000000" }, // Statusbar right {text,background,not used but cannot be empty} | |
+ [SchemeInfoSel] = { col_gray4, col_cyan, "#000000" }, // infobar middle selected {text,background,not used but cannot be empty} | |
+ [SchemeInfoNorm] = { col_gray3, col_gray1, "#000000" }, // infobar middle unselected {text,background,not used but cannot be empty} | |
}; | |
/* tagging */ | |
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | |
+static const char *tagscolors[][4] = { | |
+ /* fg bg fg_sel bg_sel */ | |
+ { "#ff0000", col_gray1, col_gray4, col_cyan }, | |
+ { "#ff7f00", col_gray1, col_gray4, col_cyan }, | |
+ { "#ffff00", col_gray1, col_gray4, col_cyan }, | |
+ { "#00ff00", col_gray1, col_gray4, col_cyan }, | |
+ { "#0000ff", col_gray1, col_gray4, col_cyan }, | |
+ { "#4b0082", col_gray1, col_gray4, col_cyan }, | |
+ { "#9400d3", col_gray1, col_gray4, col_cyan }, | |
+ { "#ff00ff", col_gray1, col_gray4, col_cyan }, | |
+ { "#dddddd", col_gray1, col_gray4, col_cyan }, | |
+}; | |
+ | |
static const Rule rules[] = { | |
/* xprop(1): | |
* WM_CLASS(STRING) = instance, class | |
@@ -36,11 +59,25 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] | |
static const int nmaster = 1; /* number of clients in master area */ | |
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ | |
+#include "vanitygaps.c" | |
+ | |
static const Layout layouts[] = { | |
/* symbol arrange function */ | |
{ "[]=", tile }, /* first entry is default */ | |
- { "><>", NULL }, /* no layout function means floating behavior */ | |
{ "[M]", monocle }, | |
+ // { "[@]", spiral }, | |
+ // { "[\\]", dwindle }, | |
+ // { "H[]", deck }, | |
+ // { "TTT", bstack }, | |
+ // { "===", bstackhoriz }, | |
+ // { "HHH", grid }, | |
+ // { "###", nrowgrid }, | |
+ // { "---", horizgrid }, | |
+ // { ":::", gaplessgrid }, | |
+ { "|M|", centeredmaster }, | |
+ // { ">M>", centeredfloatingmaster }, | |
+ { "><>", NULL }, /* no layout function means floating behavior */ | |
+ { NULL, NULL }, | |
}; | |
/* key definitions */ | |
@@ -54,6 +91,8 @@ static const Layout layouts[] = { | |
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ | |
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | |
+#define STATUSBAR "dwmblocks" | |
+ | |
/* commands */ | |
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | |
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | |
@@ -64,6 +103,8 @@ static Key keys[] = { | |
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, | |
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, | |
{ MODKEY, XK_b, togglebar, {0} }, | |
+ { MODKEY|ShiftMask, XK_j, rotatestack, {.i = +1 } }, | |
+ { MODKEY|ShiftMask, XK_k, rotatestack, {.i = -1 } }, | |
{ MODKEY, XK_j, focusstack, {.i = +1 } }, | |
{ MODKEY, XK_k, focusstack, {.i = -1 } }, | |
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, | |
@@ -71,11 +112,28 @@ static Key keys[] = { | |
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, | |
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, | |
{ MODKEY, XK_Return, zoom, {0} }, | |
+ { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, | |
+ { MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, | |
+ { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, | |
{ MODKEY, XK_Tab, view, {0} }, | |
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, | |
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, | |
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, | |
- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, | |
+ { MODKEY, XK_c, setlayout, {.v = &layouts[2]} }, | |
+ { MODKEY, XK_f, setlayout, {.v = &layouts[3]} }, | |
+ { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, | |
{ MODKEY, XK_space, setlayout, {0} }, | |
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, | |
{ MODKEY, XK_0, view, {.ui = ~0 } }, | |
@@ -102,8 +160,9 @@ static Button buttons[] = { | |
/* click event mask button function argument */ | |
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, | |
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, | |
- { ClkWinTitle, 0, Button2, zoom, {0} }, | |
- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, | |
+ { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} }, | |
+ { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} }, | |
+ { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} }, | |
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, | |
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, | |
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, | |
diff --git a/dwm.1 b/dwm.1 | |
index ddc8321..86e73f9 100644 | |
--- a/dwm.1 | |
+++ b/dwm.1 | |
@@ -30,6 +30,14 @@ top left corner. The tags which are applied to one or more windows are | |
indicated with an empty square in the top left corner. | |
.P | |
dwm draws a small border around windows to indicate the focus state. | |
+.P | |
+On start, dwm can start additional programs that may be specified in two special | |
+shell scripts (see the FILES section below), autostart_blocking.sh and | |
+autostart.sh. The former is executed first and dwm will wait for its | |
+termination before starting. The latter is executed in the background before | |
+dwm enters its handler loop. | |
+.P | |
+Either of these files may be omitted. | |
.SH OPTIONS | |
.TP | |
.B \-v | |
@@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state. | |
.TP | |
.B Mod1\-Button3 | |
Resize focused window while dragging. Tiled windows will be toggled to the floating state. | |
+.SH FILES | |
+The files containing programs to be started along with dwm are searched for in | |
+the following directories: | |
+.IP "1. $XDG_DATA_HOME/dwm" | |
+.IP "2. $HOME/.local/share/dwm" | |
+.IP "3. $HOME/.dwm" | |
+.P | |
+The first existing directory is scanned for any of the autostart files below. | |
+.TP 15 | |
+autostart.sh | |
+This file is started as a shell background process before dwm enters its handler | |
+loop. | |
+.TP 15 | |
+autostart_blocking.sh | |
+This file is started before any autostart.sh; dwm waits for its termination. | |
.SH CUSTOMIZATION | |
dwm is customized by creating a custom config.h and (re)compiling the source | |
code. This keeps it fast, secure and simple. | |
diff --git a/dwm.c b/dwm.c | |
index 664c527..20b806e 100644 | |
--- a/dwm.c | |
+++ b/dwm.c | |
@@ -29,6 +29,7 @@ | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
+#include <sys/stat.h> | |
#include <sys/wait.h> | |
#include <X11/cursorfont.h> | |
#include <X11/keysym.h> | |
@@ -59,12 +60,12 @@ | |
/* enums */ | |
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |
-enum { SchemeNorm, SchemeSel }; /* color schemes */ | |
+enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ | |
enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | |
NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ | |
-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
+enum { ClkTagBar, ClkLtSymbol, ClkStatusText, | |
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ | |
typedef union { | |
@@ -119,6 +120,10 @@ struct Monitor { | |
int by; /* bar geometry */ | |
int mx, my, mw, mh; /* screen size */ | |
int wx, wy, ww, wh; /* window area */ | |
+ int gappih; /* horizontal gap between windows */ | |
+ int gappiv; /* vertical gap between windows */ | |
+ int gappoh; /* horizontal outer gaps */ | |
+ int gappov; /* vertical outer gaps */ | |
unsigned int seltags; | |
unsigned int sellt; | |
unsigned int tagset[2]; | |
@@ -163,6 +168,9 @@ static void detachstack(Client *c); | |
static Monitor *dirtomon(int dir); | |
static void drawbar(Monitor *m); | |
static void drawbars(void); | |
+static int drawstatusbar(Monitor *m, int bh, char* text); | |
+static void enqueue(Client *c); | |
+static void enqueuestack(Client *c); | |
static void enternotify(XEvent *e); | |
static void expose(XEvent *e); | |
static void focus(Client *c); | |
@@ -172,6 +180,7 @@ static void focusstack(const Arg *arg); | |
static Atom getatomprop(Client *c, Atom prop); | |
static int getrootptr(int *x, int *y); | |
static long getstate(Window w); | |
+static pid_t getstatusbarpid(); | |
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | |
static void grabbuttons(Client *c, int focused); | |
static void grabkeys(void); | |
@@ -193,7 +202,9 @@ static void resize(Client *c, int x, int y, int w, int h, int interact); | |
static void resizeclient(Client *c, int x, int y, int w, int h); | |
static void resizemouse(const Arg *arg); | |
static void restack(Monitor *m); | |
+static void rotatestack(const Arg *arg); | |
static void run(void); | |
+static void runautostart(void); | |
static void scan(void); | |
static int sendevent(Client *c, Atom proto); | |
static void sendmon(Client *c, Monitor *m); | |
@@ -206,10 +217,10 @@ static void setup(void); | |
static void seturgent(Client *c, int urg); | |
static void showhide(Client *c); | |
static void sigchld(int unused); | |
+static void sigstatusbar(const Arg *arg); | |
static void spawn(const Arg *arg); | |
static void tag(const Arg *arg); | |
static void tagmon(const Arg *arg); | |
-static void tile(Monitor *); | |
static void togglebar(const Arg *arg); | |
static void togglefloating(const Arg *arg); | |
static void toggletag(const Arg *arg); | |
@@ -236,8 +247,15 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); | |
static void zoom(const Arg *arg); | |
/* variables */ | |
+static const char autostartblocksh[] = "autostart_blocking.sh"; | |
+static const char autostartsh[] = "autostart.sh"; | |
static const char broken[] = "broken"; | |
-static char stext[256]; | |
+static const char dwmdir[] = "dwm"; | |
+static const char localshare[] = ".local/share"; | |
+static char stext[1024]; | |
+static int statussig; | |
+static int statusw; | |
+static pid_t statuspid = -1; | |
static int screen; | |
static int sw, sh; /* X display screen geometry width, height */ | |
static int bh, blw = 0; /* bar geometry */ | |
@@ -264,6 +282,7 @@ static Atom wmatom[WMLast], netatom[NetLast]; | |
static int running = 1; | |
static Cur *cursor[CurLast]; | |
static Clr **scheme; | |
+static Clr **tagsscheme; | |
static Display *dpy; | |
static Drw *drw; | |
static Monitor *mons, *selmon; | |
@@ -440,10 +459,34 @@ buttonpress(XEvent *e) | |
arg.ui = 1 << i; | |
} else if (ev->x < x + blw) | |
click = ClkLtSymbol; | |
- else if (ev->x > selmon->ww - (int)TEXTW(stext)) | |
- click = ClkStatusText; | |
- else | |
- click = ClkWinTitle; | |
+ else if (ev->x > selmon->ww - statusw) { | |
+ x = selmon->ww - statusw; | |
+ click = ClkStatusText; | |
+ | |
+ char *text, *s, ch; | |
+ statussig = 0; | |
+ for (text = s = stext; *s && x <= ev->x; s++) { | |
+ if ((unsigned char)(*s) < ' ') { | |
+ ch = *s; | |
+ *s = '\0'; | |
+ x += TEXTW(text) - lrpad; | |
+ *s = ch; | |
+ text = s + 1; | |
+ if (x >= ev->x) | |
+ break; | |
+ statussig = ch; | |
+ } else if (*s == '^') { | |
+ *s = '\0'; | |
+ x += TEXTW(text) - lrpad; | |
+ *s = '^'; | |
+ if (*(++s) == 'f') | |
+ x += atoi(++s); | |
+ while (*(s++) != '^'); | |
+ text = s; | |
+ s--; | |
+ } | |
+ } | |
+ } | |
} else if ((c = wintoclient(ev->window))) { | |
focus(c); | |
restack(selmon); | |
@@ -485,8 +528,10 @@ cleanup(void) | |
cleanupmon(mons); | |
for (i = 0; i < CurLast; i++) | |
drw_cur_free(drw, cursor[i]); | |
- for (i = 0; i < LENGTH(colors); i++) | |
+ for (i = 0; i < LENGTH(colors) + 1; i++) | |
free(scheme[i]); | |
+ for (i = 0; i < LENGTH(tagscolors); i++) | |
+ free(tagsscheme[i]); | |
XDestroyWindow(dpy, wmcheckwin); | |
drw_free(drw); | |
XSync(dpy, False); | |
@@ -639,6 +684,10 @@ createmon(void) | |
m->nmaster = nmaster; | |
m->showbar = showbar; | |
m->topbar = topbar; | |
+ m->gappih = gappih; | |
+ m->gappiv = gappiv; | |
+ m->gappoh = gappoh; | |
+ m->gappov = gappov; | |
m->lt[0] = &layouts[0]; | |
m->lt[1] = &layouts[1 % LENGTH(layouts)]; | |
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); | |
@@ -704,9 +753,7 @@ drawbar(Monitor *m) | |
/* draw status first so it can be overdrawn by tags later */ | |
if (m == selmon) { /* status is only drawn on selected monitor */ | |
- drw_setscheme(drw, scheme[SchemeNorm]); | |
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ | |
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); | |
+ tw = statusw = m->ww - drawstatusbar(m, bh, stext); | |
} | |
for (c = m->clients; c; c = c->next) { | |
@@ -717,12 +764,22 @@ drawbar(Monitor *m) | |
x = 0; | |
for (i = 0; i < LENGTH(tags); i++) { | |
w = TEXTW(tags[i]); | |
- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); | |
+ /* set the scheme colors of drw directly as the tagsschemes don't follow the regular scheme layout */ | |
+ if (m->tagset[m->seltags] & 1 << i) { | |
+ /* Tag active */ | |
+ drw->scheme[ColFg] = tagsscheme[i][2]; | |
+ drw->scheme[ColBg] = tagsscheme[i][3]; | |
+ } else { | |
+ /* Tag not active */ | |
+ drw->scheme[ColFg] = tagsscheme[i][0]; | |
+ drw->scheme[ColBg] = tagsscheme[i][1]; | |
+ } | |
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); | |
- if (occ & 1 << i) | |
- drw_rect(drw, x + boxs, boxs, boxw, boxw, | |
- m == selmon && selmon->sel && selmon->sel->tags & 1 << i, | |
- urg & 1 << i); | |
+ /* Uncomment the following lines for the small square "occupied" indicator of the tags */ | |
+ /* if (occ & 1 << i) */ | |
+ /* drw_rect(drw, x + boxs, boxs, boxw, boxw, */ | |
+ /* m == selmon && selmon->sel && selmon->sel->tags & 1 << i, */ | |
+ /* urg & 1 << i); */ | |
x += w; | |
} | |
w = blw = TEXTW(m->ltsymbol); | |
@@ -730,15 +787,8 @@ drawbar(Monitor *m) | |
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | |
if ((w = m->ww - tw - x) > bh) { | |
- if (m->sel) { | |
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); | |
- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); | |
- if (m->sel->isfloating) | |
- drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); | |
- } else { | |
- drw_setscheme(drw, scheme[SchemeNorm]); | |
- drw_rect(drw, x, 0, w, bh, 1, 1); | |
- } | |
+ drw_setscheme(drw, scheme[SchemeInfoNorm]); | |
+ drw_rect(drw, x, 0, w, bh, 1, 1); | |
} | |
drw_map(drw, m->barwin, 0, 0, m->ww, bh); | |
} | |
@@ -752,6 +802,141 @@ drawbars(void) | |
drawbar(m); | |
} | |
+int | |
+drawstatusbar(Monitor *m, int bh, char* stext) { | |
+ int ret, i, j, w, x, len; | |
+ short isCode = 0; | |
+ char *text; | |
+ char *p; | |
+ | |
+ len = strlen(stext) + 1 ; | |
+ if (!(text = (char*) malloc(sizeof(char)*len))) | |
+ die("malloc"); | |
+ p = text; | |
+ | |
+ i = -1, j = 0; | |
+ while (stext[++i]) | |
+ if ((unsigned char)stext[i] >= ' ') | |
+ text[j++] = stext[i]; | |
+ text[j] = '\0'; | |
+ | |
+ /* compute width of the status text */ | |
+ w = 0; | |
+ i = -1; | |
+ while (text[++i]) { | |
+ if (text[i] == '^') { | |
+ if (!isCode) { | |
+ isCode = 1; | |
+ text[i] = '\0'; | |
+ w += TEXTW(text) - lrpad; | |
+ text[i] = '^'; | |
+ if (text[++i] == 'f') | |
+ w += atoi(text + ++i); | |
+ } else { | |
+ isCode = 0; | |
+ text = text + i + 1; | |
+ i = -1; | |
+ } | |
+ } | |
+ } | |
+ if (!isCode) | |
+ w += TEXTW(text) - lrpad; | |
+ else | |
+ isCode = 0; | |
+ text = p; | |
+ | |
+ w += 2; /* 1px padding on both sides */ | |
+ ret = x = m->ww - w; | |
+ | |
+ drw_setscheme(drw, scheme[LENGTH(colors)]); | |
+ drw->scheme[ColFg] = scheme[SchemeStatus][ColFg]; | |
+ drw->scheme[ColBg] = scheme[SchemeStatus][ColBg]; | |
+ drw_rect(drw, x, 0, w, bh, 1, 1); | |
+ x++; | |
+ | |
+ /* process status text */ | |
+ i = -1; | |
+ while (text[++i]) { | |
+ if (text[i] == '^' && !isCode) { | |
+ isCode = 1; | |
+ | |
+ text[i] = '\0'; | |
+ w = TEXTW(text) - lrpad; | |
+ drw_text(drw, x, 0, w, bh, 0, text, 0); | |
+ | |
+ x += w; | |
+ | |
+ /* process code */ | |
+ while (text[++i] != '^') { | |
+ if (text[i] == 'c') { | |
+ char buf[8]; | |
+ memcpy(buf, (char*)text+i+1, 7); | |
+ buf[7] = '\0'; | |
+ drw_clr_create(drw, &drw->scheme[ColFg], buf); | |
+ i += 7; | |
+ } else if (text[i] == 'b') { | |
+ char buf[8]; | |
+ memcpy(buf, (char*)text+i+1, 7); | |
+ buf[7] = '\0'; | |
+ drw_clr_create(drw, &drw->scheme[ColBg], buf); | |
+ i += 7; | |
+ } else if (text[i] == 'd') { | |
+ drw->scheme[ColFg] = scheme[SchemeStatus][ColFg]; | |
+ drw->scheme[ColBg] = scheme[SchemeStatus][ColBg]; | |
+ } 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); | |
+ | |
+ drw_rect(drw, rx + x, ry, rw, rh, 1, 0); | |
+ } else if (text[i] == 'f') { | |
+ x += atoi(text + ++i); | |
+ } | |
+ } | |
+ | |
+ text = text + i + 1; | |
+ i=-1; | |
+ isCode = 0; | |
+ } | |
+ } | |
+ | |
+ if (!isCode) { | |
+ w = TEXTW(text) - lrpad; | |
+ drw_text(drw, x, 0, w, bh, 0, text, 0); | |
+ } | |
+ | |
+ drw_setscheme(drw, scheme[SchemeStatus]); | |
+ free(p); | |
+ | |
+ return ret; | |
+} | |
+ | |
+void | |
+enqueue(Client *c) | |
+{ | |
+ Client *l; | |
+ for (l = c->mon->clients; l && l->next; l = l->next); | |
+ if (l) { | |
+ l->next = c; | |
+ c->next = NULL; | |
+ } | |
+} | |
+ | |
+void | |
+enqueuestack(Client *c) | |
+{ | |
+ Client *l; | |
+ for (l = c->mon->stack; l && l->snext; l = l->snext); | |
+ if (l) { | |
+ l->snext = c; | |
+ c->snext = NULL; | |
+ } | |
+} | |
+ | |
void | |
enternotify(XEvent *e) | |
{ | |
@@ -900,6 +1085,30 @@ getstate(Window w) | |
return result; | |
} | |
+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 strtoul(buf, NULL, 10); | |
+} | |
+ | |
int | |
gettextprop(Window w, Atom atom, char *text, unsigned int size) | |
{ | |
@@ -1236,11 +1445,8 @@ propertynotify(XEvent *e) | |
drawbars(); | |
break; | |
} | |
- if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { | |
+ if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) | |
updatetitle(c); | |
- if (c == c->mon->sel) | |
- drawbar(c->mon); | |
- } | |
if (ev->atom == netatom[NetWMWindowType]) | |
updatewindowtype(c); | |
} | |
@@ -1370,6 +1576,38 @@ restack(Monitor *m) | |
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | |
} | |
+void | |
+rotatestack(const Arg *arg) | |
+{ | |
+ Client *c = NULL, *f; | |
+ | |
+ if (!selmon->sel) | |
+ return; | |
+ f = selmon->sel; | |
+ if (arg->i > 0) { | |
+ for (c = nexttiled(selmon->clients); c && nexttiled(c->next); c = nexttiled(c->next)); | |
+ if (c){ | |
+ detach(c); | |
+ attach(c); | |
+ detachstack(c); | |
+ attachstack(c); | |
+ } | |
+ } else { | |
+ if ((c = nexttiled(selmon->clients))){ | |
+ detach(c); | |
+ enqueue(c); | |
+ detachstack(c); | |
+ enqueuestack(c); | |
+ } | |
+ } | |
+ if (c){ | |
+ arrange(selmon); | |
+ //unfocus(f, 1); | |
+ focus(f); | |
+ restack(selmon); | |
+ } | |
+} | |
+ | |
void | |
run(void) | |
{ | |
@@ -1381,6 +1619,83 @@ run(void) | |
handler[ev.type](&ev); /* call handler */ | |
} | |
+void | |
+runautostart(void) | |
+{ | |
+ char *pathpfx; | |
+ char *path; | |
+ char *xdgdatahome; | |
+ char *home; | |
+ struct stat sb; | |
+ | |
+ if ((home = getenv("HOME")) == NULL) | |
+ /* this is almost impossible */ | |
+ return; | |
+ | |
+ /* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm, | |
+ * otherwise use ~/.local/share/dwm as autostart script directory | |
+ */ | |
+ xdgdatahome = getenv("XDG_DATA_HOME"); | |
+ if (xdgdatahome != NULL && *xdgdatahome != '\0') { | |
+ /* space for path segments, separators and nul */ | |
+ pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2); | |
+ | |
+ if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) { | |
+ free(pathpfx); | |
+ return; | |
+ } | |
+ } else { | |
+ /* space for path segments, separators and nul */ | |
+ pathpfx = ecalloc(1, strlen(home) + strlen(localshare) | |
+ + strlen(dwmdir) + 3); | |
+ | |
+ if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) { | |
+ free(pathpfx); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ /* check if the autostart script directory exists */ | |
+ if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) { | |
+ /* the XDG conformant path does not exist or is no directory | |
+ * so we try ~/.dwm instead | |
+ */ | |
+ char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3); | |
+ if(pathpfx_new == NULL) { | |
+ free(pathpfx); | |
+ return; | |
+ } | |
+ pathpfx = pathpfx_new; | |
+ | |
+ if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) { | |
+ free(pathpfx); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ /* try the blocking script first */ | |
+ path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2); | |
+ 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 (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) { | |
+ free(path); | |
+ free(pathpfx); | |
+ } | |
+ | |
+ if (access(path, X_OK) == 0) | |
+ system(strcat(path, " &")); | |
+ | |
+ free(pathpfx); | |
+ free(path); | |
+} | |
+ | |
void | |
scan(void) | |
{ | |
@@ -1568,9 +1883,14 @@ setup(void) | |
cursor[CurResize] = drw_cur_create(drw, XC_sizing); | |
cursor[CurMove] = drw_cur_create(drw, XC_fleur); | |
/* init appearance */ | |
- scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); | |
+ scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *)); | |
+ scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3); | |
for (i = 0; i < LENGTH(colors); i++) | |
scheme[i] = drw_scm_create(drw, colors[i], 3); | |
+ /* init tag appearance */ | |
+ tagsscheme = ecalloc(LENGTH(tagscolors), sizeof(Clr *)); | |
+ for (i = 0; i < LENGTH(tagscolors); i++) | |
+ tagsscheme[i] = drw_scm_create(drw, tagscolors[i], 4); | |
/* init bars */ | |
updatebars(); | |
updatestatus(); | |
@@ -1637,6 +1957,20 @@ sigchld(int unused) | |
while (0 < waitpid(-1, NULL, WNOHANG)); | |
} | |
+void | |
+sigstatusbar(const Arg *arg) | |
+{ | |
+ union sigval sv; | |
+ | |
+ if (!statussig) | |
+ return; | |
+ sv.sival_int = arg->i; | |
+ if ((statuspid = getstatusbarpid()) <= 0) | |
+ return; | |
+ | |
+ sigqueue(statuspid, SIGRTMIN+statussig, sv); | |
+} | |
+ | |
void | |
spawn(const Arg *arg) | |
{ | |
@@ -1671,34 +2005,6 @@ tagmon(const Arg *arg) | |
sendmon(selmon->sel, dirtomon(arg->i)); | |
} | |
-void | |
-tile(Monitor *m) | |
-{ | |
- unsigned int i, n, h, mw, my, ty; | |
- Client *c; | |
- | |
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |
- if (n == 0) | |
- return; | |
- | |
- if (n > m->nmaster) | |
- mw = m->nmaster ? m->ww * m->mfact : 0; | |
- else | |
- mw = m->ww; | |
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |
- if (i < m->nmaster) { | |
- h = (m->wh - my) / (MIN(n, m->nmaster) - i); | |
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); | |
- if (my + HEIGHT(c) < m->wh) | |
- my += HEIGHT(c); | |
- } else { | |
- h = (m->wh - ty) / (n - i); | |
- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); | |
- if (ty + HEIGHT(c) < m->wh) | |
- ty += HEIGHT(c); | |
- } | |
-} | |
- | |
void | |
togglebar(const Arg *arg) | |
{ | |
@@ -2145,6 +2451,7 @@ main(int argc, char *argv[]) | |
die("pledge"); | |
#endif /* __OpenBSD__ */ | |
scan(); | |
+ runautostart(); | |
run(); | |
cleanup(); | |
XCloseDisplay(dpy); | |
diff --git a/vanitygaps.c b/vanitygaps.c | |
new file mode 100644 | |
index 0000000..3f31593 | |
--- /dev/null | |
+++ b/vanitygaps.c | |
@@ -0,0 +1,809 @@ | |
+/* 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); | |
+/* Layouts (delete the ones you do not need) */ | |
+static void bstack(Monitor *m); | |
+static void bstackhoriz(Monitor *m); | |
+static void centeredmaster(Monitor *m); | |
+static void centeredfloatingmaster(Monitor *m); | |
+static void deck(Monitor *m); | |
+static void dwindle(Monitor *m); | |
+static void fibonacci(Monitor *m, int s); | |
+static void grid(Monitor *m); | |
+static void nrowgrid(Monitor *m); | |
+static void spiral(Monitor *m); | |
+static void tile(Monitor *m); | |
+/* Internals */ | |
+static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc); | |
+static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr); | |
+static void setgaps(int oh, int ov, int ih, int iv); | |
+ | |
+/* Settings */ | |
+#if !PERTAG_PATCH | |
+static int enablegaps = 1; | |
+#endif // PERTAG_PATCH | |
+ | |
+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; | |
+ arrange(selmon); | |
+} | |
+ | |
+void | |
+togglegaps(const Arg *arg) | |
+{ | |
+ #if PERTAG_PATCH | |
+ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag]; | |
+ #else | |
+ enablegaps = !enablegaps; | |
+ #endif // PERTAG_PATCH | |
+ arrange(NULL); | |
+} | |
+ | |
+void | |
+defaultgaps(const Arg *arg) | |
+{ | |
+ setgaps(gappoh, gappov, gappih, gappiv); | |
+} | |
+ | |
+void | |
+incrgaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh + arg->i, | |
+ selmon->gappov + arg->i, | |
+ selmon->gappih + arg->i, | |
+ selmon->gappiv + arg->i | |
+ ); | |
+} | |
+ | |
+void | |
+incrigaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh, | |
+ selmon->gappov, | |
+ selmon->gappih + arg->i, | |
+ selmon->gappiv + arg->i | |
+ ); | |
+} | |
+ | |
+void | |
+incrogaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh + arg->i, | |
+ selmon->gappov + arg->i, | |
+ selmon->gappih, | |
+ selmon->gappiv | |
+ ); | |
+} | |
+ | |
+void | |
+incrohgaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh + arg->i, | |
+ selmon->gappov, | |
+ selmon->gappih, | |
+ selmon->gappiv | |
+ ); | |
+} | |
+ | |
+void | |
+incrovgaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh, | |
+ selmon->gappov + arg->i, | |
+ selmon->gappih, | |
+ selmon->gappiv | |
+ ); | |
+} | |
+ | |
+void | |
+incrihgaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh, | |
+ selmon->gappov, | |
+ selmon->gappih + arg->i, | |
+ selmon->gappiv | |
+ ); | |
+} | |
+ | |
+void | |
+incrivgaps(const Arg *arg) | |
+{ | |
+ setgaps( | |
+ selmon->gappoh, | |
+ selmon->gappov, | |
+ selmon->gappih, | |
+ selmon->gappiv + arg->i | |
+ ); | |
+} | |
+ | |
+void | |
+getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc) | |
+{ | |
+ unsigned int n, oe, ie; | |
+ #if PERTAG_PATCH | |
+ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag]; | |
+ #else | |
+ oe = ie = enablegaps; | |
+ #endif // PERTAG_PATCH | |
+ Client *c; | |
+ | |
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |
+ if (smartgaps && n == 1) { | |
+ oe = 0; // outer gaps disabled 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 | |
+} | |
+ | |
+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 | |
+} | |
+ | |
+/*** | |
+ * Layouts | |
+ */ | |
+ | |
+/* | |
+ * Bottomstack layout + gaps | |
+ * https://dwm.suckless.org/patches/bottomstack/ | |
+ */ | |
+static void | |
+bstack(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ int oh, ov, ih, iv; | |
+ 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; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ 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 - sh; | |
+ sx = mx; | |
+ sy = my + mh + ih; | |
+ } | |
+ | |
+ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); | |
+ | |
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { | |
+ if (i < m->nmaster) { | |
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); | |
+ mx += WIDTH(c) + iv; | |
+ } else { | |
+ resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); | |
+ sx += WIDTH(c) + iv; | |
+ } | |
+ } | |
+} | |
+ | |
+static void | |
+bstackhoriz(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ int oh, ov, ih, iv; | |
+ 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; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ 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 - sh; | |
+ sy = my + mh + ih; | |
+ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster); | |
+ } | |
+ | |
+ 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) { | |
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); | |
+ mx += WIDTH(c) + iv; | |
+ } else { | |
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); | |
+ sy += HEIGHT(c) + ih; | |
+ } | |
+ } | |
+} | |
+ | |
+/* | |
+ * Centred master layout + gaps | |
+ * https://dwm.suckless.org/patches/centeredmaster/ | |
+ */ | |
+void | |
+centeredmaster(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ int oh, ov, ih, iv; | |
+ 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; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ /* initialize areas */ | |
+ 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; | |
+ rw = (m->ww - mw - 2*ov - 2*iv) - lw; | |
+ mx += lw + iv; | |
+ } else { | |
+ /* ||<---M--->|<-S->|| */ | |
+ mw = (mw - iv) * m->mfact; | |
+ lw = 0; | |
+ rw = m->ww - mw - iv - 2*ov; | |
+ } | |
+ lx = m->wx + ov; | |
+ ly = m->wy + oh; | |
+ rx = mx + mw + iv; | |
+ ry = m->wy + oh; | |
+ } | |
+ | |
+ /* calculate facts */ | |
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { | |
+ if (!m->nmaster || n < m->nmaster) | |
+ mfacts += 1; | |
+ else if ((n - m->nmaster) % 2) | |
+ lfacts += 1; // total factor of left hand stack area | |
+ else | |
+ rfacts += 1; // total factor of right hand stack area | |
+ } | |
+ | |
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) | |
+ if (!m->nmaster || n < m->nmaster) | |
+ mtotal += mh / mfacts; | |
+ else if ((n - m->nmaster) % 2) | |
+ ltotal += lh / lfacts; | |
+ else | |
+ rtotal += rh / rfacts; | |
+ | |
+ mrest = mh - mtotal; | |
+ lrest = lh - ltotal; | |
+ rrest = rh - rtotal; | |
+ | |
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { | |
+ if (!m->nmaster || i < m->nmaster) { | |
+ /* nmaster clients are stacked vertically, in the center of the screen */ | |
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); | |
+ my += HEIGHT(c) + ih; | |
+ } else { | |
+ /* stack clients are stacked vertically */ | |
+ if ((i - m->nmaster) % 2 ) { | |
+ resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); | |
+ ly += HEIGHT(c) + ih; | |
+ } else { | |
+ resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); | |
+ ry += HEIGHT(c) + ih; | |
+ } | |
+ } | |
+ } | |
+} | |
+ | |
+void | |
+centeredfloatingmaster(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ float mfacts, sfacts; | |
+ float mivf = 1.0; // master inner vertical gap factor | |
+ int oh, ov, ih, iv, mrest, srest; | |
+ int mx = 0, my = 0, mh = 0, mw = 0; | |
+ int sx = 0, sy = 0, sh = 0, sw = 0; | |
+ Client *c; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ 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; | |
+ } | |
+ | |
+ 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 */ | |
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); | |
+ mx += WIDTH(c) + iv*mivf; | |
+ } else { | |
+ /* stack clients are stacked horizontally */ | |
+ resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); | |
+ sx += WIDTH(c) + iv; | |
+ } | |
+} | |
+ | |
+/* | |
+ * Deck layout + gaps | |
+ * https://dwm.suckless.org/patches/deck/ | |
+ */ | |
+void | |
+deck(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ int oh, ov, ih, iv; | |
+ 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; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ 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 - sw; | |
+ sx = mx + mw + iv; | |
+ sh = m->wh - 2*oh; | |
+ } | |
+ | |
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); | |
+ | |
+ if (n - m->nmaster > 0) /* override layout symbol */ | |
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster); | |
+ | |
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |
+ if (i < m->nmaster) { | |
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); | |
+ my += HEIGHT(c) + ih; | |
+ } else { | |
+ resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0); | |
+ } | |
+} | |
+ | |
+/* | |
+ * Fibonacci layout + gaps | |
+ * https://dwm.suckless.org/patches/fibonacci/ | |
+ */ | |
+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 = m->wy + 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); | |
+ } | |
+} | |
+ | |
+void | |
+dwindle(Monitor *m) | |
+{ | |
+ fibonacci(m, 1); | |
+} | |
+ | |
+void | |
+spiral(Monitor *m) | |
+{ | |
+ fibonacci(m, 0); | |
+} | |
+ | |
+/* | |
+ * Gappless grid layout + gaps (ironically) | |
+ * https://dwm.suckless.org/patches/gaplessgrid/ | |
+ */ | |
+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++; | |
+ } | |
+ } | |
+} | |
+ | |
+/* | |
+ * Gridmode layout + gaps | |
+ * https://dwm.suckless.org/patches/gridmode/ | |
+ */ | |
+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); | |
+ } | |
+} | |
+ | |
+/* | |
+ * Horizontal grid layout + gaps | |
+ * https://dwm.suckless.org/patches/horizgrid/ | |
+ */ | |
+void | |
+horizgrid(Monitor *m) { | |
+ Client *c; | |
+ unsigned int n, i; | |
+ int oh, ov, ih, iv; | |
+ int mx = 0, my = 0, mh = 0, mw = 0; | |
+ int sx = 0, sy = 0, sh = 0, sw = 0; | |
+ int ntop, nbottom = 1; | |
+ float mfacts, sfacts; | |
+ int mrest, srest; | |
+ | |
+ /* Count windows */ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ if (n <= 2) | |
+ ntop = n; | |
+ else { | |
+ ntop = n / 2; | |
+ nbottom = n - ntop; | |
+ } | |
+ 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 * (nbottom - 1); | |
+ } | |
+ | |
+ mfacts = ntop; | |
+ sfacts = nbottom; | |
+ mrest = mw - (mw / ntop) * ntop; | |
+ srest = sw - (sw / nbottom) * nbottom; | |
+ | |
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |
+ if (i < ntop) { | |
+ resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); | |
+ mx += WIDTH(c) + iv; | |
+ } else { | |
+ resize(c, sx, sy, (sw / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); | |
+ sx += WIDTH(c) + iv; | |
+ } | |
+} | |
+ | |
+/* | |
+ * nrowgrid layout + gaps | |
+ * https://dwm.suckless.org/patches/nrowgrid/ | |
+ */ | |
+void | |
+nrowgrid(Monitor *m) | |
+{ | |
+ unsigned int n; | |
+ int 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), 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); | |
+ } | |
+} | |
+ | |
+/* | |
+ * Default tile layout + gaps | |
+ */ | |
+static void | |
+tile(Monitor *m) | |
+{ | |
+ unsigned int i, n; | |
+ int oh, ov, ih, iv; | |
+ 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; | |
+ | |
+ getgaps(m, &oh, &ov, &ih, &iv, &n); | |
+ if (n == 0) | |
+ return; | |
+ | |
+ 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 - sw; | |
+ sx = mx + mw + iv; | |
+ } | |
+ | |
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); | |
+ | |
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |
+ if (i < m->nmaster) { | |
+ resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); | |
+ my += HEIGHT(c) + ih; | |
+ } else { | |
+ resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); | |
+ sy += HEIGHT(c) + ih; | |
+ } | |
+} | |
+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment