I switch Xinerama screens on and off quite often (with the help of
xrandr(1)). Sometimes, this results in windows ending up beyond the
screen boundries.
Like when a Xinerama screen has windows and is to the right or to the
bottom from another Xinerama screen and you turn it off.
Correct me if I'm wrong, but there's no way to bring such windows
back to the screen.
Even the "kill-the-app-and-start-it-again" approach doesn't always work
(let alone it being inconvenient...) -- some apps remember their
position and start up at that same location the next time (Sylpheed,
Pidgin, epdfview...).
This is how I solved it for myself: when an XRandR event comes, go thru
the list of all client windows and move those which are beyond the
screen boundries to (0,0) (or (gap_x, gap_y) if you configured them).
This also works when rotation is applied to the screen, it can
cause a window to fall off of the screen too.
Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.125
diff -u -p -r1.125 calmwm.h
--- calmwm.h 11 May 2011 13:53:51 -0000 1.125
+++ calmwm.h 15 May 2011 13:02:31 -0000
@@ -365,6 +365,9 @@ struct screen_ctx *screen_fromroot(Windo
void screen_init_xinerama(struct screen_ctx *);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_updatestackingorder(struct screen_ctx *);
+int screen_is_client_beyond(struct screen_ctx *,
+ struct client_ctx *);
+void screen_assert_clients_within(struct screen_ctx *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
Index: screen.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/screen.c,v
retrieving revision 1.28
diff -u -p -r1.28 screen.c
--- screen.c 11 May 2011 13:53:51 -0000 1.28
+++ screen.c 15 May 2011 13:02:31 -0000
@@ -131,3 +131,55 @@ screen_update_geometry(struct screen_ctx
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}
+
+/*
+ * Return non-zero if client is beyond the screen.
+ */
+int
+screen_is_client_beyond(struct screen_ctx *sc, struct client_ctx *cc)
+{
+ int bw, top, left, right, bottom;
+
+ bw = cc->bwidth * 2;
+ top = cc->geom.y;
+ left = cc->geom.x;
+ right = cc->geom.x + cc->geom.width + bw - 1;
+ bottom = cc->geom.y + cc->geom.height + bw - 1;
+
+ if (HasXinerama) {
+ if (screen_find_xinerama(sc, left, top))
+ return 0;
+ if (screen_find_xinerama(sc, left, bottom))
+ return 0;
+ if (screen_find_xinerama(sc, right, top))
+ return 0;
+ if (screen_find_xinerama(sc, right, bottom))
+ return 0;
+ return 1;
+ } else {
+ if (top > sc->ymax || left > sc->xmax)
+ return 1;
+ if (bottom < 0 || right < 0)
+ return 1;
+ return 0;
+ }
+}
+
+/*
+ * Bring clients which are beyond the screen back.
+ */
+void
+screen_assert_clients_within(struct screen_ctx *sc)
+{
+ struct client_ctx *cc;
+
+ TAILQ_FOREACH(cc, &Clientq, entry) {
+ if (cc->sc != sc)
+ continue;
+ if (screen_is_client_beyond(sc, cc)) {
+ cc->geom.x = sc->gap.left;
+ cc->geom.y = sc->gap.top;
+ client_move(cc);
+ }
+ }
+}
Index: xevents.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/xevents.c,v
retrieving revision 1.53
diff -u -p -r1.53 xevents.c
--- xevents.c 11 May 2011 13:53:51 -0000 1.53
+++ xevents.c 15 May 2011 13:02:31 -0000
@@ -377,6 +377,7 @@ xev_handle_randr(XEvent *ee)
XRRUpdateConfiguration(ee);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
+ screen_assert_clients_within(sc);
}
}
}