placemouse.c (3326B)
1 void 2 moveorplace(const Arg *arg) { 3 if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating))) 4 movemouse(arg); 5 else 6 placemouse(arg); 7 } 8 9 void 10 placemouse(const Arg *arg) 11 { 12 int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0; 13 Client *c, *r = NULL, *at, *prevr; 14 Monitor *m; 15 XEvent ev; 16 XWindowAttributes wa; 17 Time lasttime = 0; 18 int attachmode, prevattachmode; 19 attachmode = prevattachmode = -1; 20 21 if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */ 22 return; 23 if (c->isfullscreen) /* no support placing fullscreen windows by mouse */ 24 return; 25 restack(selmon); 26 prevr = c; 27 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 28 None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 29 return; 30 31 c->isfloating = 0; 32 c->beingmoved = 1; 33 34 XGetWindowAttributes(dpy, c->win, &wa); 35 ocx = wa.x; 36 ocy = wa.y; 37 38 if (arg->i == 2) // warp cursor to client center 39 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2); 40 41 if (!getrootptr(&x, &y)) 42 return; 43 44 do { 45 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 46 switch (ev.type) { 47 case ConfigureRequest: 48 case Expose: 49 case MapRequest: 50 handler[ev.type](&ev); 51 break; 52 case MotionNotify: 53 if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate_placemouse)) 54 continue; 55 lasttime = ev.xmotion.time; 56 57 nx = ocx + (ev.xmotion.x - x); 58 ny = ocy + (ev.xmotion.y - y); 59 60 if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap)) 61 freemove = 1; 62 63 if (freemove) 64 XMoveWindow(dpy, c->win, nx, ny); 65 66 if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon) 67 selmon = m; 68 69 if (arg->i == 1) { // tiled position is relative to the client window center point 70 px = nx + wa.width / 2; 71 py = ny + wa.height / 2; 72 } else { // tiled position is relative to the mouse cursor 73 px = ev.xmotion.x; 74 py = ev.xmotion.y; 75 } 76 77 r = recttoclient(px, py, 1, 1, 0); 78 79 if (!r || r == c) 80 break; 81 82 if ((((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w) 83 && (abs(r->y - py) < r->h / 2)) || (abs(r->x - px) < r->w / 2)) 84 attachmode = 1; // above 85 else 86 attachmode = 0; // below 87 88 if ((r && r != prevr) || (attachmode != prevattachmode)) { 89 detachstack(c); 90 detach(c); 91 if (c->mon != r->mon) { 92 arrangemon(c->mon); 93 c->tags = r->mon->tagset[r->mon->seltags]; 94 } 95 96 c->mon = r->mon; 97 r->mon->sel = r; 98 99 if (attachmode) { 100 if (r == r->mon->clients) 101 attach(c); 102 else { 103 for (at = r->mon->clients; at->next != r; at = at->next); 104 c->next = at->next; 105 at->next = c; 106 } 107 } else { 108 c->next = r->next; 109 r->next = c; 110 } 111 112 attachstack(c); 113 arrangemon(r->mon); 114 prevr = r; 115 prevattachmode = attachmode; 116 } 117 break; 118 } 119 } while (ev.type != ButtonRelease); 120 XUngrabPointer(dpy, CurrentTime); 121 122 if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) { 123 detach(c); 124 detachstack(c); 125 arrangemon(c->mon); 126 c->mon = m; 127 c->tags = m->tagset[m->seltags]; 128 attach(c); 129 attachstack(c); 130 selmon = m; 131 } 132 133 focus(c); 134 c->beingmoved = 0; 135 136 if (nx != -9999) 137 resize(c, nx, ny, c->w, c->h, 0); 138 arrangemon(c->mon); 139 }