Hi, 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 keeps clients overlapping with the screen's view area, handling these cases better: - Moving client without border off screen (left or up) - Moving client with a mouse, starting with the pointer outside the window - Resizing partially off-screen client using a keyboard - Client moving or resizing itself (ConfigureRequest event) The following cases are still not handled: - Not all screen's view area being viewable, i.e., covered with regions (e.g., XRandR with monitors of different sizes) - Screen's view area changing size (XRandR monitors rotating or disconnecting) - Non-rectangular clients (XShape) So here are my thoughts, and your feedback is welcome. We certainly want to deal with regions and not screens, here and in some other places where screen_area() is called. We could use a function that returns the best region for a client, along the lines of: - find the region containing the centre of the window; - failing that, find the region that has the biggest overlapping area with the window; - if none overlap with it (client fully off screen), find the region closest to the window. We may then cache the region inside client_ctx, if it worth dealing with cache invalidation. Regarding region changes, I'd like to see them handled the following way: - When a region geometry changes (screen rotating), all clients therein should retain the same relative position within the new region that they occupied in the old one - When a region disappears, all its clients should move to another region, preferrably to the same one, likewise retaining their relative position - A relative position is something like (in pseudocode): { (client.x - region.x) / (region.w - client.w), (client.y - region.y) / (region.h - client.h) } (whatever's in the corner or in the middle stays there, etc.) - It's possible to keep hidden clients in place after an XRandR event until they're shown, but probably not worth it To achieve this, screen_update_geometry() may be changed like so: - initialize new regions; - for every old region, find the best matching new region, along the lines of the algorithm above; - for every client: - find the best matching old region; - note relative position within it; - move the client to the appropriate relative position in the new region found in the step above; - if the client is {h,v}maximized or fullscreen, resize; - ensure client is still visible (with the calculation above, clients that are partially off-screen may become fully so after moving); - free old regions. The simplest way to handle shaped clients I can think of is to require them to be fully visible, i.e., that each of their four corners (that they don't have) is inside a region. Have I forgot any other cases that may move clients off screen? My paranoia tells me to call client_keep_visible() from client_cycle()... Or maybe just call client_setactive() from there. What do you think? Vadik. -- An artist should be fit for the best society and keep out of it.
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 12 Dec 2015 17:39:11 -0000 @@ -394,6 +394,7 @@ 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_msg(struct client_ctx *, Atom, Time); 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 12 Dec 2015 17:39:12 -0000 @@ -442,6 +442,29 @@ client_config(cc); } +int +client_keep_visible(struct client_ctx *cc) +{ + struct screen_ctx *sc = cc->sc; + int changed = 0; + + 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 >= sc->view.w) { + cc->geom.x = sc->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 >= sc->view.h) { + cc->geom.y = sc->view.h - 1; + changed = 1; + } + return(changed); +} + void client_move(struct client_ctx *cc) { 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 12 Dec 2015 17:39:12 -0000 @@ -104,15 +104,8 @@ 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; + client_keep_visible(cc); area = screen_area(sc, cc->geom.x + cc->geom.w / 2, @@ -149,6 +142,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. */ 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 12 Dec 2015 17:39:12 -0000 @@ -140,6 +140,12 @@ 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, 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 12 Dec 2015 17:39: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;