On Mon 2016.07.18 at 23:16 +0200, Vadim Vygonets wrote:
> 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/
Thank you. Unfortunately I've been a big slacker, but don't take that as
I'll forget about this stuff forever :) I'm hoping this next cycle I'll
have some more time to come back to cwm and all the diff's received.
> 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;
>