diff --git a/README.md b/README.md index e9bde08..5cc9935 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t ### Changelog: +2020-03-23 - Added stacker patch + 2020-03-21 - Reworked a series of layouts to re-allocate remaining pixels following an even (or cfacts) split with the aim of presenting a pixel perfect layout. This affects the following layouts: tile, bstack, bstackhoriz, centered master, centered floating master, columns, deck, and corresponding flextile-deluxe layouts 2020-02-11 - Added swaptags and vtcolor patches @@ -297,6 +299,9 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t - [spawn_cwd](https://dwm.suckless.org/patches/spawn_cwd/) - spawns programs from currently focused client's working directory + - [stacker](https://dwm.suckless.org/patches/stacker/) + - provides comprehensive utilities for managing the client stack + - [statusallmons](https://dwm.suckless.org/patches/statuspadding/) - this patch draws and updates the statusbar on all monitors diff --git a/config.def.h b/config.def.h index 308822a..6fd948a 100644 --- a/config.def.h +++ b/config.def.h @@ -629,6 +629,17 @@ static const Layout layouts[] = { { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, #endif // COMBO_PATCH / SWAPTAGS_PATCH +#if STACKER_PATCH +#define STACKKEYS(MOD,ACTION) \ + { MOD, XK_j, ACTION##stack, {.i = INC(+1) } }, \ + { MOD, XK_k, ACTION##stack, {.i = INC(-1) } }, \ + { MOD, XK_s, ACTION##stack, {.i = PREVSEL } }, \ + { MOD, XK_w, ACTION##stack, {.i = 0 } }, \ + { MOD, XK_e, ACTION##stack, {.i = 1 } }, \ + { MOD, XK_a, ACTION##stack, {.i = 2 } }, \ + { MOD, XK_z, ACTION##stack, {.i = -1 } }, +#endif // STACKER_PATCH + #if HOLDBAR_PATCH #define HOLDKEY 0 // replace 0 with the keysym to activate holdbar #endif // HOLDBAR_PATCH @@ -673,8 +684,13 @@ static Key keys[] = { { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, #endif // SCRATCHPAD_PATCH { MODKEY, XK_b, togglebar, {0} }, + #if STACKER_PATCH + STACKKEYS(MODKEY, focus) + STACKKEYS(MODKEY|ShiftMask, push) + #else { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, + #endif // STACKER_PATCH #if SWAPFOCUS_PATCH && PERTAG_PATCH { MODKEY, XK_s, swapfocus, {.i = -1 } }, #endif // SWAPFOCUS_PATCH @@ -741,7 +757,7 @@ static Key keys[] = { { MODKEY|ShiftMask, XK_backslash, shiftview, { .i = +1 } }, #endif // SHIFTVIEW_PATCH #if AWESOMEBAR_PATCH - { MODKEY, XK_z, showhideclient, {0} }, + { MODKEY|ControlMask, XK_z, showhideclient, {0} }, #endif // AWESOMEBAR_PATCH { MODKEY|ShiftMask, XK_c, killclient, {0} }, #if KILLUNSEL_PATCH diff --git a/dwm.c b/dwm.c index 5c14ada..88b9b84 100644 --- a/dwm.c +++ b/dwm.c @@ -342,7 +342,9 @@ static void expose(XEvent *e); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); +#if !STACKER_PATCH static void focusstack(const Arg *arg); +#endif // STACKER_PATCH static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); @@ -1784,6 +1786,7 @@ focusmon(const Arg *arg) #endif // WARP_PATCH } +#if !STACKER_PATCH void focusstack(const Arg *arg) { @@ -1813,6 +1816,7 @@ focusstack(const Arg *arg) restack(selmon); } } +#endif // STACKER_PATCH Atom getatomprop(Client *c, Atom prop) diff --git a/patch/include.c b/patch/include.c index d7c3178..723147b 100644 --- a/patch/include.c +++ b/patch/include.c @@ -101,6 +101,9 @@ #include "sortscreens.c" #endif // XINERAMA #endif +#if STACKER_PATCH +#include "stacker.c" +#endif #if STICKY_PATCH #include "sticky.c" #endif diff --git a/patch/include.h b/patch/include.h index aa77397..d97b503 100644 --- a/patch/include.h +++ b/patch/include.h @@ -101,6 +101,9 @@ #include "sortscreens.h" #endif // XINERAMA #endif +#if STACKER_PATCH +#include "stacker.h" +#endif #if STICKY_PATCH #include "sticky.h" #endif diff --git a/patch/stacker.c b/patch/stacker.c new file mode 100644 index 0000000..db6da82 --- /dev/null +++ b/patch/stacker.c @@ -0,0 +1,74 @@ +void +focusstack(const Arg *arg) +{ + int i = stackpos(arg); + Client *c, *p; + + if (i < 0) + return; + + #if ALWAYSFULLSCREEN_PATCH + if (!selmon->sel || selmon->sel->isfullscreen) + return; + #endif // ALWAYSFULLSCREEN_PATCH + + for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c)); + i -= ISVISIBLE(c) ? 1 : 0, p = c, c = c->next); + focus(c ? c : p); + restack(selmon); +} + +void +pushstack(const Arg *arg) +{ + int i = stackpos(arg); + Client *sel = selmon->sel, *c, *p; + + if (i < 0) + return; + else if (i == 0) { + detach(sel); + attach(sel); + } + else { + for (p = NULL, c = selmon->clients; c; p = c, c = c->next) + if (!(i -= (ISVISIBLE(c) && c != sel))) + break; + c = c ? c : p; + detach(sel); + sel->next = c->next; + c->next = sel; + } + arrange(selmon); +} + +int +stackpos(const Arg *arg) +{ + int n, i; + Client *c, *l; + + if (!selmon->clients) + return -1; + + if (arg->i == PREVSEL) { + for (l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext); + if (!l) + return -1; + for (i = 0, c = selmon->clients; c != l; i += ISVISIBLE(c) ? 1 : 0, c = c->next); + return i; + } + else if (ISINC(arg->i)) { + if(!selmon->sel) + return -1; + for (i = 0, c = selmon->clients; c != selmon->sel; i += ISVISIBLE(c) ? 1 : 0, c = c->next); + for (n = i; c; n += ISVISIBLE(c) ? 1 : 0, c = c->next); + return MOD(i + GETINC(arg->i), n); + } + else if (arg->i < 0) { + for(i = 0, c = selmon->clients; c; i += ISVISIBLE(c) ? 1 : 0, c = c->next); + return MAX(i + arg->i, 0); + } + else + return arg->i; +} \ No newline at end of file diff --git a/patch/stacker.h b/patch/stacker.h new file mode 100644 index 0000000..0a06461 --- /dev/null +++ b/patch/stacker.h @@ -0,0 +1,10 @@ +#define GETINC(X) ((X) - 2000) +#define INC(X) ((X) + 2000) +#define ISINC(X) ((X) > 1000 && (X) < 3000) +#define PREVSEL 3000 +#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M)) +#define TRUNC(X,A,B) (MAX((A), MIN((X), (B)))) + +static void focusstack(const Arg *arg); +static void pushstack(const Arg *arg); +static int stackpos(const Arg *arg); \ No newline at end of file diff --git a/patches.def.h b/patches.def.h index 0e2cc92..176ab90 100644 --- a/patches.def.h +++ b/patches.def.h @@ -424,6 +424,16 @@ */ #define SPAWNCMD_PATCH 0 +/* This patch provides comprehensive utilities for managing the client stack, providing + * keyboard shortcuts for focusing or placing a client at specific positions in the stack. + * Note that the default keybindings for this patch have been changed in dwm-flexipatch + * due to the many conflicts with other patches. As it provides similar functionality to the + * swapfocus patch it also uses the MOD+s shortcut to focus the previously selected client, + * thus note a conflict between these two patches. + * https://dwm.suckless.org/patches/stacker/ + */ +#define STACKER_PATCH 0 + /* This patch draws and updates the statusbar on all monitors. * https://dwm.suckless.org/patches/statusallmons/ */ @@ -459,7 +469,7 @@ #define SWALLOW_PATCH 0 /* This patch depends on the pertag patch and makes it possible to switch focus with a single - * shortcut (mod-s) instead of having to think if you should use mod-j or mod-k for reaching + * shortcut (MOD+s) instead of having to think if you should use MOD+j or MOD+k for reaching * the previously used window. * This patch depends on the following additional libraries: * - libxcb