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().
This commit is contained in:
cinap_lenrek 2013-01-09 16:32:53 +01:00
parent 1c69f9c023
commit 681bcfa968
3 changed files with 46 additions and 24 deletions

View file

@ -38,6 +38,7 @@ typedef struct Mousestate Mousestate;
typedef struct Ref Ref; typedef struct Ref Ref;
typedef struct Timer Timer; typedef struct Timer Timer;
typedef struct Wctlmesg Wctlmesg; typedef struct Wctlmesg Wctlmesg;
typedef struct Wdelmesg Wdelmesg;
typedef struct Window Window; typedef struct Window Window;
typedef struct Xfid Xfid; typedef struct Xfid Xfid;
@ -80,6 +81,12 @@ struct Wctlmesg
void *p; void *p;
}; };
struct Wdelmesg
{
char *s;
Image *i;
};
struct Conswritemesg struct Conswritemesg
{ {
Channel *cw; /* chan(Stringpair) */ Channel *cw; /* chan(Stringpair) */

View file

@ -205,7 +205,7 @@ threadmain(int argc, char *argv[])
exitchan = chancreate(sizeof(int), 0); exitchan = chancreate(sizeof(int), 0);
winclosechan = chancreate(sizeof(Window*), 0); winclosechan = chancreate(sizeof(Window*), 0);
deletechan = chancreate(sizeof(char*), 0); deletechan = chancreate(sizeof(Wdelmesg), 0);
timerinit(); timerinit();
threadcreate(keyboardthread, nil, STACK); threadcreate(keyboardthread, nil, STACK);
@ -422,30 +422,28 @@ winclosethread(void*)
void void
deletethread(void*) deletethread(void*)
{ {
char *s; Wdelmesg m;
Image *i;
threadsetname("deletethread"); threadsetname("deletethread");
for(;;){ for(;;){
s = recvp(deletechan); recv(deletechan, &m);
i = namedimage(display, s); freeimage(m.i);
if(i != nil){ 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 */ /* 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); freeimage(m.i);
free(s); free(m.s);
} }
} }
void void
deletetimeoutproc(void *v) deletetimeoutproc(void *v)
{ {
char *s;
s = v;
sleep(750); /* remove window from screen after 3/4 of a second */ sleep(750); /* remove window from screen after 3/4 of a second */
sendp(deletechan, s); send(deletechan, v);
free(v);
} }
/* /*

View file

@ -88,13 +88,35 @@ void
wresize(Window *w, Image *i, int move) wresize(Window *w, Image *i, int move)
{ {
Rectangle r, or; Rectangle r, or;
Wdelmesg *m;
or = w->i->r; or = w->i->r;
if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(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); 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->i = i;
w->mc.image = 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); r = insetrect(i->r, Selborder+1);
w->scrollr = r; w->scrollr = r;
w->scrollr.max.x = r.min.x+Scrollwid; w->scrollr.max.x = r.min.x+Scrollwid;
@ -1070,7 +1092,6 @@ wsendctlmesg(Window *w, int type, Rectangle r, void *p)
int int
wctlmesg(Window *w, int m, Rectangle r, void *p) wctlmesg(Window *w, int m, Rectangle r, void *p)
{ {
char buf[64];
Image *i = p; Image *i = p;
switch(m){ switch(m){
@ -1088,9 +1109,7 @@ wctlmesg(Window *w, int m, Rectangle r, void *p)
break; break;
} }
w->screenr = r; w->screenr = r;
strcpy(buf, w->name);
wresize(w, i, m==Moved); wresize(w, i, m==Moved);
proccreate(deletetimeoutproc, estrdup(buf), 4096);
flushimage(display, 1); flushimage(display, 1);
if(Dx(r)<=0){ /* window got hidden, if we had the input, drop it */ if(Dx(r)<=0){ /* window got hidden, if we had the input, drop it */
if(w==input) if(w==input)
@ -1177,7 +1196,6 @@ wctlmesg(Window *w, int m, Rectangle r, void *p)
break; break;
wclunk(w); wclunk(w);
write(w->notefd, "hangup", 6); write(w->notefd, "hangup", 6);
proccreate(deletetimeoutproc, estrdup(w->name), 4096);
wclosewin(w); wclosewin(w);
break; break;
case Exited: case Exited:
@ -1361,14 +1379,13 @@ wclunk(Window *w)
void void
wclosewin(Window *w) wclosewin(Window *w)
{ {
Image *i; Wdelmesg m;
i = w->i; m.i = w->i;
if(i){ if(m.i){
w->i = nil; w->i = nil;
/* move it off-screen to hide it, in case client is slow in letting it go */ m.s = estrdup(w->name);
MOVEIT originwindow(i, i->r.min, view->r.max); send(deletechan, &m);
freeimage(i);
} }
} }