git: 9front

Download patch

ref: 2c47d5e04a2f974decf93b50a68433d4de961c79
parent: c65387fcaae11f76f871101b30fb24712d87e7da
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Wed Jan 9 11:32:53 EST 2013

rio: fix window resize and attach race

if a window gets hidden/unhidden/resized too fast, the client might have no
chance attaching to that image using winname. so we move the window
offscreen instead and delay the freeimage() by doing it in the deletethread().

--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -38,6 +38,7 @@
 typedef	struct	Ref Ref;
 typedef	struct	Timer Timer;
 typedef	struct	Wctlmesg Wctlmesg;
+typedef struct	Wdelmesg Wdelmesg;
 typedef	struct	Window Window;
 typedef	struct	Xfid Xfid;
 
@@ -78,6 +79,12 @@
 	int		type;
 	Rectangle	r;
 	void		*p;
+};
+
+struct Wdelmesg
+{
+	char	*s;
+	Image	*i;
 };
 
 struct Conswritemesg
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -205,7 +205,7 @@
 
 	exitchan = chancreate(sizeof(int), 0);
 	winclosechan = chancreate(sizeof(Window*), 0);
-	deletechan = chancreate(sizeof(char*), 0);
+	deletechan = chancreate(sizeof(Wdelmesg), 0);
 
 	timerinit();
 	threadcreate(keyboardthread, nil, STACK);
@@ -422,19 +422,19 @@
 void
 deletethread(void*)
 {
-	char *s;
-	Image *i;
+	Wdelmesg m;
 
 	threadsetname("deletethread");
 	for(;;){
-		s = recvp(deletechan);
-		i = namedimage(display, s);
-		if(i != nil){
+		recv(deletechan, &m);
+		freeimage(m.i);
+		m.i = namedimage(display, m.s);
+		if(m.i != nil){
 			/* move it off-screen to hide it, since client is slow in letting it go */
-			originwindow(i, i->r.min, view->r.max);
+			originwindow(m.i, m.i->r.min, view->r.max);
 		}
-		freeimage(i);
-		free(s);
+		freeimage(m.i);
+		free(m.s);
 	}
 }
 
@@ -441,11 +441,9 @@
 void
 deletetimeoutproc(void *v)
 {
-	char *s;
-
-	s = v;
 	sleep(750);	/* remove window from screen after 3/4 of a second */
-	sendp(deletechan, s);
+	send(deletechan, v);
+	free(v);
 }
 
 /*
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -88,13 +88,35 @@
 wresize(Window *w, Image *i, int move)
 {
 	Rectangle r, or;
+	Wdelmesg *m;
 
 	or = w->i->r;
 	if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
 		draw(i, i->r, w->i, nil, w->i->r.min);
-	freeimage(w->i);
+
+	m = emalloc(sizeof(Wdelmesg));
+	m->s = estrdup(w->name);
+	m->i = w->i;
+
 	w->i = i;
 	w->mc.image = i;
+
+	if(w->mouseopen){
+		/*
+		 * do not freeimage() here because the client might be in
+		 * the process of attaching that image using winname.
+		 * move the old window offscreen unless its completely
+		 * hidden by the new window and let deletetimeoutproc
+		 * free the image after some delay.
+		 */
+		if(!rectinrect(or, w->screenr))
+			originwindow(m->i, or.min, view->r.max);
+	} else {
+		freeimage(m->i);
+		m->i = nil;
+	}
+	proccreate(deletetimeoutproc, m, 4096);
+
 	r = insetrect(i->r, Selborder+1);
 	w->scrollr = r;
 	w->scrollr.max.x = r.min.x+Scrollwid;
@@ -1070,7 +1092,6 @@
 int
 wctlmesg(Window *w, int m, Rectangle r, void *p)
 {
-	char buf[64];
 	Image *i = p;
 
 	switch(m){
@@ -1088,9 +1109,7 @@
 			break;
 		}
 		w->screenr = r;
-		strcpy(buf, w->name);
 		wresize(w, i, m==Moved);
-		proccreate(deletetimeoutproc, estrdup(buf), 4096);
 		flushimage(display, 1);
 		if(Dx(r)<=0){	/* window got hidden, if we had the input, drop it */
 			if(w==input)
@@ -1177,7 +1196,6 @@
 			break;
 		wclunk(w);
 		write(w->notefd, "hangup", 6);
-		proccreate(deletetimeoutproc, estrdup(w->name), 4096);
 		wclosewin(w);
 		break;
 	case Exited:
@@ -1361,14 +1379,13 @@
 void
 wclosewin(Window *w)
 {
-	Image *i;
+	Wdelmesg m;
 
-	i = w->i;
-	if(i){
+	m.i = w->i;
+	if(m.i){
 		w->i = nil;
-		/* move it off-screen to hide it, in case client is slow in letting it go */
-		MOVEIT originwindow(i, i->r.min, view->r.max);
-		freeimage(i);
+		m.s = estrdup(w->name);
+		send(deletechan, &m);
 	}
 }
 
--