Hi,
I received no comments to my previous e-mail on the subject from
13 Dec, so now that I have a machine with two monitors I just
implemented it. Now, excuse me for ranting: I understand that
the people responsible for cwm are busy, but I'd like some
feedback on the patches I've sent to the list so far. Even two
characters 'N' and 'o' would suffice. I've maintained my own
window manager fork before, and I don't have a problem to do the
same with cwm, but I'd like to know whether to keep spamming you
with unsolicited code. Meanwhile I put my patches on the web:
http://www.vygo.net/vadik/cwm/
Rant over, now onto the patch.
cwm makes a client active only when the mouse pointer enters the
window. Thus, once a client is off screen and another becomes
active, it's lost forever.
The attached patch is a bit big, as it does several things (will
split if interested):
- In lots of places, it deals with regions (that's CRTCs (or
outputs?) for XRandr affictionados, and monitors for you and
me) instead of screens.
- Clients now have regions associated with them and cached in
client_ctx. The client's region is:
- the region containing the centre of the window;
- failing that, the region that has the biggest overlapping
area with the window;
- if the window is fully off screen, the region closest to it
by Manhattan distance (edge to edge).
- When a client is moved or resized (whether by the user or by
XConfigureRequestEvent), it's forced to remain "visible", i.e.,
overlapping with a region. The client's associated region is
recalculated on every move or resize.
- When a client is created, its place is calculated to be within
the region of its desired position if position hints are set,
or within the working are of the region containing the mouse
pointer otherwise. If it's bigger than the region, it will at
least overlap with it.
- I kept cwm's behaviour of not minding the gap during
placement calculations when position hints are set, which
makes sense for panels.
- Size hints are now respected.
- Tiling now works on regions.
- When screen geometry changes (XRandR monitors are added,
removed or rotated), for every old region a matching new region
is found (using the same method as for clients' regions), and
all clients within it are migrated to the new region, keeping
their relative positions within the region, with rounding
errors. Full screen and maximized clients are resized
accordingly. Tiled regions may cease to be tiled.
- A relative position is something like:
{ (client.x - region.x) / (region.w - client.w),
(client.y - region.y) / (region.h - client.h) }
(whatever's in the corner or in the centre stays there).
- I added bind commands to move clients between regions, as most
of the code was already there.
This patch does not handle XShape, so non-rectangular clients can
still be moved off screen.
Vadik.
--
An artist is never ahead of his time, but most people are far
behind theirs.
-- Varese
Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.311
diff -u -r1.311 calmwm.h
--- calmwm.h 12 Nov 2015 21:28:03 -0000 1.311
+++ calmwm.h 18 Jul 2016 20:40:12 -0000
@@ -141,6 +141,7 @@
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) group_entry;
struct screen_ctx *sc;
+ struct region_ctx *rc;
struct group_ctx *gc;
Window win;
Colormap colormap;
@@ -218,9 +219,7 @@
struct region_ctx {
TAILQ_ENTRY(region_ctx) entry;
int num;
- struct geom area;
struct geom view; /* viewable area */
- struct geom work; /* workable area, gap-applied */
};
TAILQ_HEAD(region_ctx_q, region_ctx);
@@ -394,8 +393,11 @@
void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_htile(struct client_ctx *);
+int client_keep_visible(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_map(struct client_ctx *);
+void client_migrate_region(struct client_ctx *,
+ struct region_ctx *);
void client_msg(struct client_ctx *, Atom, Time);
void client_move(struct client_ctx *);
struct client_ctx *client_init(Window, struct screen_ctx *);
@@ -408,6 +410,7 @@
void client_setactive(struct client_ctx *);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
+struct geom client_region_area(struct client_ctx *, int);
void client_toggle_freeze(struct client_ctx *);
void client_toggle_fullscreen(struct client_ctx *);
void client_toggle_hidden(struct client_ctx *);
@@ -453,7 +456,7 @@
void search_print_cmd(struct menu *, int);
void search_print_group(struct menu *, int);
-struct region_ctx *region_find(struct screen_ctx *, int, int);
+struct region_ctx *region_find(struct screen_ctx *, struct geom);
struct geom screen_apply_gap(struct screen_ctx *, struct geom);
struct screen_ctx *screen_find(Window);
struct geom screen_area(struct screen_ctx *, int, int, int);
@@ -468,11 +471,12 @@
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
+void kbfunc_client_migrateregion(struct client_ctx *,
+ union arg *);
void kbfunc_client_move(struct client_ctx *, union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
-void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_client_resize(struct client_ctx *, union arg *);
void kbfunc_client_tile(struct client_ctx *, union arg *);
void kbfunc_client_toggle_freeze(struct client_ctx *,
Index: client.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/client.c,v
retrieving revision 1.214
diff -u -r1.214 client.c
--- client.c 12 Nov 2015 18:33:30 -0000 1.214
+++ client.c 18 Jul 2016 20:40:12 -0000
@@ -101,6 +101,7 @@
if ((cc->wmh) && (cc->wmh->flags & StateHint))
client_set_wm_state(cc, cc->wmh->initial_state);
} else {
+ cc->rc = region_find(sc, cc->geom);
if ((XQueryPointer(X_Dpy, cc->win, &rwin, &cwin,
&x, &y, &wx, &wy, &mask)) && (cwin != None))
activate = 1;
@@ -250,6 +251,16 @@
return(curcc);
}
+struct geom
+client_region_area(struct client_ctx *cc, int flags)
+{
+ struct geom area = cc->rc->view;
+
+ if (flags & CWM_GAP)
+ area = screen_apply_gap(cc->sc, area);
+ return(area);
+}
+
void
client_toggle_freeze(struct client_ctx *cc)
{
@@ -289,8 +300,7 @@
void
client_toggle_fullscreen(struct client_ctx *cc)
{
- struct screen_ctx *sc = cc->sc;
- struct geom area;
+ struct geom area;
if ((cc->flags & CLIENT_FREEZE) &&
!(cc->flags & CLIENT_FULLSCREEN))
@@ -305,9 +315,7 @@
cc->fullgeom = cc->geom;
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_NOGAP);
+ area = client_region_area(cc, CWM_NOGAP);
cc->bwidth = 0;
cc->geom = area;
@@ -321,8 +329,7 @@
void
client_toggle_maximize(struct client_ctx *cc)
{
- struct screen_ctx *sc = cc->sc;
- struct geom area;
+ struct geom area;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -343,14 +350,7 @@
cc->savegeom.x = cc->geom.x;
}
- /*
- * pick screen that the middle of the window is on.
- * that's probably more fair than if just the origin of
- * a window is poking over a boundary
- */
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
cc->geom.x = area.x;
cc->geom.y = area.y;
@@ -366,8 +366,7 @@
void
client_toggle_vmaximize(struct client_ctx *cc)
{
- struct screen_ctx *sc = cc->sc;
- struct geom area;
+ struct geom area;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -382,9 +381,7 @@
cc->savegeom.y = cc->geom.y;
cc->savegeom.h = cc->geom.h;
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
cc->geom.y = area.y;
cc->geom.h = area.h - (cc->bwidth * 2);
@@ -398,8 +395,7 @@
void
client_toggle_hmaximize(struct client_ctx *cc)
{
- struct screen_ctx *sc = cc->sc;
- struct geom area;
+ struct geom area;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -414,9 +410,7 @@
cc->savegeom.x = cc->geom.x;
cc->savegeom.w = cc->geom.w;
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
cc->geom.x = area.x;
cc->geom.w = area.w - (cc->bwidth * 2);
@@ -442,6 +436,32 @@
client_config(cc);
}
+int
+client_keep_visible(struct client_ctx *cc)
+{
+ struct region_ctx *rc;
+ int changed = 0;
+
+ /* Recalculate region for the client */
+ cc->rc = region_find(cc->sc, cc->geom);
+ rc = cc->rc;
+ if (cc->geom.x + cc->geom.w + (int)(cc->bwidth * 2) <= 0) {
+ cc->geom.x = -(cc->geom.w + (cc->bwidth * 2) - 1);
+ changed = 1;
+ } else if (cc->geom.x >= (rc->view.x + rc->view.w)) {
+ cc->geom.x = rc->view.x + rc->view.w - 1;
+ changed = 1;
+ }
+ if (cc->geom.y + cc->geom.h + (int)(cc->bwidth * 2) <= 0) {
+ cc->geom.y = -(cc->geom.h + (cc->bwidth * 2) - 1);
+ changed = 1;
+ } else if (cc->geom.y >= (rc->view.y + rc->view.h)) {
+ cc->geom.y = rc->view.y + rc->view.h - 1;
+ changed = 1;
+ }
+ return(changed);
+}
+
void
client_move(struct client_ctx *cc)
{
@@ -749,6 +769,7 @@
client_placecalc(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
+ struct geom area;
int xslack, yslack;
if (cc->hint.flags & (USPosition | PPosition)) {
@@ -759,40 +780,29 @@
* XRandR bits mean that {x,y}max shouldn't be outside what's
* currently there.
*/
- xslack = sc->view.w - cc->geom.w - cc->bwidth * 2;
- yslack = sc->view.h - cc->geom.h - cc->bwidth * 2;
- cc->geom.x = MIN(cc->geom.x, xslack);
- cc->geom.y = MIN(cc->geom.y, yslack);
+ cc->rc = region_find(sc, cc->geom);
+ area = client_region_area(cc, CWM_NOGAP);
} else {
- struct geom area;
+ struct geom point;
int xmouse, ymouse;
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
- area = screen_area(sc, xmouse, ymouse, CWM_GAP);
- area.w += area.x;
- area.h += area.y;
- xmouse = MAX(xmouse, area.x) - cc->geom.w / 2;
- ymouse = MAX(ymouse, area.y) - cc->geom.h / 2;
-
- xmouse = MAX(xmouse, area.x);
- ymouse = MAX(ymouse, area.y);
-
- xslack = area.w - cc->geom.w - cc->bwidth * 2;
- yslack = area.h - cc->geom.h - cc->bwidth * 2;
-
- if (xslack >= area.x) {
- cc->geom.x = MAX(MIN(xmouse, xslack), area.x);
- } else {
- cc->geom.x = area.x;
- cc->geom.w = area.w;
- }
- if (yslack >= area.y) {
- cc->geom.y = MAX(MIN(ymouse, yslack), area.y);
- } else {
- cc->geom.y = area.y;
- cc->geom.h = area.h;
+ point = (struct geom){ xmouse, ymouse, 0, 0 };
+ cc->rc = region_find(sc, point);
+ area = client_region_area(cc, CWM_GAP);
+
+ if (!(cc->hint.flags & (USSize | PSize))) {
+ cc->geom.w = MIN(cc->geom.w, area.w - cc->bwidth * 2);
+ cc->geom.h = MIN(cc->geom.h, area.h - cc->bwidth * 2);
+ client_applysizehints(cc);
}
+ cc->geom.x = xmouse - cc->geom.w / 2 - cc->bwidth;
+ cc->geom.y = ymouse - cc->geom.h / 2 - cc->bwidth;
}
+ xslack = area.x + area.w - cc->geom.w - cc->bwidth * 2;
+ yslack = area.y + area.h - cc->geom.h - cc->bwidth * 2;
+ cc->geom.x = MAX(MIN(cc->geom.x, xslack), area.x);
+ cc->geom.y = MAX(MIN(cc->geom.y, yslack), area.y);
}
static void
@@ -974,7 +984,6 @@
{
struct client_ctx *ci;
struct group_ctx *gc = cc->gc;
- struct screen_ctx *sc = cc->sc;
struct geom area;
int i, n, mh, x, h, w;
@@ -983,17 +992,15 @@
i = n = 0;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
- if (ci->flags & CLIENT_HIDDEN ||
- ci->flags & CLIENT_IGNORE || (ci == cc))
+ if ((ci->flags & (CLIENT_HIDDEN | CLIENT_IGNORE)) ||
+ (ci == cc) || (ci->rc != cc->rc))
continue;
n++;
}
if (n == 0)
return;
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
if (cc->flags & CLIENT_VMAXIMIZED ||
cc->geom.h + (cc->bwidth * 2) >= area.h)
@@ -1011,8 +1018,8 @@
w = area.w / n;
h = area.h - mh;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
- if (ci->flags & CLIENT_HIDDEN ||
- ci->flags & CLIENT_IGNORE || (ci == cc))
+ if ((ci->flags & (CLIENT_HIDDEN | CLIENT_IGNORE)) ||
+ (ci == cc) || (ci->rc != cc->rc))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.y = area.y + mh;
@@ -1033,7 +1040,6 @@
{
struct client_ctx *ci;
struct group_ctx *gc = cc->gc;
- struct screen_ctx *sc = cc->sc;
struct geom area;
int i, n, mw, y, h, w;
@@ -1042,17 +1048,15 @@
i = n = 0;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
- if (ci->flags & CLIENT_HIDDEN ||
- ci->flags & CLIENT_IGNORE || (ci == cc))
+ if ((ci->flags & (CLIENT_HIDDEN | CLIENT_IGNORE)) ||
+ (ci == cc) || (ci->rc != cc->rc))
continue;
n++;
}
if (n == 0)
return;
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
if (cc->flags & CLIENT_HMAXIMIZED ||
cc->geom.w + (cc->bwidth * 2) >= area.w)
@@ -1070,8 +1074,8 @@
h = area.h / n;
w = area.w - mw;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
- if (ci->flags & CLIENT_HIDDEN ||
- ci->flags & CLIENT_IGNORE || (ci == cc))
+ if ((ci->flags & (CLIENT_HIDDEN | CLIENT_IGNORE)) ||
+ (ci == cc) || (ci->rc != cc->rc))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.y = y;
@@ -1087,6 +1091,51 @@
}
}
+static void
+client_migrate_area(struct geom *geom, struct geom *newarea,
+ struct geom *oldarea)
+{
+ int oldslack, newslack;
+
+ oldslack = oldarea->w - geom->w - (Conf.bwidth * 2);
+ newslack = newarea->w - geom->w - (Conf.bwidth * 2);
+ geom->x -= oldarea->x;
+ if (oldslack != 0 && newslack != oldslack)
+ geom->x = (long long)geom->x * newslack / oldslack;
+ geom->x += newarea->x;
+
+ oldslack = oldarea->h - geom->h - (Conf.bwidth * 2);
+ newslack = newarea->h - geom->h - (Conf.bwidth * 2);
+ geom->y -= oldarea->y;
+ if (oldslack != 0 && newslack != oldslack)
+ geom->y = (long long)geom->y * newslack / oldslack;
+ geom->y += newarea->y;
+}
+
+void
+client_migrate_region(struct client_ctx *cc, struct region_ctx *rc)
+{
+ struct screen_ctx *sc = cc->sc;
+ struct geom oldarea, newarea;
+
+ oldarea = screen_apply_gap(sc, cc->rc->view);
+ newarea = screen_apply_gap(sc, rc->view);
+ client_migrate_area(&cc->savegeom, &newarea, &oldarea);
+ client_migrate_area(&cc->fullgeom, &newarea, &oldarea);
+ if (cc->flags & CLIENT_FULLSCREEN)
+ cc->geom = rc->view;
+ else {
+ client_migrate_area(&cc->geom, &newarea, &oldarea);
+ if (cc->flags & CLIENT_HMAXIMIZED)
+ cc->geom.w = newarea.w - (cc->bwidth * 2);
+ if (cc->flags & CLIENT_VMAXIMIZED)
+ cc->geom.h = newarea.h - (cc->bwidth * 2);
+ client_keep_visible(cc);
+ }
+ cc->rc = rc;
+ client_resize(cc, 0);
+}
+
long
client_get_wm_state(struct client_ctx *cc)
{
@@ -1108,4 +1157,3 @@
XChangeProperty(X_Dpy, cc->win, cwmh[WM_STATE], cwmh[WM_STATE], 32,
PropModeReplace, (unsigned char *)data, 2);
}
-
Index: conf.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/conf.c,v
retrieving revision 1.202
diff -u -r1.202 conf.c
--- conf.c 17 Nov 2015 15:19:19 -0000 1.202
+++ conf.c 18 Jul 2016 20:40:12 -0000
@@ -406,6 +406,10 @@
{.i = (CWM_CLIENT_CYCLE | CWM_CLIENT_CYCLE_INGRP)} },
{ "rcycleingroup", kbfunc_client_cycle, CWM_CONTEXT_CLIENT,
{.i = (CWM_CLIENT_RCYCLE | CWM_CLIENT_CYCLE_INGRP)} },
+ { "migrateregion", kbfunc_client_migrateregion, CWM_CONTEXT_CLIENT,
+ {.i = CWM_CLIENT_CYCLE} },
+ { "rmigrateregion", kbfunc_client_migrateregion, CWM_CONTEXT_CLIENT,
+ {.i = CWM_CLIENT_RCYCLE} },
{ "grouptoggle", kbfunc_client_grouptoggle, CWM_CONTEXT_CLIENT,
{.i = CWM_KBD}},
{ "sticky", kbfunc_client_toggle_sticky, CWM_CONTEXT_CLIENT, {0} },
Index: cwmrc.5
===================================================================
RCS file: /cvs/xenocara/app/cwm/cwmrc.5,v
retrieving revision 1.61
diff -u -r1.61 cwmrc.5
--- cwmrc.5 12 Jul 2015 14:31:47 -0000 1.61
+++ cwmrc.5 18 Jul 2016 20:40:12 -0000
@@ -289,6 +289,10 @@
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
+.It migrateregion
+Migrate current window to next region (XRandR monitor).
+.It rmigrateregion
+Migrate current window to previous region (XRandR monitor).
.It delete
Delete current window.
.It hide
Index: kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
retrieving revision 1.126
diff -u -r1.126 kbfunc.c
--- kbfunc.c 17 Nov 2015 14:32:38 -0000 1.126
+++ kbfunc.c 18 Jul 2016 20:40:12 -0000
@@ -104,19 +104,10 @@
kbfunc_amount(arg->i, Conf.mamount, &mx, &my);
cc->geom.x += mx;
- if (cc->geom.x + cc->geom.w < 0)
- cc->geom.x = -cc->geom.w;
- if (cc->geom.x > sc->view.w - 1)
- cc->geom.x = sc->view.w - 1;
cc->geom.y += my;
- if (cc->geom.y + cc->geom.h < 0)
- cc->geom.y = -cc->geom.h;
- if (cc->geom.y > sc->view.h - 1)
- cc->geom.y = sc->view.h - 1;
-
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ client_keep_visible(cc);
+
+ area = client_region_area(cc, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
area.x, area.x + area.w, sc->snapdist);
@@ -149,6 +140,7 @@
cc->geom.w = cc->hint.minw;
if ((cc->geom.h += my * cc->hint.inch) < cc->hint.minh)
cc->geom.h = cc->hint.minh;
+ client_keep_visible(cc);
client_resize(cc, 1);
/* Make sure the pointer stays within the window. */
@@ -491,6 +483,24 @@
kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
{
group_movetogroup(cc, arg->i);
+}
+
+void
+kbfunc_client_migrateregion(struct client_ctx *cc, union arg *arg)
+{
+ struct screen_ctx *sc = cc->sc;
+ struct region_ctx *rc;
+
+ if (arg->i == CWM_CLIENT_RCYCLE) {
+ if ((rc = TAILQ_PREV(cc->rc, region_ctx_q, entry)) == NULL)
+ rc = TAILQ_LAST(&sc->regionq, region_ctx_q);
+ } else {
+ if ((rc = TAILQ_NEXT(cc->rc, entry)) == NULL)
+ rc = TAILQ_FIRST(&sc->regionq);
+ }
+ client_ptrsave(cc);
+ client_migrate_region(cc, rc);
+ client_ptrwarp(cc);
}
void
Index: mousefunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/mousefunc.c,v
retrieving revision 1.103
diff -u -r1.103 mousefunc.c
--- mousefunc.c 17 Nov 2015 14:31:28 -0000 1.103
+++ mousefunc.c 18 Jul 2016 20:40:12 -0000
@@ -140,10 +140,14 @@
cc->geom.x = ev.xmotion.x_root - px - cc->bwidth;
cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
+ if (client_keep_visible(cc)) {
+ px = ev.xmotion.x_root - cc->geom.x -
+ cc->bwidth;
+ py = ev.xmotion.y_root - cc->geom.y -
+ cc->bwidth;
+ }
- area = screen_area(sc,
- cc->geom.x + cc->geom.w / 2,
- cc->geom.y + cc->geom.h / 2, CWM_GAP);
+ area = client_region_area(cc, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
area.x, area.x + area.w, sc->snapdist);
Index: screen.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/screen.c,v
retrieving revision 1.79
diff -u -r1.79 screen.c
--- screen.c 11 Nov 2015 14:22:01 -0000 1.79
+++ screen.c 18 Jul 2016 20:40:12 -0000
@@ -125,32 +125,67 @@
}
struct region_ctx *
-region_find(struct screen_ctx *sc, int x, int y)
+region_find(struct screen_ctx *sc, struct geom area)
{
struct region_ctx *rc;
+ struct region_ctx *best = NULL;
+ long long overlap = 0;
+ int cx, cy, distance = -1;
+ cx = area.x + area.w / 2;
+ cy = area.y + area.h / 2;
TAILQ_FOREACH(rc, &sc->regionq, entry) {
- if ((x >= rc->view.x) && (x < (rc->view.x + rc->view.w)) &&
- (y >= rc->view.y) && (y < (rc->view.y + rc->view.h))) {
- break;
+ if ((cx >= rc->view.x) && (cx < (rc->view.x + rc->view.w)) &&
+ (cy >= rc->view.y) && (cy < (rc->view.y + rc->view.h))) {
+ /* Centre of area is within region, we're done */
+ return(rc);
+ }
+ if ((area.x < (rc->view.x + rc->view.w)) &&
+ (rc->view.x < (area.x + area.w)) &&
+ (area.y < (rc->view.y + rc->view.h)) &&
+ (rc->view.y < (area.y + area.h))) {
+ /* Region overlaps with area; find largest overlap */
+ int w, h;
+
+ w = MIN(area.x + area.w, rc->view.x + rc->view.w) -
+ MAX(area.x, rc->view.x);
+ h = MIN(area.y + area.h, rc->view.y + rc->view.h) -
+ MAX(area.y, rc->view.y);
+ if ((long long)w * h > overlap) {
+ overlap = (long long)w * h;
+ best = rc;
+ }
+ } else if (!overlap) {
+ /* Lacking overlaps, find region with shortest
+ * Manhattan distance from area */
+ int d = 0;
+
+ if ((area.x + area.w) <= rc->view.x)
+ d += rc->view.x - (area.x + area.w - 1);
+ else if ((rc->view.x + rc->view.w) <= area.x)
+ d += area.x - (rc->view.x + rc->view.w - 1);
+ if ((area.y + area.h) <= rc->view.y)
+ d += rc->view.y - (area.y + area.h - 1);
+ else if ((rc->view.y + rc->view.h) <= area.y)
+ d += area.y - (rc->view.y + rc->view.h - 1);
+
+ if (distance == -1 || d < distance) {
+ distance = d;
+ best = rc;
+ }
}
}
- return(rc);
+ return(best);
}
struct geom
screen_area(struct screen_ctx *sc, int x, int y, int flags)
{
struct region_ctx *rc;
- struct geom area = sc->work;
+ struct geom area, point = { x, y, 0, 0 };
- TAILQ_FOREACH(rc, &sc->regionq, entry) {
- if ((x >= rc->area.x) && (x < (rc->area.x + rc->area.w)) &&
- (y >= rc->area.y) && (y < (rc->area.y + rc->area.h))) {
- area = rc->area;
- break;
- }
- }
+ rc = region_find(sc, point);
+ area = rc->view;
if (flags & CWM_GAP)
area = screen_apply_gap(sc, area);
return(area);
@@ -159,7 +194,9 @@
void
screen_update_geometry(struct screen_ctx *sc)
{
- struct region_ctx *rc;
+ struct region_ctx_q oldregionq;
+ struct region_ctx *oldrc, *rc;
+ struct client_ctx *cc;
sc->view.x = 0;
sc->view.y = 0;
@@ -167,9 +204,10 @@
sc->view.h = DisplayHeight(X_Dpy, sc->which);
sc->work = screen_apply_gap(sc, sc->view);
+ TAILQ_INIT(&oldregionq);
while ((rc = TAILQ_FIRST(&sc->regionq)) != NULL) {
TAILQ_REMOVE(&sc->regionq, rc, entry);
- free(rc);
+ TAILQ_INSERT_TAIL(&oldregionq, rc, entry);
}
if (HasRandr) {
@@ -189,15 +227,10 @@
rc = xmalloc(sizeof(*rc));
rc->num = i;
- rc->area.x = ci->x;
- rc->area.y = ci->y;
- rc->area.w = ci->width;
- rc->area.h = ci->height;
rc->view.x = ci->x;
rc->view.y = ci->y;
rc->view.w = ci->width;
rc->view.h = ci->height;
- rc->work = screen_apply_gap(sc, rc->view);
TAILQ_INSERT_TAIL(&sc->regionq, rc, entry);
XRRFreeCrtcInfo(ci);
@@ -210,8 +243,18 @@
rc->view.y = 0;
rc->view.w = DisplayWidth(X_Dpy, sc->which);
rc->view.h = DisplayHeight(X_Dpy, sc->which);
- rc->work = screen_apply_gap(sc, rc->view);
TAILQ_INSERT_TAIL(&sc->regionq, rc, entry);
+ }
+
+ while ((oldrc = TAILQ_FIRST(&oldregionq)) != NULL) {
+ rc = region_find(sc, oldrc->view);
+ TAILQ_FOREACH(cc, &sc->clientq, entry) {
+ if (cc->rc != oldrc)
+ continue;
+ client_migrate_region(cc, rc);
+ }
+ TAILQ_REMOVE(&oldregionq, oldrc, entry);
+ free(oldrc);
}
xu_ewmh_net_desktop_geometry(sc);
Index: xevents.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/xevents.c,v
retrieving revision 1.120
diff -u -r1.120 xevents.c
--- xevents.c 10 Nov 2015 20:05:33 -0000 1.120
+++ xevents.c 18 Jul 2016 20:40:12 -0000
@@ -139,6 +139,8 @@
if (e->value_mask & CWStackMode)
wc.stack_mode = e->detail;
+ client_keep_visible(cc);
+
if (cc->geom.x == 0 && cc->geom.w >= sc->view.w)
cc->geom.x -= cc->bwidth;