Version 3 of the patch fixes region border calculation in
client_keep_visible().
Quoth Vadim Vygonets on Mon, Jul 18, 2016:
> 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.
--
Computer games don't affect kids; I mean if Pac-Man affected us
as kids, we'd all be running around in darkened rooms, munching
magic pills and listening to repetitive electronic music.
-- Marcus Brigstocke, British Comedian
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 15 Aug 2016 19:51:00 -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) <= rc->view.x) {
+ cc->geom.x = rc->view.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) <= rc->view.y) {
+ cc->geom.y = rc->view.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.204
diff -u -r1.204 conf.c
--- conf.c 13 Aug 2016 09:59:48 -0000 1.204
+++ 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;