dwm-placemouse-6.3.diff (7743B)
1 From 399cb51f86d259d0d15d2db767d31c9e030c0528 Mon Sep 17 00:00:00 2001 2 From: Bakkeby <[email protected]> 3 Date: Mon, 10 Jan 2022 13:18:37 +0100 4 Subject: [PATCH] Adding placemouse patch 5 6 --- 7 config.def.h | 12 +++- 8 dwm.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++ 9 2 files changed, 177 insertions(+), 1 deletion(-) 10 11 diff --git a/config.def.h b/config.def.h 12 index a2ac963..caaebf6 100644 13 --- a/config.def.h 14 +++ b/config.def.h 15 @@ -105,7 +105,17 @@ static Button buttons[] = { 16 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, 17 { ClkWinTitle, 0, Button2, zoom, {0} }, 18 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 19 - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 20 + /* placemouse options, choose which feels more natural: 21 + * 0 - tiled position is relative to mouse cursor 22 + * 1 - tiled postiion is relative to window center 23 + * 2 - mouse pointer warps to window center 24 + * 25 + * The moveorplace uses movemouse or placemouse depending on the floating state 26 + * of the selected client. Set up individual keybindings for the two if you want 27 + * to control these separately (i.e. to retain the feature to move a tiled window 28 + * into a floating position). 29 + */ 30 + { ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} }, 31 { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, 32 { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, 33 { ClkTagBar, 0, Button1, view, {0} }, 34 diff --git a/dwm.c b/dwm.c 35 index a96f33c..5d57e18 100644 36 --- a/dwm.c 37 +++ b/dwm.c 38 @@ -49,6 +49,8 @@ 39 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 40 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 41 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 42 +#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \ 43 + * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y))) 44 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 45 #define LENGTH(X) (sizeof X / sizeof X[0]) 46 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 47 @@ -93,6 +95,7 @@ struct Client { 48 int bw, oldbw; 49 unsigned int tags; 50 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; 51 + int beingmoved; 52 Client *next; 53 Client *snext; 54 Monitor *mon; 55 @@ -184,10 +187,13 @@ static void maprequest(XEvent *e); 56 static void monocle(Monitor *m); 57 static void motionnotify(XEvent *e); 58 static void movemouse(const Arg *arg); 59 +static void moveorplace(const Arg *arg); 60 static Client *nexttiled(Client *c); 61 +static void placemouse(const Arg *arg); 62 static void pop(Client *); 63 static void propertynotify(XEvent *e); 64 static void quit(const Arg *arg); 65 +static Client *recttoclient(int x, int y, int w, int h); 66 static Monitor *recttomon(int x, int y, int w, int h); 67 static void resize(Client *c, int x, int y, int w, int h, int interact); 68 static void resizeclient(Client *c, int x, int y, int w, int h); 69 @@ -1136,6 +1142,14 @@ motionnotify(XEvent *e) 70 mon = m; 71 } 72 73 +void 74 +moveorplace(const Arg *arg) { 75 + if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating))) 76 + movemouse(arg); 77 + else 78 + placemouse(arg); 79 +} 80 + 81 void 82 movemouse(const Arg *arg) 83 { 84 @@ -1203,6 +1217,139 @@ nexttiled(Client *c) 85 return c; 86 } 87 88 +void 89 +placemouse(const Arg *arg) 90 +{ 91 + int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0; 92 + Client *c, *r = NULL, *at, *prevr; 93 + Monitor *m; 94 + XEvent ev; 95 + XWindowAttributes wa; 96 + Time lasttime = 0; 97 + int attachmode, prevattachmode; 98 + attachmode = prevattachmode = -1; 99 + 100 + if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */ 101 + return; 102 + if (c->isfullscreen) /* no support placing fullscreen windows by mouse */ 103 + return; 104 + restack(selmon); 105 + prevr = c; 106 + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 107 + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 108 + return; 109 + 110 + c->isfloating = 0; 111 + c->beingmoved = 1; 112 + 113 + XGetWindowAttributes(dpy, c->win, &wa); 114 + ocx = wa.x; 115 + ocy = wa.y; 116 + 117 + if (arg->i == 2) // warp cursor to client center 118 + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2); 119 + 120 + if (!getrootptr(&x, &y)) 121 + return; 122 + 123 + do { 124 + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 125 + switch (ev.type) { 126 + case ConfigureRequest: 127 + case Expose: 128 + case MapRequest: 129 + handler[ev.type](&ev); 130 + break; 131 + case MotionNotify: 132 + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) 133 + continue; 134 + lasttime = ev.xmotion.time; 135 + 136 + nx = ocx + (ev.xmotion.x - x); 137 + ny = ocy + (ev.xmotion.y - y); 138 + 139 + if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap)) 140 + freemove = 1; 141 + 142 + if (freemove) 143 + XMoveWindow(dpy, c->win, nx, ny); 144 + 145 + if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon) 146 + selmon = m; 147 + 148 + if (arg->i == 1) { // tiled position is relative to the client window center point 149 + px = nx + wa.width / 2; 150 + py = ny + wa.height / 2; 151 + } else { // tiled position is relative to the mouse cursor 152 + px = ev.xmotion.x; 153 + py = ev.xmotion.y; 154 + } 155 + 156 + r = recttoclient(px, py, 1, 1); 157 + 158 + if (!r || r == c) 159 + break; 160 + 161 + attachmode = 0; // below 162 + if (((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)) { 163 + if (abs(r->y - py) < r->h / 2) 164 + attachmode = 1; // above 165 + } else if (abs(r->x - px) < r->w / 2) 166 + attachmode = 1; // above 167 + 168 + if ((r && r != prevr) || (attachmode != prevattachmode)) { 169 + detachstack(c); 170 + detach(c); 171 + if (c->mon != r->mon) { 172 + arrangemon(c->mon); 173 + c->tags = r->mon->tagset[r->mon->seltags]; 174 + } 175 + 176 + c->mon = r->mon; 177 + r->mon->sel = r; 178 + 179 + if (attachmode) { 180 + if (r == r->mon->clients) 181 + attach(c); 182 + else { 183 + for (at = r->mon->clients; at->next != r; at = at->next); 184 + c->next = at->next; 185 + at->next = c; 186 + } 187 + } else { 188 + c->next = r->next; 189 + r->next = c; 190 + } 191 + 192 + attachstack(c); 193 + arrangemon(r->mon); 194 + prevr = r; 195 + prevattachmode = attachmode; 196 + } 197 + break; 198 + } 199 + } while (ev.type != ButtonRelease); 200 + XUngrabPointer(dpy, CurrentTime); 201 + 202 + if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) { 203 + detach(c); 204 + detachstack(c); 205 + arrangemon(c->mon); 206 + c->mon = m; 207 + c->tags = m->tagset[m->seltags]; 208 + attach(c); 209 + attachstack(c); 210 + selmon = m; 211 + } 212 + 213 + focus(c); 214 + c->beingmoved = 0; 215 + 216 + if (nx != -9999) 217 + resize(c, nx, ny, c->w, c->h, 0); 218 + arrangemon(c->mon); 219 +} 220 + 221 void 222 pop(Client *c) 223 { 224 @@ -1255,6 +1402,21 @@ quit(const Arg *arg) 225 running = 0; 226 } 227 228 +Client * 229 +recttoclient(int x, int y, int w, int h) 230 +{ 231 + Client *c, *r = NULL; 232 + int a, area = 0; 233 + 234 + for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) { 235 + if ((a = INTERSECTC(x, y, w, h, c)) > area) { 236 + area = a; 237 + r = c; 238 + } 239 + } 240 + return r; 241 +} 242 + 243 Monitor * 244 recttomon(int x, int y, int w, int h) 245 { 246 @@ -1285,6 +1447,10 @@ resizeclient(Client *c, int x, int y, int w, int h) 247 c->oldy = c->y; c->y = wc.y = y; 248 c->oldw = c->w; c->w = wc.width = w; 249 c->oldh = c->h; c->h = wc.height = h; 250 + 251 + if (c->beingmoved) 252 + return; 253 + 254 wc.border_width = c->bw; 255 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); 256 configure(c); 257 -- 258 2.19.1 259