diff options
29 files changed, 2737 insertions, 124 deletions
diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..f7ea9f8 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,6 @@ +;;; Directory Local Variables -*- no-byte-compile: t; -*- +;;; For more information see (info "(emacs) Directory Variables") + +((c-mode . ((indent-tabs-mode . t) + (flycheck-mode . nil) + (eval . (clang-format-mode 0))))) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef35fa6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.idea +*.log +tmp/ + + +*.o +dwm +.ccls-cache @@ -34,6 +34,9 @@ install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f dwm ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/dwm + $(MAKE) manpage + +manpage: mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 diff --git a/README.org b/README.org new file mode 100644 index 0000000..643dafd --- /dev/null +++ b/README.org @@ -0,0 +1,41 @@ +* Key layout +Notation: ++ S = Super ++ C = Control ++ ^k = Shift-k + +S-b = toggle bar +S-grave = toggle scratch terminal +S-j = focus next on the stack +S-k = focus prev on the stack +** Gaps +S-period = Increase gaps +S-comma = Decrease gaps +S-slash = Turn gaps off and on +S-^slash = Print current gaps (notify-send) +** Master manipulation +S-h = Decrease size of master +S-l = Increase size of master +S-c = Set current focused client to master +S-C-period = Decrease number of master clients +S-C-comma = Increase number of master clients +** Layouts +S-^t = Tiling +S-^f = Floating +S-^m = Monocle +S-^u = Centred monocle +S-^o = Centred floating monocle +S-^s = Spiral fibonacci +S-^d = Dwindle fibonacci +S-^g = 2 row grid +S-^i = Deck +S-^space = Toggle between current and previous layout +S-space = Toggle floating on currently focused client +** Monitors +S-m = Focus on the next monitor (wraps around) +S-^comma = Send to previous monitor +S-^period = Send to next monitor +** Tags and quit +S-Tab = Go to previously viewed tag +S-q = killclient +S-^q = quit diff --git a/config.def.h b/config.def.h index 9efa774..ccd0df6 100644 --- a/config.def.h +++ b/config.def.h @@ -16,11 +16,24 @@ 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} + [SchemeTagsSel] = { col_gray4, col_cyan, "#000000" }, // Tagbar left selected {text,background,not used but cannot be empty} + [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, // Tagbar left unselected {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" }; +/* launcher commands (They must be NULL terminated) */ +static const char* surf[] = { "surf", "duckduckgo.com", NULL }; + +static const Launcher launchers[] = { + /* command name to display */ + { surf, "surf" }, +}; + static const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class @@ -42,6 +55,8 @@ static const Layout layouts[] = { { "[]=", tile }, /* first entry is default */ { "><>", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, + { "|M|", centeredmaster }, + { ">M>", centeredfloatingmaster }, }; /* key definitions */ @@ -55,18 +70,27 @@ 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 }; static const char *termcmd[] = { "st", NULL }; +static const char scratchpadname[] = "scratchpad"; +static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, + { MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, + { MODKEY|ShiftMask, XK_h, inplacerotate, {.i = +2} }, + { MODKEY|ShiftMask, XK_l, inplacerotate, {.i = -2} }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, @@ -77,6 +101,8 @@ static const Key keys[] = { { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, + { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, { MODKEY, XK_space, setlayout, {0} }, { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, @@ -104,7 +130,9 @@ static const Button buttons[] = { { 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/config.h b/config.h new file mode 100644 index 0000000..fb514c7 --- /dev/null +++ b/config.h @@ -0,0 +1,189 @@ +/* See LICENSE file for copyright and license details. */ +#define true 1 +#define false 0 + +#define GTMask(X) 1 << (X - 1) +#define STATUSBAR "dwmblocks" + +/* appearance */ +static const unsigned int borderpx = 0; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int opengap = 20; /* optional gaps between windows */ +static const unsigned int gappx = 0; /* default gaps between windows */ +static const int showbar = true; /* 0 means no bar */ +static const int topbar = 0; /* 0 means bottom bar */ +static const char *fonts[] = { "Noto Sans Mono:size=13" }; +static const char dmenufont[] = "monospace:size=9"; +static const char col_black[] = "#161616"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +static const char col_cyan[] = "#005577"; +static const char col_lblue[] = "#77aafc"; +static const char col_dblue[] = "#225599"; +static const char col_lgreen[] = "#55f055"; +static const char col_dgreen[] = "#008000"; +static const char *colors[][3] = { + /* Scheme fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_black }, + [SchemeSel] = { col_gray4, col_cyan, "#230142" }, + [SchemeStatus] = { col_lblue, col_black, col_black }, + [SchemeTagsSel] = { col_gray4, col_dblue, col_black }, + [SchemeTagsNorm] = { col_lblue, col_black, col_black }, + [SchemeInfoSel] = { col_gray4, col_black, col_black }, + [SchemeInfoNorm] = { col_gray3, col_gray1, col_black }, +}; + +/* tagging */ + +static const char *tags[] = { "", "", "", "", "", "6", "7", "8", "9" }; + +/* Custom functions */ +static void togglegaps(const Arg *arg); +static void printgaps(const Arg *arg); + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Onboard", NULL, NULL, 0, 1, -1 }, + { "qutebrowser", NULL, NULL, GTMask(2), 0, -1 }, + { "firefox", NULL, NULL, GTMask(2), 0, -1 }, + { "Chromium", NULL, NULL, GTMask(2), 0, -1 }, + { "media-term", NULL, NULL, GTMask(3), 0, -1 }, + { "Spotify", NULL, NULL, GTMask(3), 0, -1 }, + { "Zathura", NULL, NULL, GTMask(4), 0, -1 }, + { "Com.github.xournalpp.xournalpp", NULL, NULL, GTMask(5), 0, -1 }, +}; + +/* layout(s) */ +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 */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +#include "./fibonacci.c" +#include "./gaplessgrid.c" + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[T]=", tile }, /* first entry is default */ + { "<F>=", NULL }, /* no layout function means floating behavior */ + { "{M}", monocle }, + { "|M|", centeredmaster }, + { ">M>", centeredfloatingmaster }, + { "[@]", spiral }, + { "[\\]", dwindle }, + { "###", gaplessgrid }, + { "[D]", deck }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static const char scratchpadname[] = "scratchpad"; +static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-e", "tmux", + NULL }; + +static char *statuscmds[] = { "notify-send Mouse$BUTTON" }; + +static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_period, setgaps, {.i = +1} }, + { MODKEY, XK_comma, setgaps, {.i = -1} }, + { MODKEY, XK_slash, togglegaps, {0} }, + { MODKEY|ShiftMask, XK_slash, printgaps, {0} }, + { MODKEY, XK_h, setmfact, {.f = -0.01} }, + { MODKEY, XK_l, setmfact, {.f = +0.01} }, + { MODKEY|ControlMask, XK_period, incnmaster, {.i = -1 } }, + { MODKEY|ControlMask, XK_comma, incnmaster, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, inplacerotate, {.i = +1} }, + { MODKEY|ShiftMask, XK_j, inplacerotate, {.i = -1} }, + { MODKEY|ShiftMask, XK_h, inplacerotate, {.i = -2} }, + { MODKEY|ShiftMask, XK_l, inplacerotate, {.i = +2} }, + { MODKEY, XK_c, zoom, {0} }, + { MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[0]} }, //tiling + { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, //floating + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[2]} }, //monocle + { MODKEY|ShiftMask, XK_u, setlayout, {.v = &layouts[3]} }, //cmonocle + { MODKEY|ShiftMask, XK_o, setlayout, {.v = &layouts[4]} }, //cfmonocle + { MODKEY|ShiftMask, XK_s, setlayout, {.v = &layouts[5]} }, //fib-spiral + { MODKEY|ShiftMask, XK_d, setlayout, {.v = &layouts[6]} }, //fib-spiral + { MODKEY|ShiftMask, XK_g, setlayout, {.v = &layouts[7]} }, //gapless-grid + { MODKEY|ShiftMask, XK_i, setlayout, {.v = &layouts[8]} }, //deck + { MODKEY|ShiftMask, XK_space, setlayout, {0} }, + { MODKEY, XK_space, togglefloating, {0} }, + { MODKEY, XK_m, focusmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_Tab, view, {.ui = 0} }, \ + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static const 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} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + +void +togglegaps(const Arg *arg) +{ + if (!selmon) + return; + int *gap_size = &selmon->pertag->gaps[selmon->pertag->curtag]; + if (*gap_size == gappx) + selmon->pertag->gaps[selmon->pertag->curtag] = opengap; + else + selmon->pertag->gaps[selmon->pertag->curtag] = gappx; + arrange(selmon); +} + +void +printgaps(const Arg *arg) +{ + if (!selmon) + return; + char *cmd = malloc(sizeof(*cmd) * 38); + sprintf(cmd, "notify-send -u low \"Gaps=%d\"", + selmon->pertag->gaps[selmon->pertag->curtag]); + system(cmd); + free(cmd); +} @@ -5,29 +5,59 @@ dwm \- dynamic window manager .B dwm .RB [ \-v ] .SH DESCRIPTION -dwm is a dynamic window manager for X. It manages windows in tiled, monocle -and floating layouts. Either layout can be applied dynamically, optimising the -environment for the application in use and the task performed. +dwm is a dynamic window manager for X. It manages windows in a +variety of layouts: +.nr PI 1n +.IP \[bu] +floating: windows can be resized and moved freely, a la usual window +managers. +.IP \[bu] +tiled: windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area +on the right contains all other windows. The number of master area +windows can be adjusted from zero to an arbitrary number. +.IP \[bu] +monocle (normal, centred or floating) + +Normal: all windows are maximised to the screen size. + +Centred: the screen is split into three sections with the master +clients getting the second section and the stacking clients get the +remaining 2 sections to be laid out in. + +Floating: the master clients are placed floating in the centre of the +screen while the remaining stacking clients are placed side by side +vertically. +.IP \[bu] +fibonacci (dwindle and spiral): windows are tiled in a spiralling or +dwindling pattern. + +In the dwindle layout new clients tend towards the bottom left of the +monitor while in the spiral layout clients tend towards the centre +bottom left. +.IP \[bu] +deck: the stacking clients are placed floating on top of each other +such that there are only two partitions of the screen space. +.IP \[bu] +gapless grid: n clients are arranged into a square of ceil(sqrt(n)) +length, where the top left is the latest client opened. .P -In tiled layouts windows are managed in a master and stacking area. The master -area on the left contains one window by default, and the stacking area on the -right contains all other windows. The number of master area windows can be -adjusted from zero to an arbitrary number. In monocle layout all windows are -maximised to the screen size. In floating layout windows can be resized and -moved freely. Dialog windows are always managed floating, regardless of the -layout applied. +Dialog windows are always managed floating, regardless of the layout +applied. .P -Windows are grouped by tags. Each window can be tagged with one or multiple -tags. Selecting certain tags displays all windows with these tags. +Windows are grouped by tags. Each window can be tagged with one or +multiple tags. Selecting certain tags displays all windows with these +tags. .P -Each screen contains a small status bar which displays all available tags, the -layout, the title of the focused window, and the text read from the root window -name property, if the screen is focused. A floating window is indicated with an -empty square and a maximised floating window is indicated with a filled square -before the windows title. The selected tags are indicated with a different -color. The tags of the focused window are indicated with a filled square in the -top left corner. The tags which are applied to one or more windows are -indicated with an empty square in the top left corner. +Each screen contains a small status bar which displays all available +tags, the layout, the title of the focused window, and the text read +from the root window name property, if the screen is focused. A +floating window is indicated with an empty square and a maximised +floating window is indicated with a filled square before the windows +title. The selected tags are indicated with a different color. The +tags of the focused window are indicated with a filled square in the +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. .SH OPTIONS @@ -39,119 +69,172 @@ prints version information to stderr, then exits. .TP .B X root window name is read and displayed in the status text area. It can be set with the -.BR xsetroot (1) +.BR xsetroot (1). This fork uses dwmblocks to generate system status information. command. +.SS Keyboard commands +Mod is set to Super (the "windows" key). .TP -.B Button1 -click on a tag label to display all windows with that tag, click on the layout -label toggles between tiled and floating layout. +.B Mod\-b +Toggle status bar + .TP -.B Button3 -click on a tag label adds/removes all windows with that tag to/from the view. +.B Mod\-` +Toggle scratchpad terminal (set to +.BR st(1) +) + +.TP +.B Mod\-j +Focus next window + +.TP +.B Mod\-k +Focus previous window + .TP -.B Mod1\-Button1 -click on a tag label applies that tag to the focused window. +.B Mod\-. +Increase gap size + .TP -.B Mod1\-Button3 -click on a tag label adds/removes that tag to/from the focused window. -.SS Keyboard commands +.B Mod\-, +Decrease gap size + .TP -.B Mod1\-Shift\-Return -Start -.BR st(1). +.B Mod\-/ +Toggle gaps + .TP -.B Mod1\-p -Spawn -.BR dmenu(1) -for launching other programs. +.B Mod\-Shift\-/ +Print current gap value (using +.BR notify-send(1) +) + .TP -.B Mod1\-, -Focus previous screen, if any. +.B Mod\-h +Decrease size of master area + .TP -.B Mod1\-. -Focus next screen, if any. +.B Mod\-l +Increase size of master are + .TP -.B Mod1\-Shift\-, -Send focused window to previous screen, if any. +.B Mod\-Control\-. +Decrease number of master clients + .TP -.B Mod1\-Shift\-. -Send focused window to next screen, if any. +.B Mod\-Control\-, +Increase number of master clients + .TP -.B Mod1\-b -Toggles bar on and off. +.B Mod\-Shift\-h +Rotate the stack clockwise but keep focus on the same position. + .TP -.B Mod1\-t -Sets tiled layout. +.B Mod\-Shift\-l +Rotate the stack anticlockwise but keep focus on the same position. + .TP -.B Mod1\-f -Sets floating layout. +.B Mod\-Shift\-k +Rotate the master clients clockwise but keep focus on the same position. + .TP -.B Mod1\-m -Sets monocle layout. +.B Mod\-Shift\-j +Rotate the master clients anticlockwise but keep focus on the same position. + .TP -.B Mod1\-space -Toggles between current and previous layout. +.B Mod\-c +If in stack area, swap currently focused client with master. If in master area, swap currently focused client with top of stack area. + .TP -.B Mod1\-j -Focus next window. +.B Mod\-Shift\-t +Set layout to tiling + .TP -.B Mod1\-k -Focus previous window. +.B Mod\-Shift\-f +Set layout to floating + .TP -.B Mod1\-i -Increase number of windows in master area. +.B Mod\-Shift\-m +Set layout to monocle + .TP -.B Mod1\-d -Decrease number of windows in master area. +.B Mod\-Shift\-u +Set layout to centred monocle + .TP -.B Mod1\-l -Increase master area size. +.B Mod\-Shift\-o +Set layout to centred floating monocle + .TP -.B Mod1\-h -Decrease master area size. +.B Mod\-Shift\-s +Set layout to spiral fibonacci + .TP -.B Mod1\-Return -Zooms/cycles focused window to/from master area (tiled layouts only). +.B Mod\-Shift\-d +Set layout to dwindle fibonacci + .TP -.B Mod1\-Shift\-c -Close focused window. +.B Mod\-Shift\-g +Set layout to gapless grid + .TP -.B Mod1\-Shift\-space -Toggle focused window between tiled and floating state. +.B Mod\-Shift\-i +Set layout to deck + .TP -.B Mod1\-Tab -Toggles to the previously selected tags. +.B Mod\-Shift\-space +Toggle between current layout and previous layout + +.TP +.B Mod\-space +Toggle current client's floating (floating -> not floating, not floating -> floating) + +.TP +.B Mod1\-[1..n] +Go to nth tag + .TP .B Mod1\-Shift\-[1..n] -Apply nth tag to focused window. +Send focused client to nth tag. + .TP -.B Mod1\-Shift\-0 -Apply all tags to focused window. +.B Mod\-m +Focus on the next monitor in monitor stack + .TP -.B Mod1\-Control\-Shift\-[1..n] -Add/remove nth tag to/from focused window. +.B Mod\-Shift\-, +Send client to previous monitor in monitor stack + .TP -.B Mod1\-[1..n] -View all windows with nth tag. +.B Mod\-Shift\-. +Send client to next monitor in monitor stack + .TP -.B Mod1\-0 -View all windows with any tag. +.B Mod\-Tab +View the previous tag + .TP -.B Mod1\-Control\-[1..n] -Add/remove all windows with nth tag to/from the view. +.B Mod\-q +Kill the currently focused client + .TP -.B Mod1\-Shift\-q -Quit dwm. +.B Mod\-Shift\-q +Kill dwm + .SS Mouse commands + .TP .B Mod1\-Button1 Move focused window while dragging. Tiled windows will be toggled to the floating state. + .TP .B Mod1\-Button2 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 CUSTOMIZATION dwm is customized by creating a custom config.h and (re)compiling the source code. This keeps it fast, secure and simple. @@ -49,7 +49,9 @@ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define ISVISIBLEONTAG(C, T) ((C->tags & T)) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +/* #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) */ #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -59,7 +61,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -111,6 +113,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +typedef struct Pertag Pertag; struct Monitor { char ltsymbol[16]; float mfact; @@ -130,6 +133,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; + Pertag *pertag; }; typedef struct { @@ -147,6 +151,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); +static void attachaside(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -156,7 +161,9 @@ static void clientmessage(XEvent *e); static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); +static void copyvalidchars(char *text, char *rawtext); static Monitor *createmon(void); +static void deck(Monitor *m); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c); @@ -176,6 +183,7 @@ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); static void incnmaster(const Arg *arg); +static void inplacerotate(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); @@ -184,6 +192,7 @@ static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); +static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); static void pop(Client *c); static void propertynotify(XEvent *e); @@ -200,6 +209,7 @@ static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); @@ -211,6 +221,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); +static void togglescratch(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -233,10 +244,15 @@ static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +static void centeredmaster(Monitor *m); +static void centeredfloatingmaster(Monitor *m); /* variables */ static const char broken[] = "broken"; static char stext[256]; +static char rawstext[256]; +static int statuscmdn; +static char lastbutton[] = "-"; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ @@ -269,8 +285,22 @@ static Monitor *mons, *selmon; static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ +// TODO: Figure out if there is a better way of doing this +#define TAG_SIZE 9 +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[TAG_SIZE + 1]; /* number of windows in master area */ + float mfacts[TAG_SIZE + 1]; /* mfacts per tag */ + unsigned int sellts[TAG_SIZE + 1]; /* selected layouts */ + const Layout *ltidxs[TAG_SIZE + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[TAG_SIZE + 1]; /* display bar for the current tag */ + int gaps[TAG_SIZE + 1]; /* size of gaps for the current tag*/ +}; + #include "config.h" +static unsigned int scratchtag = 1 << LENGTH(tags); + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -409,6 +439,17 @@ attach(Client *c) } void +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = c; +} + +void attachstack(Client *c) { c->snext = c->mon->stack; @@ -418,11 +459,12 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; - Arg arg = {0}; + unsigned int i, x, click, occ = 0; Client *c; + Arg arg = {0}; Monitor *m; XButtonPressedEvent *ev = &e->xbutton; + *lastbutton = '0' + ev->button; click = ClkRootWin; /* focus monitor if necessary */ @@ -433,9 +475,14 @@ buttonpress(XEvent *e) } if (ev->window == selmon->barwin) { i = x = 0; - do + for (c = m->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + do { + /* do not reserve space for vacant tags */ + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; x += TEXTW(tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); + } while (ev->x >= x && ++i < LENGTH(tags)); if (i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; @@ -445,6 +492,22 @@ buttonpress(XEvent *e) click = ClkStatusText; else click = ClkWinTitle; + char *text = rawstext; + int i = -1; + char ch; + statuscmdn = 0; + while (text[++i]) { + if ((unsigned char)text[i] < ' ') { + ch = text[i]; + text[i] = '\0'; + x += TEXTW(text) - lrpad; + text[i] = ch; + text += i+1; + i = -1; + if (x >= ev->x) break; + if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; + } + } } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -630,10 +693,24 @@ configurerequest(XEvent *e) XSync(dpy, False); } +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'; +} + Monitor * createmon(void) { Monitor *m; + unsigned int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -644,6 +721,21 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + m->pertag->gaps[i] = gappx; + } + return m; } @@ -658,6 +750,35 @@ destroynotify(XEvent *e) } void +deck(Monitor *m) { + unsigned int i, n, h, mw, my, ns, gap_size; + 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; + ns = m->nmaster > 0 ? 2 : 1; + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); + } else { + mw = m->ww; + ns = 1; + } + + gap_size = m->pertag->gaps[m->pertag->curtag]; + for(i = 0, my = gap_size, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; + resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size*(5-ns)/2, h - (2*c->bw), False); + my += HEIGHT(c) + gap_size; + } + else + resize(c, m->wx + mw + gap_size/ns, m->wy + gap_size, m->ww - mw - (2*c->bw) - gap_size*(5-ns)/2, m->wh - (2*c->bw) - 2*gap_size, False); +} + +void detach(Client *c) { Client **tc; @@ -709,25 +830,28 @@ 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]); + drw_setscheme(drw, scheme[SchemeStatus]); tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); } for (c = m->clients; c; c = c->next) { - occ |= c->tags; + occ |= c->tags == 255 ? 0 : c->tags; if (c->isurgent) urg |= c->tags; } x = 0; for (i = 0; i < LENGTH(tags); i++) { + /* do not draw vacant tags */ + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); 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); + /* 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 = TEXTW(m->ltsymbol); @@ -736,12 +860,12 @@ drawbar(Monitor *m) if ((w = m->ww - tw - x) > bh) { if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); 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_setscheme(drw, scheme[SchemeInfoNorm]); drw_rect(drw, x, 0, w, bh, 1, 1); } } @@ -980,7 +1104,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1061,6 +1185,14 @@ manage(Window w, XWindowAttributes *wa) c->y = MAX(c->y, c->mon->wy); c->bw = borderpx; + selmon->tagset[selmon->seltags] &= ~scratchtag; + if (!strcmp(c->name, scratchpadname)) { + c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag; + c->isfloating = True; + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); @@ -1074,10 +1206,11 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); + /* attachaside(c); */ attach(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); + (unsigned char *) &(c->win), 1); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ setclientstate(c, NormalState); if (c->mon == selmon) @@ -1121,8 +1254,12 @@ monocle(Monitor *m) n++; if (n > 0) /* override layout symbol */ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + const int gap_size = m->pertag->gaps[m->pertag->curtag]; 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); + resize(c, m->wx + gap_size, m->wy + gap_size, + m->ww - 2 * c->bw - (2 * gap_size), + m->wh - 2 * c->bw - (2 * gap_size), + 0); } void @@ -1203,6 +1340,16 @@ movemouse(const Arg *arg) } Client * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + +Client * nexttiled(Client *c) { for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); @@ -1427,6 +1574,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + /* attachaside(c); */ attach(c); attachstack(c); focus(NULL); @@ -1508,12 +1656,23 @@ setfullscreen(Client *c, int fullscreen) } void +setgaps(const Arg *arg) +{ + int *gap_size = &selmon->pertag->gaps[selmon->pertag->curtag]; + if ((arg->i == 0) || ((*gap_size) + arg->i < 0)) + *gap_size = 0; + else + *gap_size += arg->i; + arrange(selmon); +} + +void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1532,7 +1691,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1648,9 +1807,7 @@ void spawn(const Arg *arg) { struct sigaction sa; - - if (arg->v == dmenucmd) - dmenumon[0] = '0' + selmon->num; + selmon->tagset[selmon->seltags] &= ~scratchtag; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); @@ -1694,28 +1851,29 @@ tile(Monitor *m) if (n == 0) return; + const int gap_size = m->pertag->gaps[m->pertag->curtag]; if (n > m->nmaster) mw = m->nmaster ? m->ww * m->mfact : 0; else - mw = m->ww; - for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + mw = m->ww - gap_size; + for (i = 0, my = ty = gap_size, 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); + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; + resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size, h - (2*c->bw), 0); if (my + HEIGHT(c) < m->wh) - my += HEIGHT(c); + my += HEIGHT(c) + gap_size; } 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); + h = (m->wh - ty) / (n - i) - gap_size; + resize(c, m->wx + mw + gap_size, m->wy + ty, m->ww - mw - (2*c->bw) - 2*gap_size, h - (2*c->bw), 0); if (ty + HEIGHT(c) < m->wh) - ty += HEIGHT(c); + ty += HEIGHT(c) + gap_size; } } void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1736,6 +1894,28 @@ togglefloating(const Arg *arg) } void +togglescratch(const Arg *arg) +{ + Client *c; + unsigned int found = 0; + + for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); + if (found) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(c)) { + focus(c); + restack(selmon); + } + } else + spawn(arg); +} + +void toggletag(const Arg *arg) { unsigned int newtags; @@ -1754,9 +1934,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2005,8 +2209,10 @@ updatesizehints(Client *c) void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) strcpy(stext, "dwm-"VERSION); + else + copyvalidchars(stext, rawstext); drawbar(selmon); } @@ -2053,11 +2259,37 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2163,3 +2395,164 @@ main(int argc, char *argv[]) XCloseDisplay(dpy); return EXIT_SUCCESS; } + +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++; + } + } + + // All clients rotate + if (arg->i == 2) insertclient(selmon->clients, stail, 0); + if (arg->i == -2) insertclient(stail, selmon->clients, 1); + // Stack xor master rotate + if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); + if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); + if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); + if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); + + // 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); +} + +void +centeredmaster(Monitor *m) +{ + unsigned int i, n, h, mw, mx, my, oty, ety, tw; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize areas */ + mw = m->ww; + mx = 0; + my = 0; + tw = mw; + + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + mw = m->nmaster ? m->ww * m->mfact : 0; + tw = m->ww - mw; + + if (n - m->nmaster > 1) { + /* only one client */ + mx = (m->ww - mw) / 2; + tw = (m->ww - mw) / 2; + } + } + + oty = 0; + ety = 0; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked vertically, in the center + * of the screen */ + h = (m->wh - my) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), + h - (2*c->bw), 0); + my += HEIGHT(c); + } else { + /* stack clients are stacked vertically */ + if ((i - m->nmaster) % 2 ) { + h = (m->wh - ety) / ( (1 + n - i) / 2); + resize(c, m->wx, m->wy + ety, tw - (2*c->bw), + h - (2*c->bw), 0); + ety += HEIGHT(c); + } else { + h = (m->wh - oty) / ((1 + n - i) / 2); + resize(c, m->wx + mx + mw, m->wy + oty, + tw - (2*c->bw), h - (2*c->bw), 0); + oty += HEIGHT(c); + } + } +} + +void +centeredfloatingmaster(Monitor *m) +{ + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize nmaster area */ + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + if (m->ww > m->wh) { + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * 0.9 : 0; + } else { + mh = m->nmaster ? m->wh * m->mfact : 0; + mw = m->nmaster ? m->ww * 0.9 : 0; + } + mx = mxo = (m->ww - mw) / 2; + my = myo = (m->wh - mh) / 2; + } else { + /* go fullscreen if all clients are in the master area */ + mh = m->wh; + mw = m->ww; + mx = mxo = 0; + my = myo = 0; + } + + for(i = tx = 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 */ + w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), + mh - (2*c->bw), 0); + mx += WIDTH(c); + } else { + /* stack clients are stacked horizontally */ + w = (m->ww - tx) / (n - i); + resize(c, m->wx + tx, m->wy, w - (2*c->bw), + m->wh - (2*c->bw), 0); + tx += WIDTH(c); + } +} diff --git a/fibonacci.c b/fibonacci.c new file mode 100644 index 0000000..32cb89b --- /dev/null +++ b/fibonacci.c @@ -0,0 +1,66 @@ +void +fibonacci(Monitor *mon, int s) { + unsigned int i, n, nx, ny, nw, nh; + Client *c; + + for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + nx = mon->wx; + ny = 0; + nw = mon->ww; + nh = mon->wh; + + for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { + if((i % 2 && nh / 2 > 2 * c->bw) + || (!(i % 2) && nw / 2 > 2 * c->bw)) { + if(i < n - 1) { + if(i % 2) + nh /= 2; + else + nw /= 2; + if((i % 4) == 2 && !s) + nx += nw; + else if((i % 4) == 3 && !s) + ny += nh; + } + if((i % 4) == 0) { + if(s) + ny += nh; + else + ny -= nh; + } + else if((i % 4) == 1) + nx += nw; + else if((i % 4) == 2) + ny += nh; + else if((i % 4) == 3) { + if(s) + nx += nw; + else + nx -= nw; + } + if(i == 0) + { + if(n != 1) + nw = mon->ww * mon->mfact; + ny = mon->wy; + } + else if(i == 1) + nw = mon->ww - nw; + i++; + } + resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); + } +} + +void +dwindle(Monitor *mon) { + fibonacci(mon, 1); +} + +void +spiral(Monitor *mon) { + fibonacci(mon, 0); +} diff --git a/gaplessgrid.c b/gaplessgrid.c new file mode 100644 index 0000000..3c9ad76 --- /dev/null +++ b/gaplessgrid.c @@ -0,0 +1,36 @@ +void +gaplessgrid(Monitor *m) { + unsigned int n, cols, rows, cn, rn, i, cx, cy, cw, ch; + 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; + + const int gap_size = m->pertag->gaps[m->pertag->curtag]; + /* window geometries */ + cw = cols ? m->ww / cols : m->ww; + cn = 0; /* current column number */ + rn = 0; /* current row number */ + 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 = (rows ? m->wh / rows : m->wh) - gap_size; + cx = (m->wx + cn*cw) + gap_size; + cy = (m->wy + rn*ch) + gap_size; + resize(c, cx + gap_size, cy + gap_size, cw - 2 * c->bw - gap_size, ch - 2 * c->bw - gap_size, False); + rn++; + if(rn >= rows) { + rn = 0; + cn++; + } + } +} diff --git a/patches/dwm-attachaside-6.1.diff b/patches/dwm-attachaside-6.1.diff new file mode 100644 index 0000000..176cdb0 --- /dev/null +++ b/patches/dwm-attachaside-6.1.diff @@ -0,0 +1,92 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..be7e7a6 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -49,7 +49,8 @@ + #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) + #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +-#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) ++#define ISVISIBLEONTAG(C, T) ((C->tags & T)) ++#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) + #define WIDTH(X) ((X)->w + 2 * (X)->bw) +@@ -147,6 +148,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac + static void arrange(Monitor *m); + static void arrangemon(Monitor *m); + static void attach(Client *c); ++static void attachaside(Client *c); + static void attachstack(Client *c); + static void buttonpress(XEvent *e); + static void checkotherwm(void); +@@ -184,6 +186,7 @@ static void maprequest(XEvent *e); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); ++static Client *nexttagged(Client *c); + static Client *nexttiled(Client *c); + static void pop(Client *); + static void propertynotify(XEvent *e); +@@ -406,6 +409,17 @@ attach(Client *c) + } + + void ++attachaside(Client *c) { ++ Client *at = nexttagged(c); ++ if(!at) { ++ attach(c); ++ return; ++ } ++ c->next = at->next; ++ at->next = c; ++} ++ ++void + attachstack(Client *c) + { + c->snext = c->mon->stack; +@@ -1076,7 +1090,7 @@ manage(Window w, XWindowAttributes *wa) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); +- attach(c); ++ attachaside(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +@@ -1210,6 +1224,16 @@ movemouse(const Arg *arg) + } + + Client * ++nexttagged(Client *c) { ++ Client *walked = c->mon->clients; ++ for(; ++ walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); ++ walked = walked->next ++ ); ++ return walked; ++} ++ ++Client * + nexttiled(Client *c) + { + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); +@@ -1434,7 +1458,7 @@ sendmon(Client *c, Monitor *m) + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +- attach(c); ++ attachaside(c); + attachstack(c); + focus(NULL); + arrange(NULL); +@@ -1891,7 +1915,7 @@ updategeom(void) + m->clients = c->next; + detachstack(c); + c->mon = mons; +- attach(c); ++ attachaside(c); + attachstack(c); + } + if (m == selmon) diff --git a/patches/dwm-centeredmaster-6.1.diff b/patches/dwm-centeredmaster-6.1.diff new file mode 100644 index 0000000..6926892 --- /dev/null +++ b/patches/dwm-centeredmaster-6.1.diff @@ -0,0 +1,142 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..527b214 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -39,6 +39,8 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "|M|", centeredmaster }, ++ { ">M>", centeredfloatingmaster }, + }; + + /* key definitions */ +@@ -74,6 +76,8 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, ++ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/dwm.c b/dwm.c +index 0362114..1e81412 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -233,6 +233,8 @@ static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); ++static void centeredmaster(Monitor *m); ++static void centeredfloatingmaster(Monitor *m); + + /* variables */ + static const char broken[] = "broken"; +@@ -2139,3 +2141,106 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++void ++centeredmaster(Monitor *m) ++{ ++ unsigned int i, n, h, mw, mx, my, oty, ety, tw; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ ++ /* initialize areas */ ++ mw = m->ww; ++ mx = 0; ++ my = 0; ++ tw = mw; ++ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ tw = m->ww - mw; ++ ++ if (n - m->nmaster > 1) { ++ /* only one client */ ++ mx = (m->ww - mw) / 2; ++ tw = (m->ww - mw) / 2; ++ } ++ } ++ ++ oty = 0; ++ ety = 0; ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked vertically, in the center ++ * of the screen */ ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), ++ h - (2*c->bw), 0); ++ my += HEIGHT(c); ++ } else { ++ /* stack clients are stacked vertically */ ++ if ((i - m->nmaster) % 2 ) { ++ h = (m->wh - ety) / ( (1 + n - i) / 2); ++ resize(c, m->wx, m->wy + ety, tw - (2*c->bw), ++ h - (2*c->bw), 0); ++ ety += HEIGHT(c); ++ } else { ++ h = (m->wh - oty) / ((1 + n - i) / 2); ++ resize(c, m->wx + mx + mw, m->wy + oty, ++ tw - (2*c->bw), h - (2*c->bw), 0); ++ oty += HEIGHT(c); ++ } ++ } ++} ++ ++void ++centeredfloatingmaster(Monitor *m) ++{ ++ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ ++ /* initialize nmaster area */ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ if (m->ww > m->wh) { ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ mh = m->nmaster ? m->wh * 0.9 : 0; ++ } else { ++ mh = m->nmaster ? m->wh * m->mfact : 0; ++ mw = m->nmaster ? m->ww * 0.9 : 0; ++ } ++ mx = mxo = (m->ww - mw) / 2; ++ my = myo = (m->wh - mh) / 2; ++ } else { ++ /* go fullscreen if all clients are in the master area */ ++ mh = m->wh; ++ mw = m->ww; ++ mx = mxo = 0; ++ my = myo = 0; ++ } ++ ++ for(i = tx = 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 */ ++ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), ++ mh - (2*c->bw), 0); ++ mx += WIDTH(c); ++ } else { ++ /* stack clients are stacked horizontally */ ++ w = (m->ww - tx) / (n - i); ++ resize(c, m->wx + tx, m->wy, w - (2*c->bw), ++ m->wh - (2*c->bw), 0); ++ tx += WIDTH(c); ++ } ++} diff --git a/patches/dwm-colorbar-6.2.diff b/patches/dwm-colorbar-6.2.diff new file mode 100644 index 0000000..91c067d --- /dev/null +++ b/patches/dwm-colorbar-6.2.diff @@ -0,0 +1,68 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..a516645 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -16,6 +16,11 @@ 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} ++ [SchemeTagsSel] = { col_gray4, col_cyan, "#000000" }, // Tagbar left selected {text,background,not used but cannot be empty} ++ [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, // Tagbar left unselected {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 */ +diff --git a/dwm.c b/dwm.c +index 4465af1..0d1d2f7 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -59,7 +59,7 @@ + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -703,7 +703,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]); ++ drw_setscheme(drw, scheme[SchemeStatus]); + sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); + } +@@ -716,7 +716,7 @@ 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]); ++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); + 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, +@@ -725,17 +725,17 @@ drawbar(Monitor *m) + x += w; + } + w = blw = TEXTW(m->ltsymbol); +- drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_setscheme(drw, scheme[SchemeTagsNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - sw - x) > bh) { + if (m->sel) { +- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); ++ drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); + 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_setscheme(drw, scheme[SchemeInfoNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } diff --git a/patches/dwm-deck-6.2.diff b/patches/dwm-deck-6.2.diff new file mode 100644 index 0000000..b5afed7 --- /dev/null +++ b/patches/dwm-deck-6.2.diff @@ -0,0 +1,77 @@ +From a071b060a1b9b94bcb167b988cf7774ceb870aad Mon Sep 17 00:00:00 2001 +From: Jack Bird <jack.bird@durham.ac.uk> +Date: Mon, 2 Aug 2021 18:44:05 +0100 +Subject: [PATCH] deck patch works with 6.2 + +--- + config.def.h | 2 ++ + dwm.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/config.def.h b/config.def.h +index a2ac963..d865e18 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -42,6 +42,7 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "[D]", deck }, + }; + + /* key definitions */ +@@ -77,6 +78,7 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_r, setlayout, {.v = &layouts[3]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/dwm.c b/dwm.c +index 5e4d494..c67ff91 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -157,6 +157,7 @@ static void configure(Client *c); + static void configurenotify(XEvent *e); + static void configurerequest(XEvent *e); + static Monitor *createmon(void); ++static void deck(Monitor *m); + static void destroynotify(XEvent *e); + static void detach(Client *c); + static void detachstack(Client *c); +@@ -655,6 +656,31 @@ destroynotify(XEvent *e) + unmanage(c, 1); + } + ++void ++deck(Monitor *m) { ++ unsigned int i, n, h, mw, my; ++ 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; ++ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); ++ } ++ else ++ mw = m->ww; ++ for(i = my = 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), False); ++ my += HEIGHT(c); ++ } ++ else ++ resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); ++} ++ + void + detach(Client *c) + { +-- +2.32.0 + diff --git a/patches/dwm-deck-tilegap-6.1.diff b/patches/dwm-deck-tilegap-6.1.diff new file mode 100644 index 0000000..30b6e83 --- /dev/null +++ b/patches/dwm-deck-tilegap-6.1.diff @@ -0,0 +1,55 @@ +From a9e442ec18683e2255ffef74404c283bbb0b6381 Mon Sep 17 00:00:00 2001 +From: aleks <aleks.stier@icloud.com> +Date: Thu, 23 May 2019 23:27:59 +0200 +Subject: [PATCH] Make deck-patch work with the tilegap-patch + +Apply this patch on top of the deck-patch to make it work with the +tilegap-patch. +--- + dwm.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/dwm.c b/dwm.c +index 5b68242..1c17891 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -656,7 +656,7 @@ createmon(void) + + void + deck(Monitor *m) { +- unsigned int i, n, h, mw, my; ++ unsigned int i, n, h, mw, my, ns; + Client *c; + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +@@ -665,18 +665,20 @@ deck(Monitor *m) { + + if(n > m->nmaster) { + mw = m->nmaster ? m->ww * m->mfact : 0; ++ ns = m->nmaster > 0 ? 2 : 1; + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); +- } +- else ++ } else { + mw = m->ww; +- for(i = my = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ ns = 1; ++ } ++ for(i = 0, my = gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); +- my += HEIGHT(c); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gappx; ++ resize(c, m->wx + gappx, m->wy + my, mw - (2*c->bw) - gappx*(5-ns)/2, h - (2*c->bw), False); ++ my += HEIGHT(c) + gappx; + } + else +- resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); ++ resize(c, m->wx + mw + gappx/ns, m->wy + gappx, m->ww - mw - (2*c->bw) - gappx*(5-ns)/2, m->wh - (2*c->bw) - 2*gappx, False); + } + + void +-- +2.21.0 + diff --git a/patches/dwm-fibonacci-6.2.diff b/patches/dwm-fibonacci-6.2.diff new file mode 100644 index 0000000..81bba7a --- /dev/null +++ b/patches/dwm-fibonacci-6.2.diff @@ -0,0 +1,114 @@ +From ec9f55b6005cfa3b025b3d700c61af3ce539d057 Mon Sep 17 00:00:00 2001 +From: Niki Yoshiuchi <nyoshiuchi@gmail.com> +Date: Sat, 18 Apr 2020 09:55:26 -0700 +Subject: [PATCH] Adding the fibonacci layout patch + +--- + config.def.h | 5 ++++ + fibonacci.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+) + create mode 100644 fibonacci.c + +diff --git a/config.def.h b/config.def.h +index 1c0b587..5708487 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -36,11 +36,14 @@ 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 "fibonacci.c" + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "[@]", spiral }, ++ { "[\\]", dwindle }, + }; + + /* key definitions */ +@@ -76,6 +79,8 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_r, setlayout, {.v = &layouts[3]} }, ++ { MODKEY|ShiftMask, XK_r, setlayout, {.v = &layouts[4]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/fibonacci.c b/fibonacci.c +new file mode 100644 +index 0000000..fce0a57 +--- /dev/null ++++ b/fibonacci.c +@@ -0,0 +1,66 @@ ++void ++fibonacci(Monitor *mon, int s) { ++ unsigned int i, n, nx, ny, nw, nh; ++ Client *c; ++ ++ for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); ++ if(n == 0) ++ return; ++ ++ nx = mon->wx; ++ ny = 0; ++ nw = mon->ww; ++ nh = mon->wh; ++ ++ for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { ++ if((i % 2 && nh / 2 > 2 * c->bw) ++ || (!(i % 2) && nw / 2 > 2 * c->bw)) { ++ if(i < n - 1) { ++ if(i % 2) ++ nh /= 2; ++ else ++ nw /= 2; ++ if((i % 4) == 2 && !s) ++ nx += nw; ++ else if((i % 4) == 3 && !s) ++ ny += nh; ++ } ++ if((i % 4) == 0) { ++ if(s) ++ ny += nh; ++ else ++ ny -= nh; ++ } ++ else if((i % 4) == 1) ++ nx += nw; ++ else if((i % 4) == 2) ++ ny += nh; ++ else if((i % 4) == 3) { ++ if(s) ++ nx += nw; ++ else ++ nx -= nw; ++ } ++ if(i == 0) ++ { ++ if(n != 1) ++ nw = mon->ww * mon->mfact; ++ ny = mon->wy; ++ } ++ else if(i == 1) ++ nw = mon->ww - nw; ++ i++; ++ } ++ resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); ++ } ++} ++ ++void ++dwindle(Monitor *mon) { ++ fibonacci(mon, 1); ++} ++ ++void ++spiral(Monitor *mon) { ++ fibonacci(mon, 0); ++} +-- +2.20.1 + diff --git a/patches/dwm-fullgaps-6.2.diff b/patches/dwm-fullgaps-6.2.diff new file mode 100644 index 0000000..7206aec --- /dev/null +++ b/patches/dwm-fullgaps-6.2.diff @@ -0,0 +1,95 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..38d2f6c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,7 @@ + + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int gappx = 5; /* gaps between windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ +@@ -84,6 +85,9 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_minus, setgaps, {.i = -1 } }, ++ { MODKEY, XK_equal, setgaps, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff --git a/dwm.c b/dwm.c +index 4465af1..4363627 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -119,6 +119,7 @@ struct Monitor { + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ ++ int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -199,6 +200,7 @@ static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(const Arg *arg); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); +@@ -638,6 +640,7 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; ++ m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -1497,6 +1500,16 @@ setfullscreen(Client *c, int fullscreen) + } + } + ++void ++setgaps(const Arg *arg) ++{ ++ if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) ++ selmon->gappx = 0; ++ else ++ selmon->gappx += arg->i; ++ arrange(selmon); ++} ++ + void + setlayout(const Arg *arg) + { +@@ -1683,16 +1696,16 @@ tile(Monitor *m) + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else +- mw = m->ww; +- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ mw = m->ww - m->gappx; ++ for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +- my += HEIGHT(c); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; ++ resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); ++ my += HEIGHT(c) + m->gappx; + } else { +- h = (m->wh - ty) / (n - i); +- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); +- ty += HEIGHT(c); ++ h = (m->wh - ty) / (n - i) - m->gappx; ++ resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); ++ ty += HEIGHT(c) + m->gappx; + } + } + +-- +2.20.1 + diff --git a/patches/dwm-gaplessgrid-20160731-56a31dc.diff b/patches/dwm-gaplessgrid-20160731-56a31dc.diff new file mode 100644 index 0000000..4f3bb13 --- /dev/null +++ b/patches/dwm-gaplessgrid-20160731-56a31dc.diff @@ -0,0 +1,43 @@ +URL: http://dwm.suckless.org/patches/gapless_grid +Add gapless grid layout. + +Index: dwm/gaplessgrid.c +=================================================================== +--- /dev/null ++++ dwm/gaplessgrid.c +@@ -0,0 +1,35 @@ ++void ++gaplessgrid(Monitor *m) { ++ unsigned int n, cols, rows, cn, rn, i, cx, cy, cw, ch; ++ 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; ++ ++ /* window geometries */ ++ cw = cols ? m->ww / cols : m->ww; ++ cn = 0; /* current column number */ ++ rn = 0; /* current row number */ ++ 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 = rows ? m->wh / rows : m->wh; ++ cx = m->wx + cn*cw; ++ cy = m->wy + rn*ch; ++ resize(c, cx, cy, cw - 2 * c->bw, ch - 2 * c->bw, False); ++ rn++; ++ if(rn >= rows) { ++ rn = 0; ++ cn++; ++ } ++ } ++} diff --git a/patches/dwm-gaplessgrid-add-gaps.diff b/patches/dwm-gaplessgrid-add-gaps.diff new file mode 100644 index 0000000..1b2b758 --- /dev/null +++ b/patches/dwm-gaplessgrid-add-gaps.diff @@ -0,0 +1,32 @@ +From f84237584b76348058bc205b2e0fcf5dfc005d47 Mon Sep 17 00:00:00 2001 +From: Aryadev Chavali <aryadev@aryadevchavali.com> +Date: Tue, 23 Apr 2024 15:42:04 +0530 +Subject: [PATCH] Add gaps to gapless-grid (properly) + +This adjusts both the x and y of each client now. +--- + gaplessgrid.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/gaplessgrid.c b/gaplessgrid.c +index 09d9ac8..649f656 100644 +--- a/gaplessgrid.c ++++ b/gaplessgrid.c +@@ -22,11 +22,10 @@ gaplessgrid(Monitor *m) { + 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 = (rows ? m->wh / rows : m->wh); +- cx = (m->wx + cn*cw); +- cy = (m->wy + rn*ch); +- resize(c, cx, cy, cw - 2 * c->bw, ch - 2 * c->bw, False); ++ ch = (rows ? m->wh / rows : m->wh) - m->gappx; ++ cx = (m->wx + cn*cw) + m->gappx; ++ cy = (m->wy + rn*ch) + m->gappx; ++ resize(c, cx + m->gappx, cy + m->gappx, cw - 2 * c->bw - m->gappx, ch - 2 * c->bw - m->gappx, False); + rn++; + if(rn >= rows) { + rn = 0; +-- +2.44.0 + diff --git a/patches/dwm-gaplessgrid-pertag-gaps.diff b/patches/dwm-gaplessgrid-pertag-gaps.diff new file mode 100644 index 0000000..e38f041 --- /dev/null +++ b/patches/dwm-gaplessgrid-pertag-gaps.diff @@ -0,0 +1,39 @@ +From d15f7fd6781e8916538efcb62011167d5b540ada Mon Sep 17 00:00:00 2001 +From: Aryadev Chavali <aryadev@aryadevchavali.com> +Date: Wed, 22 May 2024 12:58:03 +0530 +Subject: [PATCH] [PATCH] Adjust gapless grid for pertag gaps + +--- + gaplessgrid.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/gaplessgrid.c b/gaplessgrid.c +index 649f656..3c9ad76 100644 +--- a/gaplessgrid.c ++++ b/gaplessgrid.c +@@ -15,6 +15,7 @@ gaplessgrid(Monitor *m) { + cols = 2; + rows = n/cols; + ++ const int gap_size = m->pertag->gaps[m->pertag->curtag]; + /* window geometries */ + cw = cols ? m->ww / cols : m->ww; + cn = 0; /* current column number */ +@@ -22,10 +23,10 @@ gaplessgrid(Monitor *m) { + 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 = (rows ? m->wh / rows : m->wh) - m->gappx; +- cx = (m->wx + cn*cw) + m->gappx; +- cy = (m->wy + rn*ch) + m->gappx; +- resize(c, cx + m->gappx, cy + m->gappx, cw - 2 * c->bw - m->gappx, ch - 2 * c->bw - m->gappx, False); ++ ch = (rows ? m->wh / rows : m->wh) - gap_size; ++ cx = (m->wx + cn*cw) + gap_size; ++ cy = (m->wy + rn*ch) + gap_size; ++ resize(c, cx + gap_size, cy + gap_size, cw - 2 * c->bw - gap_size, ch - 2 * c->bw - gap_size, False); + rn++; + if(rn >= rows) { + rn = 0; +-- +2.45.0 + diff --git a/patches/dwm-gaps-pertag.diff b/patches/dwm-gaps-pertag.diff new file mode 100644 index 0000000..c5f1221 --- /dev/null +++ b/patches/dwm-gaps-pertag.diff @@ -0,0 +1,163 @@ +From f8aa7781bb890992b75fbc2c9039e2477f1a09c6 Mon Sep 17 00:00:00 2001 +From: Aryadev Chavali <aryadev@aryadevchavali.com> +Date: Wed, 22 May 2024 12:55:50 +0530 +Subject: [PATCH] [PATCH] Gaps are set on a pertag basis + +For each tag there is a gap (set to the default gappx on +construction). When adjusting gaps or arranging a monitor use the +gaps of the currently selected tag. This means I can have gaps +activated in some tags and not activated on others. +--- + dwm.c | 64 ++++++++++++++++++++++++++++++++--------------------------- + 1 file changed, 35 insertions(+), 29 deletions(-) + +diff --git a/dwm.c b/dwm.c +index af66670..c9dd38a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -122,7 +122,6 @@ struct Monitor { + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ +- int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -287,16 +286,19 @@ static Monitor *mons, *selmon; + static Window root, wmcheckwin; + + /* configuration, allows nested code to access above variables */ +-#include "config.h" ++// TODO: Figure out if there is a better way of doing this ++#define TAG_SIZE 9 + struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ +- int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ +- float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ +- unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ +- const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ +- int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ int nmasters[TAG_SIZE + 1]; /* number of windows in master area */ ++ float mfacts[TAG_SIZE + 1]; /* mfacts per tag */ ++ unsigned int sellts[TAG_SIZE + 1]; /* selected layouts */ ++ const Layout *ltidxs[TAG_SIZE + 1][2]; /* matrix of tags and layouts indexes */ ++ int showbars[TAG_SIZE + 1]; /* display bar for the current tag */ ++ int gaps[TAG_SIZE + 1]; /* size of gaps for the current tag*/ + }; + ++#include "config.h" + + static unsigned int scratchtag = 1 << LENGTH(tags); + +@@ -715,7 +717,6 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; +- m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -731,6 +732,7 @@ createmon(void) + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; ++ m->pertag->gaps[i] = gappx; + } + + return m; +@@ -748,7 +750,7 @@ destroynotify(XEvent *e) + + void + deck(Monitor *m) { +- unsigned int i, n, h, mw, my, ns; ++ unsigned int i, n, h, mw, my, ns, gap_size; + Client *c; + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +@@ -763,15 +765,16 @@ deck(Monitor *m) { + mw = m->ww; + ns = 1; + } +- for(i = 0, my = gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ ++ gap_size = m->pertag->gaps[m->pertag->curtag]; ++ for(i = 0, my = gap_size, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gappx; +- resize(c, m->wx + gappx, m->wy + my, mw - (2*c->bw) - gappx*(5-ns)/2, h - (2*c->bw), False); +- if (my + HEIGHT(c) < m->wh) +- my += HEIGHT(c) + m->gappx; ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; ++ resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size*(5-ns)/2, h - (2*c->bw), False); ++ my += HEIGHT(c) + gap_size; + } + else +- resize(c, m->wx + mw + gappx/ns, m->wy + gappx, m->ww - mw - (2*c->bw) - gappx*(5-ns)/2, m->wh - (2*c->bw) - 2*gappx, False); ++ resize(c, m->wx + mw + gap_size/ns, m->wy + gap_size, m->ww - mw - (2*c->bw) - gap_size*(5-ns)/2, m->wh - (2*c->bw) - 2*gap_size, False); + } + + void +@@ -1243,10 +1246,11 @@ monocle(Monitor *m) + n++; + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); ++ const int gap_size = m->pertag->gaps[m->pertag->curtag]; + for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) +- resize(c, m->wx + m->gappx, m->wy + m->gappx, +- m->ww - 2 * c->bw - (2 * m->gappx), +- m->wh - 2 * c->bw - (2 * m->gappx), ++ resize(c, m->wx + gap_size, m->wy + gap_size, ++ m->ww - 2 * c->bw - (2 * gap_size), ++ m->wh - 2 * c->bw - (2 * gap_size), + 0); + } + +@@ -1646,10 +1650,11 @@ setfullscreen(Client *c, int fullscreen) + void + setgaps(const Arg *arg) + { +- if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) +- selmon->gappx = 0; ++ int *gap_size = &selmon->pertag->gaps[selmon->pertag->curtag]; ++ if ((arg->i == 0) || ((*gap_size) + arg->i < 0)) ++ *gap_size = 0; + else +- selmon->gappx += arg->i; ++ *gap_size += arg->i; + arrange(selmon); + } + +@@ -1839,21 +1844,22 @@ tile(Monitor *m) + if (n == 0) + return; + ++ const int gap_size = m->pertag->gaps[m->pertag->curtag]; + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else +- mw = m->ww - m->gappx; +- for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ mw = m->ww - gap_size; ++ for (i = 0, my = ty = gap_size, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; +- resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; ++ resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size, h - (2*c->bw), 0); + if (my + HEIGHT(c) < m->wh) +- my += HEIGHT(c) + m->gappx; ++ my += HEIGHT(c) + gap_size; + } else { +- h = (m->wh - ty) / (n - i) - m->gappx; +- resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); ++ h = (m->wh - ty) / (n - i) - gap_size; ++ resize(c, m->wx + mw + gap_size, m->wy + ty, m->ww - mw - (2*c->bw) - 2*gap_size, h - (2*c->bw), 0); + if (ty + HEIGHT(c) < m->wh) +- ty += HEIGHT(c) + m->gappx; ++ ty += HEIGHT(c) + gap_size; + } + } + +-- +2.45.0 + diff --git a/patches/dwm-hide_vacant_tags-6.2.diff b/patches/dwm-hide_vacant_tags-6.2.diff new file mode 100644 index 0000000..a981b23 --- /dev/null +++ b/patches/dwm-hide_vacant_tags-6.2.diff @@ -0,0 +1,55 @@ +diff --git a/dwm.c b/dwm.c +index 4465af1..c4aa3de 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -416,7 +416,7 @@ attachstack(Client *c) + void + buttonpress(XEvent *e) + { +- unsigned int i, x, click; ++ unsigned int i, x, click, occ = 0; + Arg arg = {0}; + Client *c; + Monitor *m; +@@ -431,9 +431,14 @@ buttonpress(XEvent *e) + } + if (ev->window == selmon->barwin) { + i = x = 0; +- do ++ for (c = m->clients; c; c = c->next) ++ occ |= c->tags == 255 ? 0 : c->tags; ++ do { ++ /* do not reserve space for vacant tags */ ++ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) ++ continue; + x += TEXTW(tags[i]); +- while (ev->x >= x && ++i < LENGTH(tags)); ++ } while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; +@@ -709,19 +714,19 @@ drawbar(Monitor *m) + } + + for (c = m->clients; c; c = c->next) { +- occ |= c->tags; ++ occ |= c->tags == 255 ? 0 : c->tags; + if (c->isurgent) + urg |= c->tags; + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { ++ /* do not draw vacant tags */ ++ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) ++ continue; ++ + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + 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); + x += w; + } + w = blw = TEXTW(m->ltsymbol); diff --git a/patches/dwm-inplacerotate-6.2.diff b/patches/dwm-inplacerotate-6.2.diff new file mode 100644 index 0000000..d331368 --- /dev/null +++ b/patches/dwm-inplacerotate-6.2.diff @@ -0,0 +1,108 @@ +From 75012a6ab9cc1b6c319af7f4ae7d682b16a66ce3 Mon Sep 17 00:00:00 2001 +From: Miles Alan <m@milesalan.com> +Date: Sun, 26 Apr 2020 16:05:43 -0500 +Subject: [PATCH] Add inplacerotate fn to rotate all, master, or stacks clients + inplace + +CW (+2) or CCW (-2) Rotates all windows. +CW (+1) or CCW (-1) Rotates master xor stack windows (depending on focus). + +Focus position stays 'in-place' so the area of the screen you are focused +on remains unchanged. +--- + config.def.h | 4 ++++ + dwm.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 63 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..9bcb792 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -66,6 +66,10 @@ static Key keys[] = { + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, ++ { MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, ++ { MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, ++ { MODKEY|ShiftMask, XK_h, inplacerotate, {.i = +2} }, ++ { MODKEY|ShiftMask, XK_l, inplacerotate, {.i = -2} }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, +diff --git a/dwm.c b/dwm.c +index 4465af1..3930680 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -175,6 +175,7 @@ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); + static void incnmaster(const Arg *arg); ++static void inplacerotate(const Arg *arg); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); +@@ -2147,3 +2148,61 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++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++; ++ } ++ } ++ ++ // All clients rotate ++ if (arg->i == 2) insertclient(selmon->clients, stail, 0); ++ if (arg->i == -2) insertclient(stail, selmon->clients, 1); ++ // Stack xor master rotate ++ if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); ++ if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); ++ if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); ++ if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); ++ ++ // 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); ++} +-- +2.23.1 + diff --git a/patches/dwm-monocle-gaps.diff b/patches/dwm-monocle-gaps.diff new file mode 100644 index 0000000..83698af --- /dev/null +++ b/patches/dwm-monocle-gaps.diff @@ -0,0 +1,29 @@ +From 09ed528140fadeb5641bf6871f92ce83aa3d4880 Mon Sep 17 00:00:00 2001 +From: Aryadev Chavali <aryadev@aryadevchavali.com> +Date: Tue, 23 Apr 2024 16:12:19 +0530 +Subject: [PATCH] Monocle now uses gaps + +Just added gaps to moncole layout. +--- + dwm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/dwm.c b/dwm.c +index 19ee521..a6aaace 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1244,8 +1244,10 @@ monocle(Monitor *m) + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + 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); ++ resize(c, m->wx + m->gappx, m->wy + m->gappx, ++ m->ww - 2 * c->bw - (2 * m->gappx), ++ m->wh - 2 * c->bw - (2 * m->gappx), ++ 0); + } + + void +-- +2.44.0 + diff --git a/patches/dwm-pertag-6.2.diff b/patches/dwm-pertag-6.2.diff new file mode 100644 index 0000000..d753727 --- /dev/null +++ b/patches/dwm-pertag-6.2.diff @@ -0,0 +1,177 @@ +diff --git a/dwm.c b/dwm.c +index 4465af1..6474055 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +131,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -271,6 +273,15 @@ static Window root, wmcheckwin; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -631,6 +642,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ unsigned int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -641,6 +653,20 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ m->pertag = ecalloc(1, sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ ++ for (i = 0; i <= LENGTH(tags); i++) { ++ m->pertag->nmasters[i] = m->nmaster; ++ m->pertag->mfacts[i] = m->mfact; ++ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ m->pertag->showbars[i] = m->showbar; ++ } ++ + return m; + } + +@@ -966,7 +992,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1501,9 +1527,9 @@ void + setlayout(const Arg *arg) + { + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1522,7 +1548,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1699,7 +1725,7 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +@@ -1738,9 +1764,33 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; ++ ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i = 0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } +@@ -2035,11 +2085,37 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { ++ int i; ++ unsigned int tmptag; ++ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ ++ if (arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i = 0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } diff --git a/patches/dwm-remove-dmenu.diff b/patches/dwm-remove-dmenu.diff new file mode 100644 index 0000000..f0fac2a --- /dev/null +++ b/patches/dwm-remove-dmenu.diff @@ -0,0 +1,30 @@ +From 6fc206cb7cce97f947d121b5ce80b665bcc37a6f Mon Sep 17 00:00:00 2001 +From: Aryadev Chavali <aryadev@aryadevchavali.com> +Date: Wed, 22 May 2024 12:27:59 +0530 +Subject: [PATCH] [Patch] Remove dmenu functionality from DWM + +If using an external keyboard client such as sxhkdrc then dwm has no +business or need to spawn something like dmenu. +--- + config.h | 2 -- + dwm.c | 4 +--- + 2 files changed, 1 insertion(+), 5 deletions(-) + +diff --git a/dwm.c b/dwm.c +index a6aaace..af66670 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1795,10 +1795,7 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) +- dmenumon[0] = '0' + selmon->num; +- else if (arg->v == statuscmd) { ++ if (arg->v == statuscmd) { + statuscmd[2] = statuscmds[statuscmdn]; + setenv("BUTTON", lastbutton, 1); + } +-- +2.45.0 + diff --git a/patches/dwm-scratchpad-6.2.diff b/patches/dwm-scratchpad-6.2.diff new file mode 100644 index 0000000..2062263 --- /dev/null +++ b/patches/dwm-scratchpad-6.2.diff @@ -0,0 +1,90 @@ +diff -up a/config.def.h b/config.def.h +--- a/config.def.h 2019-06-06 21:23:27.006661784 +0200 ++++ b/config.def.h 2019-06-20 15:05:59.083102462 +0200 +@@ -58,11 +58,14 @@ static const Layout layouts[] = { + 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 }; + static const char *termcmd[] = { "st", NULL }; ++static const char scratchpadname[] = "scratchpad"; ++static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; + + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, ++ { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, +diff -up a/dwm.c b/dwm.c +--- a/dwm.c 2019-06-06 21:23:27.023328450 +0200 ++++ b/dwm.c 2019-06-20 15:07:01.089767947 +0200 +@@ -213,6 +213,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglescratch(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -273,6 +274,8 @@ static Window root, wmcheckwin; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++static unsigned int scratchtag = 1 << LENGTH(tags); ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -1052,6 +1055,14 @@ manage(Window w, XWindowAttributes *wa) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + ++ selmon->tagset[selmon->seltags] &= ~scratchtag; ++ if (!strcmp(c->name, scratchpadname)) { ++ c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag; ++ c->isfloating = True; ++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); ++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); ++ } ++ + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); +@@ -1661,6 +1672,7 @@ spawn(const Arg *arg) + { + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; ++ selmon->tagset[selmon->seltags] &= ~scratchtag; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); +@@ -1748,6 +1760,28 @@ togglefloating(const Arg *arg) + } + + void ++togglescratch(const Arg *arg) ++{ ++ Client *c; ++ unsigned int found = 0; ++ ++ for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); ++ if (found) { ++ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; ++ if (newtagset) { ++ selmon->tagset[selmon->seltags] = newtagset; ++ focus(NULL); ++ arrange(selmon); ++ } ++ if (ISVISIBLE(c)) { ++ focus(c); ++ restack(selmon); ++ } ++ } else ++ spawn(arg); ++} ++ ++void + toggletag(const Arg *arg) + { + unsigned int newtags; diff --git a/patches/dwm-statuscmd-20210405-67d76bd.diff b/patches/dwm-statuscmd-20210405-67d76bd.diff new file mode 100644 index 0000000..4b26420 --- /dev/null +++ b/patches/dwm-statuscmd-20210405-67d76bd.diff @@ -0,0 +1,208 @@ +From f58c7e4fd05ec13383518ccd51663167d45e92d0 Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:02:58 +0200 +Subject: [PATCH] [statuscmd] Signal mouse button and click location to status + monitor + +--- + config.def.h | 6 +++- + dwm.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 100 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..154a59b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -54,6 +54,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 }; +@@ -103,7 +105,9 @@ static Button buttons[] = { + { 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.c b/dwm.c +index b0b3466..d871457 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -172,6 +172,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); +@@ -206,6 +207,7 @@ 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); +@@ -238,6 +240,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; ++static int statusw; ++static int statussig; ++static pid_t statuspid = -1; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -422,6 +427,7 @@ buttonpress(XEvent *e) + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; ++ char *text, *s, ch; + + click = ClkRootWin; + /* focus monitor if necessary */ +@@ -440,9 +446,23 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - statusw) { ++ x = selmon->ww - statusw; + click = ClkStatusText; +- else ++ statussig = 0; ++ for (text = s = stext; *s && x <= ev->x; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ if (x >= ev->x) ++ break; ++ statussig = ch; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -704,9 +724,24 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ ++ char *text, *s, ch; + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ ++ x = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ tw = TEXTW(text) - lrpad; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ x += tw; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ tw = TEXTW(text) - lrpad + 2; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ tw = statusw; + } + + for (c = m->clients; c; c = c->next) { +@@ -872,6 +907,30 @@ getatomprop(Client *c, Atom prop) + return atom; + } + ++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); ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1637,6 +1696,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) + { +@@ -1990,8 +2063,25 @@ updatesizehints(Client *c) + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { + strcpy(stext, "dwm-"VERSION); ++ statusw = TEXTW(stext) - lrpad + 2; ++ } else { ++ char *text, *s, ch; ++ ++ statusw = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ statusw += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ statusw += TEXTW(text) - lrpad + 2; ++ ++ } + drawbar(selmon); + } + +-- +2.31.0 + diff --git a/patches/dwm-statuscmd-6.2.diff b/patches/dwm-statuscmd-6.2.diff new file mode 100644 index 0000000..c825749 --- /dev/null +++ b/patches/dwm-statuscmd-6.2.diff @@ -0,0 +1,142 @@ +From 2761ad72b4b8a80e434e7eba1a24676119ab666d Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Sat, 18 Apr 2020 01:41:03 +0200 +Subject: [PATCH] statuscmd: run shell commands based on mouse button and + position when clicking statusbar + +--- + config.def.h | 8 +++++++- + dwm.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 51 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..5cd7efa 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -59,6 +59,10 @@ 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 }; + static const char *termcmd[] = { "st", NULL }; + ++/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */ ++static char *statuscmds[] = { "notify-send Mouse$BUTTON" }; ++static char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL }; ++ + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +@@ -103,7 +107,9 @@ static Button buttons[] = { + { 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, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index 4465af1..d35d173 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -156,6 +156,7 @@ static void clientmessage(XEvent *e); + static void configure(Client *c); + static void configurenotify(XEvent *e); + static void configurerequest(XEvent *e); ++static void copyvalidchars(char *text, char *rawtext); + static Monitor *createmon(void); + static void destroynotify(XEvent *e); + static void detach(Client *c); +@@ -237,6 +238,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; ++static char rawstext[256]; ++static int statuscmdn; ++static char lastbutton[] = "-"; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -421,6 +425,7 @@ buttonpress(XEvent *e) + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; ++ *lastbutton = '0' + ev->button; + + click = ClkRootWin; + /* focus monitor if necessary */ +@@ -439,9 +444,26 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) ++ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) { + click = ClkStatusText; +- else ++ ++ char *text = rawstext; ++ int i = -1; ++ char ch; ++ statuscmdn = 0; ++ while (text[++i]) { ++ if ((unsigned char)text[i] < ' ') { ++ ch = text[i]; ++ text[i] = '\0'; ++ x += TEXTW(text) - lrpad; ++ text[i] = ch; ++ text += i+1; ++ i = -1; ++ if (x >= ev->x) break; ++ if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -627,6 +649,19 @@ configurerequest(XEvent *e) + XSync(dpy, False); + } + ++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'; ++} ++ + Monitor * + createmon(void) + { +@@ -1641,6 +1676,10 @@ spawn(const Arg *arg) + { + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; ++ else if (arg->v == statuscmd) { ++ statuscmd[2] = statuscmds[statuscmdn]; ++ setenv("BUTTON", lastbutton, 1); ++ } + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); +@@ -1987,8 +2026,10 @@ updatesizehints(Client *c) + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) + strcpy(stext, "dwm-"VERSION); ++ else ++ copyvalidchars(stext, rawstext); + drawbar(selmon); + } + +-- +2.26.1 + |