dwm/patch/placemouse.c
2021-06-14 08:54:23 +03:00

154 lines
3.4 KiB
C

void
moveorplace(const Arg *arg) {
if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)))
movemouse(arg);
else
placemouse(arg);
}
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;
if ((((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)
&& (abs(r->y - py) < r->h / 2)) || (abs(r->x - px) < r->w / 2))
attachmode = 1; // above
else
attachmode = 0; // below
if ((r && r != prevr) || (attachmode != prevattachmode)) {
detachstack(c);
detach(c);
if (c->mon != r->mon)
arrangemon(c->mon);
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);
}
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;
}