commit efa06680da77bcca77995840d20adab824ecec04
parent bd337776bdf316967c18877f324857039a8ad43d
Author: Niky Kovalski <nikykovalski@gmail.com>
Date: Tue, 29 Sep 2026 05:12:54 -0400
[dwm][patch] movestackmouse
A patch that adds a function which drags the focused window and places
it on a tiled layout without toggling the float state.
Diffstat:
2 files changed, 171 insertions(+), 0 deletions(-)
diff --git a/dwm.suckless.org/patches/movestackmouse/dwm-movestackmouse-20260929-44dbc68.diff b/dwm.suckless.org/patches/movestackmouse/dwm-movestackmouse-20260929-44dbc68.diff
@@ -0,0 +1,156 @@
+From cf83ca2326c9ea6dffa0757fb4805d1f33cfa207 Mon Sep 17 00:00:00 2001
+From: Niky Kovalski <nikykovalski@gmail.com>
+Date: Tue, 29 Sep 2026 01:10:41 -0400
+Subject: [PATCH] movestackmouse
+
+Move focused window while dragging. Tiled windows will not be toggled to
+the floating state.
+---
+ config.def.h | 1 +
+ dwm.1 | 3 ++
+ dwm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 86 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 81c3fc0..206261b 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -107,6 +107,7 @@ static const Button buttons[] = {
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
++ { ClkClientWin, MODKEY|ShiftMask, Button1, movestackmouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+diff --git a/dwm.1 b/dwm.1
+index ddc8321..de4bf91 100644
+--- a/dwm.1
++++ b/dwm.1
+@@ -144,6 +144,9 @@ Add/remove all windows with nth tag to/from the view.
+ Quit dwm.
+ .SS Mouse commands
+ .TP
++.B Mod1\-Shift\-Button1
++Move focused window while dragging. Tiled windows will not be toggled to the floating state.
++.TP
+ .B Mod1\-Button1
+ Move focused window while dragging. Tiled windows will be toggled to the floating state.
+ .TP
+diff --git a/dwm.c b/dwm.c
+index ab3a84c..3e9229e 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -146,6 +146,8 @@ 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 attachafter(Client *c, Client *t);
++static void attachbefore(Client *c, Client *t);
+ static void attachstack(Client *c);
+ static void buttonpress(XEvent *e);
+ static void checkotherwm(void);
+@@ -183,6 +185,7 @@ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
++static void movestackmouse(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *c);
+ static void propertynotify(XEvent *e);
+@@ -407,6 +410,25 @@ attach(Client *c)
+ c->mon->clients = c;
+ }
+
++void
++attachafter(Client *c, Client *t)
++{
++ c->next = t->next;
++ t->next = c;
++}
++
++void
++attachbefore(Client *c, Client *t)
++{
++ Client **tc;
++
++ for (tc = &t->mon->clients; *tc && *tc != t; tc = &(*tc)->next);
++ if (*tc)
++ c->next = (*tc)->next;
++ c->next = *tc;
++ *tc = c;
++}
++
+ void
+ attachstack(Client *c)
+ {
+@@ -1202,6 +1224,66 @@ movemouse(const Arg *arg)
+ }
+ }
+
++void
++movestackmouse(const Arg *arg)
++{
++ Client *c, *t;
++ Monitor *m;
++ XEvent ev;
++ Time lasttime = 0;
++ int isfound = 0;
++
++ if (!(c = selmon->sel))
++ return;
++ if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
++ return;
++ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { /* fallback to movemouse */
++ movemouse(NULL);
++ return;
++ }
++ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
++ return;
++ do {
++ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
++ switch(ev.type) {
++ case ConfigureRequest:
++ case Expose:
++ case MapRequest:
++ handler[ev.type](&ev);
++ break;
++ case MotionNotify:
++ if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
++ continue;
++ lasttime = ev.xmotion.time;
++ isfound = 0;
++
++ for (t = nexttiled(c->mon->clients); t; t = nexttiled(t->next)) {
++ if (t == c) {
++ isfound = 1;
++ continue;
++ }
++ if (ev.xmotion.x_root >= t->x &&
++ ev.xmotion.x_root < t->x + t->w + 2 * t->bw &&
++ ev.xmotion.y_root >= t->y &&
++ ev.xmotion.y_root < t->y + t->h + 2 * t->bw) {
++ detach(c);
++ isfound ? attachafter(c, t) : attachbefore(c, t);
++ focus(c);
++ arrange(c->mon);
++ break;
++ }
++ }
++ break;
++ }
++ } while (ev.type != ButtonRelease);
++ XUngrabPointer(dpy, CurrentTime);
++ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
++ selmon = m;
++ focus(NULL);
++ }
++}
++
+ Client *
+ nexttiled(Client *c)
+ {
+--
+2.55.0
+
diff --git a/dwm.suckless.org/patches/movestackmouse/index.md b/dwm.suckless.org/patches/movestackmouse/index.md
@@ -0,0 +1,15 @@
+movestackmouse
+==============
+
+Description
+-----------
+A patch that adds a function which drags the focused window and places
+it on a tiled layout without toggling the float state.
+
+Download
+--------
+* [dwm-movestackmouse-20260929-44dbc68.diff](dwm-movestackmouse-20260929-44dbc68.diff)
+
+Author
+------
+* Niky Kovalski - <nikykovalski@gmail.com>