From cf83ca2326c9ea6dffa0757fb4805d1f33cfa207 Mon Sep 17 00:00:00 2001 From: Niky Kovalski 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