aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.def.h4
-rw-r--r--dwm-shif-tools-6.2.diff198
-rw-r--r--dwm.c68
3 files changed, 269 insertions, 1 deletions
diff --git a/config.def.h b/config.def.h
index ed736ea..0097501 100644
--- a/config.def.h
+++ b/config.def.h
@@ -281,6 +281,10 @@ static const Key keys[] = {
{ MODKEY, XK_minus, setgaps, {.i = -1 } },
{ MODKEY, XK_equal, setgaps, {.i = +1 } },
{ MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } },
+ { MODKEY|ControlMask, XK_h, shiftview, { .i = -1 } },
+ { MODKEY|ControlMask, XK_l, shiftview, { .i = +1 } },
+ { MODKEY|METAKEY, XK_h, shiftboth, { .i = -1 } },
+ { MODKEY|METAKEY, XK_l, shiftboth, { .i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
diff --git a/dwm-shif-tools-6.2.diff b/dwm-shif-tools-6.2.diff
new file mode 100644
index 0000000..4535342
--- /dev/null
+++ b/dwm-shif-tools-6.2.diff
@@ -0,0 +1,198 @@
+From d57c8508c9f26be40667d402a2daaa2b27ae759f Mon Sep 17 00:00:00 2001
+From: explosion-mental <explosion0mental@gmail.com>
+Date: Wed, 11 Aug 2021 21:05:44 -0500
+Subject: [PATCH] shift-tools - shifttag, moves the current selected client to
+ the adjacent tag - shifttagclients, moves the current selected client to the
+ adjacent tag that has at least one client else acts as shifttag -
+ shiftview, view adjacent tag - shiftviewclients, view the closes tag that has
+ a client. If none acts as shiftview - shiftboth, shifttag and shiftview.
+ Basically moves the window to the next/prev tag and follows it. -
+ shiftswaptags, its a shift implementation on the swaptags function (see
+ https://github.com/moizifty/DWM-Build/blob/65379c62640788881486401a0d8c79333751b02f/config.h#L48
+ for more details), which in short 'swaps tags' (swaps all clients with
+ the clients on the adjacent tag). A pretty useful example of this is
+ chosing a tag empty and sending all your clients to that tag. - swapfunction
+ is the 'helper' function for the shiftswaptags. remember that these functions
+ **shift**, which means you can go from tag 1 to 9 or 9 to 1. Also remember
+ that the default argument is 1 and you can change it.
+
+---
+ config.def.h | 9 ++++
+ shift-tools.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 144 insertions(+)
+ create mode 100644 shift-tools.c
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..1390d17 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -58,9 +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 };
++#include "shift-tools.c"
+
+ static Key keys[] = {
+ /* modifier key function argument */
++ { MODKEY, XK_o, shiftviewclients, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_o, shiftview, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_i, shiftview, { .i = -1 } },
++ { MODKEY, XK_i, shiftviewclients, { .i = -1 } },
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
+@@ -69,6 +74,10 @@ static Key keys[] = {
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
++ { MODKEY|ShiftMask, XK_h, shiftboth, { .i = -1 } },
++ { MODKEY|ControlMask, XK_h, shiftswaptags, { .i = -1 } },
++ { MODKEY|ControlMask, XK_l, shiftswaptags, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_l, shiftboth, { .i = +1 } },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+diff --git a/shift-tools.c b/shift-tools.c
+new file mode 100644
+index 0000000..cf130c8
+--- /dev/null
++++ b/shift-tools.c
+@@ -0,0 +1,135 @@
++/* Sends a window to the next/prev tag */
++void
++shifttag(const Arg *arg)
++{
++ Arg shifted;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++
++ if (arg->i > 0) /* left circular shift */
++ shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
++ else /* right circular shift */
++ shifted.ui = (shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i));
++ tag(&shifted);
++}
++/* Sends a window to the next/prev tag that has a client, else it moves it to the next/prev one. */
++void
++shifttagclients(const Arg *arg)
++{
++
++ Arg shifted;
++ Client *c;
++ unsigned int tagmask = 0;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++ for (c = selmon->clients; c; c = c->next)
++ if (!(c->tags))
++ tagmask = tagmask | c->tags;
++
++
++ if (arg->i > 0) /* left circular shift */
++ do {
++ shifted.ui = (shifted.ui << arg->i)
++ | (shifted.ui >> (LENGTH(tags) - arg->i));
++ } while (tagmask && !(shifted.ui & tagmask));
++ else /* right circular shift */
++ do {
++ shifted.ui = (shifted.ui >> (- arg->i)
++ | shifted.ui << (LENGTH(tags) + arg->i));
++ } while (tagmask && !(shifted.ui & tagmask));
++ tag(&shifted);
++}
++/* Navigate to the next/prev tag */
++void
++shiftview(const Arg *arg)
++{
++ Arg shifted;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++ if (arg->i > 0) /* left circular shift */
++ shifted.ui = (shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i));
++ else /* right circular shift */
++ shifted.ui = (shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i));
++ view(&shifted);
++}
++/* Navigate to the next/prev tag that has a client, else moves it to the next/prev tag */
++void
++shiftviewclients(const Arg *arg)
++{
++ Arg shifted;
++ Client *c;
++ unsigned int tagmask = 0;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++ for (c = selmon->clients; c; c = c->next)
++ if (!(c->tags))
++ tagmask = tagmask | c->tags;
++
++
++ if (arg->i > 0) /* left circular shift */
++ do {
++ shifted.ui = (shifted.ui << arg->i)
++ | (shifted.ui >> (LENGTH(tags) - arg->i));
++ } while (tagmask && !(shifted.ui & tagmask));
++ else /* right circular shift */
++ do {
++ shifted.ui = (shifted.ui >> (- arg->i)
++ | shifted.ui << (LENGTH(tags) + arg->i));
++ } while (tagmask && !(shifted.ui & tagmask));
++ view(&shifted);
++}
++/* move the current active window to the next/prev tag and view it. More like following the window */
++void
++shiftboth(const Arg *arg)
++{
++ Arg shifted;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++ if (arg->i > 0) /* left circular shift */
++ shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
++ else /* right circular shift */
++ shifted.ui = ((shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i)));
++ tag(&shifted);
++ view(&shifted);
++}
++//helper function for shiftswaptags.
++//see: https://github.com/moizifty/DWM-Build/blob/65379c62640788881486401a0d8c79333751b02f/config.h#L48
++void
++swaptags(const Arg *arg)
++{
++ Client *c;
++ unsigned int newtag = arg->ui & TAGMASK;
++ unsigned int curtag = selmon->tagset[selmon->seltags];
++
++ if (newtag == curtag || !curtag || (curtag & (curtag-1)))
++ return;
++
++ for (c = selmon->clients; c != NULL; c = c->next) {
++ if ((c->tags & newtag) || (c->tags & curtag))
++ c->tags ^= curtag ^ newtag;
++
++ if (!c->tags)
++ c->tags = newtag;
++ }
++
++ //move to the swaped tag
++ //selmon->tagset[selmon->seltags] = newtag;
++
++ focus(NULL);
++ arrange(selmon);
++}
++/* swaps "tags" (all the clients) with the next/prev tag. */
++void
++shiftswaptags(const Arg *arg)
++{
++ Arg shifted;
++ shifted.ui = selmon->tagset[selmon->seltags];
++
++ if (arg->i > 0) /* left circular shift */
++ shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
++ else /* right circular shift */
++ shifted.ui = ((shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i)));
++ swaptags(&shifted);
++ // uncomment if you also want to "go" (view) the tag where the the clients are going
++ //view(&shifted);
++}
+--
+2.32.0
+
diff --git a/dwm.c b/dwm.c
index 1218622..a477d6f 100644
--- a/dwm.c
+++ b/dwm.c
@@ -85,7 +85,7 @@ enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */
enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText,
@@ -252,6 +252,7 @@ static void scan(void);
static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
+static void setclienttagprop(Client *c);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setgaps(const Arg *arg);
@@ -259,6 +260,8 @@ static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void seturgent(Client *c, int urg);
+static void shiftboth(const Arg *arg);
+static void shiftview(const Arg *arg);
static void showhide(Client *c);
static void sighup(int unused);
static void sigterm(int unused);
@@ -1626,6 +1629,26 @@ manage(Window w, XWindowAttributes *wa)
updatewindowtype(c);
updatesizehints(c);
updatewmhints(c);
+ {
+ int format;
+ unsigned long *data, n, extra;
+ Monitor *m;
+ Atom atom;
+ if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL,
+ &atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2) {
+ c->tags = *data;
+ for (m = mons; m; m = m->next) {
+ if (m->num == *(data+1)) {
+ c->mon = m;
+ break;
+ }
+ }
+ }
+ if (n > 0)
+ XFree(data);
+ }
+ setclienttagprop(c);
+
c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
c->sfx = c->x;
@@ -2330,6 +2353,7 @@ sendmon(Client *c, Monitor *m)
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
attachBelow(c);
attachstack(c);
+ setclienttagprop(c);
focus(NULL);
arrange(NULL);
}
@@ -2508,6 +2532,7 @@ setup(void)
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+ netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
@@ -2542,6 +2567,7 @@ setup(void)
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
XDeleteProperty(dpy, root, netatom[NetClientList]);
+ XDeleteProperty(dpy, root, netatom[NetClientInfo]);
/* select events */
wa.cursor = cursor[CurNormal]->cursor;
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
@@ -2567,6 +2593,33 @@ seturgent(Client *c, int urg)
}
void
+shiftboth(const Arg *arg)
+{
+ Arg shifted;
+ shifted.ui = selmon->tagset[selmon->seltags];
+
+ if (arg->i > 0) /* left circular shift */
+ shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
+ else /* right circular shift */
+ shifted.ui = ((shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i)));
+ tag(&shifted);
+ view(&shifted);
+}
+
+void
+shiftview(const Arg *arg)
+{
+ Arg shifted;
+ shifted.ui = selmon->tagset[selmon->seltags];
+
+ if (arg->i > 0) /* left circular shift */
+ shifted.ui = (shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i));
+ else /* right circular shift */
+ shifted.ui = (shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i));
+ view(&shifted);
+}
+
+void
showhide(Client *c)
{
if (!c)
@@ -2681,12 +2734,23 @@ spawn(const Arg *arg)
die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
}
}
+void
+setclienttagprop(Client *c)
+{
+ long data[] = { (long) c->tags, (long) c->mon->num };
+ XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 2);
+}
void
tag(const Arg *arg)
{
+ Client *c;
+
if (selmon->sel && arg->ui & TAGMASK) {
+ c = selmon->sel;
selmon->sel->tags = arg->ui & TAGMASK;
+ setclienttagprop(c);
focus(NULL);
arrange(selmon);
}
@@ -2725,6 +2789,7 @@ tagothermon(const Arg *arg, int dir)
sendmon(sel, newmon);
if (arg->ui & TAGMASK) {
sel->tags = arg->ui & TAGMASK;
+ setclienttagprop(selmon->sel);
focus(NULL);
arrange(newmon);
}
@@ -2866,6 +2931,7 @@ toggletag(const Arg *arg)
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
if (newtags) {
selmon->sel->tags = newtags;
+ setclienttagprop(selmon->sel);
focus(NULL);
arrange(selmon);
}