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->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); } 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; }