neodotfiles/source/dwm/patches/dwm-placemouse-6.2.diff

260 lines
7.6 KiB
Diff
Raw Normal View History

2024-08-05 19:19:42 +00:00
From ca26e9e8533da2657fcbb56a407eb5a6d2735719 Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Fri, 28 Jun 2024 10:08:07 +0200
Subject: [PATCH] placemouse patch
---
config.def.h | 12 +++-
dwm.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..86f878a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -104,7 +104,17 @@ static Button buttons[] = {
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
- { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ /* placemouse options, choose which feels more natural:
+ * 0 - tiled position is relative to mouse cursor
+ * 1 - tiled postiion is relative to window center
+ * 2 - mouse pointer warps to window center
+ *
+ * The moveorplace uses movemouse or placemouse depending on the floating state
+ * of the selected client. Set up individual keybindings for the two if you want
+ * to control these separately (i.e. to retain the feature to move a tiled window
+ * into a floating position).
+ */
+ { ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
diff --git a/dwm.c b/dwm.c
index 4465af1..8a0ae73 100644
--- a/dwm.c
+++ b/dwm.c
@@ -49,6 +49,8 @@
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \
+ * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
@@ -93,6 +95,7 @@ struct Client {
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ int beingmoved;
Client *next;
Client *snext;
Monitor *mon;
@@ -183,10 +186,13 @@ static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
+static void moveorplace(const Arg *arg);
static Client *nexttiled(Client *c);
+static void placemouse(const Arg *arg);
static void pop(Client *);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
+static Client *recttoclient(int x, int y, int w, int h);
static Monitor *recttomon(int x, int y, int w, int h);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
@@ -1132,6 +1138,14 @@ motionnotify(XEvent *e)
mon = m;
}
+void
+moveorplace(const Arg *arg) {
+ if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)))
+ movemouse(arg);
+ else
+ placemouse(arg);
+}
+
void
movemouse(const Arg *arg)
{
@@ -1199,6 +1213,139 @@ nexttiled(Client *c)
return c;
}
+void
+placemouse(const Arg *arg)
+{
+ int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0;
+ Client *c, *r = NULL, *at, *prevr;
+ Monitor *m;
+ XEvent ev;
+ XWindowAttributes wa;
+ Time lasttime = 0;
+ int attachmode, prevattachmode;
+ attachmode = prevattachmode = -1;
+
+ if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */
+ return;
+ if (c->isfullscreen) /* no support placing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ prevr = c;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ return;
+
+ c->isfloating = 0;
+ c->beingmoved = 1;
+
+ XGetWindowAttributes(dpy, c->win, &wa);
+ ocx = wa.x;
+ ocy = wa.y;
+
+ if (arg->i == 2) // warp cursor to client center
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2);
+
+ if (!getrootptr(&x, &y))
+ 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 / 60))
+ continue;
+ lasttime = ev.xmotion.time;
+
+ nx = ocx + (ev.xmotion.x - x);
+ ny = ocy + (ev.xmotion.y - y);
+
+ if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap))
+ freemove = 1;
+
+ if (freemove)
+ XMoveWindow(dpy, c->win, nx, ny);
+
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon)
+ selmon = m;
+
+ if (arg->i == 1) { // tiled position is relative to the client window center point
+ px = nx + wa.width / 2;
+ py = ny + wa.height / 2;
+ } else { // tiled position is relative to the mouse cursor
+ px = ev.xmotion.x;
+ py = ev.xmotion.y;
+ }
+
+ r = recttoclient(px, py, 1, 1);
+
+ if (!r || r == c)
+ break;
+
+ attachmode = 0; // below
+ if (((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)) {
+ if (abs(r->y - py) < r->h / 2)
+ attachmode = 1; // above
+ } else if (abs(r->x - px) < r->w / 2)
+ attachmode = 1; // above
+
+ if ((r && r != prevr) || (attachmode != prevattachmode)) {
+ detachstack(c);
+ detach(c);
+ if (c->mon != r->mon) {
+ arrangemon(c->mon);
+ c->tags = r->mon->tagset[r->mon->seltags];
+ }
+
+ c->mon = r->mon;
+ r->mon->sel = r;
+
+ if (attachmode) {
+ if (r == r->mon->clients)
+ attach(c);
+ else {
+ for (at = r->mon->clients; at->next != r; at = at->next);
+ c->next = at->next;
+ at->next = c;
+ }
+ } else {
+ c->next = r->next;
+ r->next = c;
+ }
+
+ attachstack(c);
+ arrangemon(r->mon);
+ prevr = r;
+ prevattachmode = attachmode;
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) {
+ detach(c);
+ detachstack(c);
+ arrangemon(c->mon);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags];
+ attach(c);
+ attachstack(c);
+ selmon = m;
+ }
+
+ focus(c);
+ c->beingmoved = 0;
+
+ if (nx != -9999)
+ resize(c, nx, ny, c->w, c->h, 0);
+ arrangemon(c->mon);
+}
+
void
pop(Client *c)
{
@@ -1251,6 +1398,21 @@ quit(const Arg *arg)
running = 0;
}
+Client *
+recttoclient(int x, int y, int w, int h)
+{
+ Client *c, *r = NULL;
+ int a, area = 0;
+
+ for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) {
+ if ((a = INTERSECTC(x, y, w, h, c)) > area) {
+ area = a;
+ r = c;
+ }
+ }
+ return r;
+}
+
Monitor *
recttomon(int x, int y, int w, int h)
{
@@ -1281,6 +1443,10 @@ resizeclient(Client *c, int x, int y, int w, int h)
c->oldy = c->y; c->y = wc.y = y;
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
+
+ if (c->beingmoved)
+ return;
+
wc.border_width = c->bw;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c);
--
2.45.2