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;
>  

Reply via email to