summary refs log tree commit diff
diff options
context:
space:
mode:
authoroga <oga>2009-01-17 18:41:50 +0000
committeroga <oga>2009-01-17 18:41:50 +0000
commitfa87ef4a9e6131597d86b0d3e76cd2e7b6911bcd (patch)
treebabdf0da910b8fd6085519bc0e948719b0f61032
parent399253a4ff975c3858b9bba1db8e7aca15860399 (diff)
downloadcwm-fa87ef4a9e6131597d86b0d3e76cd2e7b6911bcd.tar.gz
cwm-fa87ef4a9e6131597d86b0d3e76cd2e7b6911bcd.tar.xz
cwm-fa87ef4a9e6131597d86b0d3e76cd2e7b6911bcd.zip
Finally fix the really annoying race where if you rapidly switch groups several
times you'd end up losing clients (thinking they had gone away).

From the ICCCM (which should not be read without a stiff drink in hand,
I made this mistake so you don't have to): to request a window to be
withdrawn one should send a synthetic UnmapRequest event when iconified.
To request iconification one should just unmap the window. The ICCM
further recommends that the synthetic event should just be taken as a
cue to withdraw, to deal with legacy clients. Taking a hint from this,
rework xev_handle_unmaprequest to correctly detect these situations.  A
Withdrawn window may come back anywhere, even as a subwindow of
something else, so the correct way to handle this state is to forget it
ever existed.

While i'm here, kill a dumb attempt to notice this in client_delete, and
nuke the very unnecessary arguments.

Todd confirmed this fixes the `race'.

ok todd@, ok ok okan@
-rw-r--r--calmwm.h2
-rw-r--r--client.c5
-rw-r--r--xevents.c35
3 files changed, 23 insertions, 19 deletions
diff --git a/calmwm.h b/calmwm.h
index 5234376..1343011 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -310,7 +310,7 @@ __dead void		 usage(void);
 struct client_ctx	*client_find(Window);
 void			 client_setup(void);
 struct client_ctx	*client_new(Window, struct screen_ctx *, int);
-int			 client_delete(struct client_ctx *, int, int);
+int			 client_delete(struct client_ctx *);
 void			 client_setactive(struct client_ctx *, int);
 void			 client_resize(struct client_ctx *);
 void			 client_lower(struct client_ctx *);
diff --git a/client.c b/client.c
index cf72174..ab3bd3d 100644
--- a/client.c
+++ b/client.c
@@ -144,14 +144,11 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
 }
 
 int
-client_delete(struct client_ctx *cc, int sendevent, int ignorewindow)
+client_delete(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = CCTOSC(cc);
 	struct winname		*wn;
 
-	if (cc->state == IconicState && !sendevent)
-		return (1);
-
 	group_client_delete(cc);
 
 	XGrabServer(X_Dpy);
diff --git a/xevents.c b/xevents.c
index 4add085..8db5862 100644
--- a/xevents.c
+++ b/xevents.c
@@ -36,12 +36,8 @@ void
 xev_handle_maprequest(struct xevent *xev, XEvent *ee)
 {
 	XMapRequestEvent	*e = &ee->xmaprequest;
-	XWindowAttributes	 xattr;
 	struct client_ctx	*cc = NULL, *old_cc;
-
-#ifdef notyet
-	int state;
-#endif
+	XWindowAttributes	 xattr;
 
 	if ((old_cc = client_current()) != NULL)
 		client_ptrsave(old_cc);
@@ -51,12 +47,6 @@ xev_handle_maprequest(struct xevent *xev, XEvent *ee)
 		cc = client_new(e->window, screen_fromroot(xattr.root), 1);
 	}
 
-#ifdef notyet			/* XXX - possibly, we shouldn't map if
-				 * the window is withdrawn. */
-	if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
-		warnx("WITHDRAWNSTATE for %s", cc->name);
-#endif
-
 	client_ptrwarp(cc);
 	xev_register(xev);
 }
@@ -65,10 +55,27 @@ void
 xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
 {
 	XUnmapEvent		*e = &ee->xunmap;
+	XEvent			ev;
 	struct client_ctx	*cc;
 
-	if ((cc = client_find(e->window)) != NULL)
-		client_delete(cc, e->send_event, 0);
+	/* XXX, we need a recursive locking wrapper around grab server */
+	XGrabServer(X_Dpy);
+	if ((cc = client_find(e->window)) != NULL) {
+		/*
+		 * If it's going to die anyway, nuke it.
+		 *
+		 * Else, if it's a synthetic event delete state, since they
+		 * want it to be withdrawn. ICCM recommends you withdraw on
+		 * this even if we haven't alredy been told to iconify, to
+		 * deal with legacy clients.
+		 */
+		if (XCheckTypedWindowEvent(X_Dpy, cc->win,
+		    DestroyNotify, &ev) || e->send_event != 0) {
+			client_delete(cc);
+		} else
+			client_hide(cc);
+	}
+	XUngrabServer(X_Dpy);
 
 	xev_register(xev);
 }
@@ -80,7 +87,7 @@ xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
 	struct client_ctx	*cc;
 
 	if ((cc = client_find(e->window)) != NULL)
-		client_delete(cc, 1, 1);
+		client_delete(cc);
 
 	xev_register(xev);
 }