|
@@ -53,6 +53,8 @@
|
|
|
#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 HIDDEN(C) ((getstate(C->win) == IconicState))
|
|
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
|
@@ -175,6 +177,7 @@ struct Client {
|
|
|
unsigned int tags;
|
|
|
int isfixed, iscentered, isfloating, isurgent, neverfocus, oldstate,
|
|
|
isfullscreen;
|
|
|
+ int beingmoved;
|
|
|
Client *next;
|
|
|
Client *snext;
|
|
|
Monitor *mon;
|
|
@@ -263,10 +266,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 removesystrayicon(Client *i);
|
|
|
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
|
@@ -2025,6 +2031,14 @@ void 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) {
|
|
|
int x, y, ocx, ocy, nx, ny;
|
|
|
Client *c;
|
|
@@ -2089,6 +2103,139 @@ Client *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) {
|
|
|
detach(c);
|
|
|
attach(c);
|
|
@@ -2160,6 +2307,22 @@ void quit(const Arg *arg) {
|
|
|
system("killall bar");
|
|
|
}
|
|
|
|
|
|
+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) {
|
|
|
Monitor *m, *r = selmon;
|
|
|
int a, area = 0;
|
|
@@ -2207,7 +2370,11 @@ void resizeclient(Client *c, int x, int y, int w, int h) {
|
|
|
c->w = wc.width = w;
|
|
|
c->oldh = c->h;
|
|
|
c->h = wc.height = h;
|
|
|
- wc.border_width = c->bw;
|
|
|
+
|
|
|
+ if (c->beingmoved)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wc.border_width = c->bw;
|
|
|
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth,
|
|
|
&wc);
|
|
|
configure(c);
|
|
@@ -3012,7 +3179,7 @@ void updateclientlist() {
|
|
|
void updatecurrentdesktop(void){
|
|
|
long rawdata[] = { selmon->tagset[selmon->seltags] };
|
|
|
int i=0;
|
|
|
- while(*rawdata >> i+1){
|
|
|
+ while(*rawdata >> (i+1)){
|
|
|
i++;
|
|
|
}
|
|
|
long data[] = { i };
|