dwm-movestackmouse-20260929-44dbc68.diff (4423B)
1 From cf83ca2326c9ea6dffa0757fb4805d1f33cfa207 Mon Sep 17 00:00:00 2001 2 From: Niky Kovalski <nikykovalski@gmail.com> 3 Date: Tue, 29 Sep 2026 01:10:41 -0400 4 Subject: [PATCH] movestackmouse 5 6 Move focused window while dragging. Tiled windows will not be toggled to 7 the floating state. 8 --- 9 config.def.h | 1 + 10 dwm.1 | 3 ++ 11 dwm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 3 files changed, 86 insertions(+) 13 14 diff --git a/config.def.h b/config.def.h 15 index 81c3fc0..206261b 100644 16 --- a/config.def.h 17 +++ b/config.def.h 18 @@ -107,6 +107,7 @@ static const Button buttons[] = { 19 { ClkWinTitle, 0, Button2, zoom, {0} }, 20 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 21 { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 22 + { ClkClientWin, MODKEY|ShiftMask, Button1, movestackmouse, {0} }, 23 { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, 24 { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, 25 { ClkTagBar, 0, Button1, view, {0} }, 26 diff --git a/dwm.1 b/dwm.1 27 index ddc8321..de4bf91 100644 28 --- a/dwm.1 29 +++ b/dwm.1 30 @@ -144,6 +144,9 @@ Add/remove all windows with nth tag to/from the view. 31 Quit dwm. 32 .SS Mouse commands 33 .TP 34 +.B Mod1\-Shift\-Button1 35 +Move focused window while dragging. Tiled windows will not be toggled to the floating state. 36 +.TP 37 .B Mod1\-Button1 38 Move focused window while dragging. Tiled windows will be toggled to the floating state. 39 .TP 40 diff --git a/dwm.c b/dwm.c 41 index ab3a84c..3e9229e 100644 42 --- a/dwm.c 43 +++ b/dwm.c 44 @@ -146,6 +146,8 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac 45 static void arrange(Monitor *m); 46 static void arrangemon(Monitor *m); 47 static void attach(Client *c); 48 +static void attachafter(Client *c, Client *t); 49 +static void attachbefore(Client *c, Client *t); 50 static void attachstack(Client *c); 51 static void buttonpress(XEvent *e); 52 static void checkotherwm(void); 53 @@ -183,6 +185,7 @@ static void maprequest(XEvent *e); 54 static void monocle(Monitor *m); 55 static void motionnotify(XEvent *e); 56 static void movemouse(const Arg *arg); 57 +static void movestackmouse(const Arg *arg); 58 static Client *nexttiled(Client *c); 59 static void pop(Client *c); 60 static void propertynotify(XEvent *e); 61 @@ -407,6 +410,25 @@ attach(Client *c) 62 c->mon->clients = c; 63 } 64 65 +void 66 +attachafter(Client *c, Client *t) 67 +{ 68 + c->next = t->next; 69 + t->next = c; 70 +} 71 + 72 +void 73 +attachbefore(Client *c, Client *t) 74 +{ 75 + Client **tc; 76 + 77 + for (tc = &t->mon->clients; *tc && *tc != t; tc = &(*tc)->next); 78 + if (*tc) 79 + c->next = (*tc)->next; 80 + c->next = *tc; 81 + *tc = c; 82 +} 83 + 84 void 85 attachstack(Client *c) 86 { 87 @@ -1202,6 +1224,66 @@ movemouse(const Arg *arg) 88 } 89 } 90 91 +void 92 +movestackmouse(const Arg *arg) 93 +{ 94 + Client *c, *t; 95 + Monitor *m; 96 + XEvent ev; 97 + Time lasttime = 0; 98 + int isfound = 0; 99 + 100 + if (!(c = selmon->sel)) 101 + return; 102 + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ 103 + return; 104 + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { /* fallback to movemouse */ 105 + movemouse(NULL); 106 + return; 107 + } 108 + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 109 + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 110 + return; 111 + do { 112 + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 113 + switch(ev.type) { 114 + case ConfigureRequest: 115 + case Expose: 116 + case MapRequest: 117 + handler[ev.type](&ev); 118 + break; 119 + case MotionNotify: 120 + if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) 121 + continue; 122 + lasttime = ev.xmotion.time; 123 + isfound = 0; 124 + 125 + for (t = nexttiled(c->mon->clients); t; t = nexttiled(t->next)) { 126 + if (t == c) { 127 + isfound = 1; 128 + continue; 129 + } 130 + if (ev.xmotion.x_root >= t->x && 131 + ev.xmotion.x_root < t->x + t->w + 2 * t->bw && 132 + ev.xmotion.y_root >= t->y && 133 + ev.xmotion.y_root < t->y + t->h + 2 * t->bw) { 134 + detach(c); 135 + isfound ? attachafter(c, t) : attachbefore(c, t); 136 + focus(c); 137 + arrange(c->mon); 138 + break; 139 + } 140 + } 141 + break; 142 + } 143 + } while (ev.type != ButtonRelease); 144 + XUngrabPointer(dpy, CurrentTime); 145 + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { 146 + selmon = m; 147 + focus(NULL); 148 + } 149 +} 150 + 151 Client * 152 nexttiled(Client *c) 153 { 154 -- 155 2.55.0 156