rio: fix deadlock
we can't really change the Window *input from outside the winctl() thread. the problem is that the window might end up reading the mouse (scroll, select) which makes the w->cctl channel block once you try to talk to the window again (from the mousethread). this also means we have to coordinate window switchin from the winctl proc waiting for the current window to release the input and then take over. thers a new Winctl message Topped that basically does that now using Wakeup and a chan to synchronize.
This commit is contained in:
parent
54d2424a7c
commit
99216e0129
5 changed files with 71 additions and 47 deletions
|
@ -61,13 +61,14 @@ enum /* control messages */
|
||||||
Wakeup,
|
Wakeup,
|
||||||
Reshaped,
|
Reshaped,
|
||||||
Moved,
|
Moved,
|
||||||
|
Topped,
|
||||||
|
Repaint,
|
||||||
Refresh,
|
Refresh,
|
||||||
Movemouse,
|
Movemouse,
|
||||||
Rawon,
|
Rawon,
|
||||||
Rawoff,
|
Rawoff,
|
||||||
Holdon,
|
Holdon,
|
||||||
Holdoff,
|
Holdoff,
|
||||||
Repaint,
|
|
||||||
Deleted,
|
Deleted,
|
||||||
Exited,
|
Exited,
|
||||||
};
|
};
|
||||||
|
@ -76,7 +77,7 @@ struct Wctlmesg
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
Rectangle r;
|
Rectangle r;
|
||||||
Image *image;
|
void *p;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Conswritemesg
|
struct Conswritemesg
|
||||||
|
@ -132,7 +133,7 @@ struct Window
|
||||||
Mousectl mc;
|
Mousectl mc;
|
||||||
Mouseinfo mouse;
|
Mouseinfo mouse;
|
||||||
Channel *ck; /* chan(char*) */
|
Channel *ck; /* chan(char*) */
|
||||||
Channel *cctl; /* chan(Wctlmesg)[20] */
|
Channel *cctl; /* chan(Wctlmesg)[4] */
|
||||||
Channel *conswrite; /* chan(Conswritemesg) */
|
Channel *conswrite; /* chan(Conswritemesg) */
|
||||||
Channel *consread; /* chan(Consreadmesg) */
|
Channel *consread; /* chan(Consreadmesg) */
|
||||||
Channel *mouseread; /* chan(Mousereadmesg) */
|
Channel *mouseread; /* chan(Mousereadmesg) */
|
||||||
|
@ -188,8 +189,7 @@ char* wcontents(Window*, int*);
|
||||||
int wbswidth(Window*, Rune);
|
int wbswidth(Window*, Rune);
|
||||||
int wclickmatch(Window*, int, int, int, uint*);
|
int wclickmatch(Window*, int, int, int, uint*);
|
||||||
int wclose(Window*);
|
int wclose(Window*);
|
||||||
int wctlmesg(Window*, int, Rectangle, Image*);
|
int wctlmesg(Window*, int, Rectangle, void*);
|
||||||
int wctlmesg(Window*, int, Rectangle, Image*);
|
|
||||||
uint wbacknl(Window*, uint, uint);
|
uint wbacknl(Window*, uint, uint);
|
||||||
uint winsert(Window*, Rune*, int, uint);
|
uint winsert(Window*, Rune*, int, uint);
|
||||||
void waddraw(Window*, Rune*, int);
|
void waddraw(Window*, Rune*, int);
|
||||||
|
@ -213,7 +213,7 @@ void wresize(Window*, Image*, int);
|
||||||
void wscrdraw(Window*);
|
void wscrdraw(Window*);
|
||||||
void wscroll(Window*, int);
|
void wscroll(Window*, int);
|
||||||
void wselect(Window*);
|
void wselect(Window*);
|
||||||
void wsendctlmesg(Window*, int, Rectangle, Image*);
|
void wsendctlmesg(Window*, int, Rectangle, void*);
|
||||||
void wsetcursor(Window*, int);
|
void wsetcursor(Window*, int);
|
||||||
void wsetname(Window*);
|
void wsetname(Window*);
|
||||||
void wsetorigin(Window*, uint, int);
|
void wsetorigin(Window*, uint, int);
|
||||||
|
|
|
@ -345,7 +345,7 @@ keyboardthread(void*)
|
||||||
while(s = recvp(kbdchan)){
|
while(s = recvp(kbdchan)){
|
||||||
if(*s == 'k' || *s == 'K')
|
if(*s == 'k' || *s == 'K')
|
||||||
shiftdown = utfrune(s+1, Kshift) != nil;
|
shiftdown = utfrune(s+1, Kshift) != nil;
|
||||||
if(input == nil || input->deleted || sendp(input->ck, s) <= 0)
|
if(input == nil || sendp(input->ck, s) <= 0)
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1113,10 +1113,8 @@ resize(void)
|
||||||
return;
|
return;
|
||||||
incref(w);
|
incref(w);
|
||||||
i = sweep();
|
i = sweep();
|
||||||
if(i){
|
if(i)
|
||||||
wsendctlmesg(w, Reshaped, i->r, i);
|
wsendctlmesg(w, Reshaped, i->r, i);
|
||||||
wcurrent(w);
|
|
||||||
}
|
|
||||||
wclose(w);
|
wclose(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1132,10 +1130,8 @@ move(void)
|
||||||
return;
|
return;
|
||||||
incref(w);
|
incref(w);
|
||||||
i = drag(w, &r);
|
i = drag(w, &r);
|
||||||
if(i){
|
if(i)
|
||||||
wsendctlmesg(w, Moved, r, i);
|
wsendctlmesg(w, Moved, r, i);
|
||||||
wcurrent(w);
|
|
||||||
}
|
|
||||||
cornercursor(w, mouse->xy, 1);
|
cornercursor(w, mouse->xy, 1);
|
||||||
wclose(w);
|
wclose(w);
|
||||||
}
|
}
|
||||||
|
@ -1154,8 +1150,6 @@ whide(Window *w)
|
||||||
incref(w);
|
incref(w);
|
||||||
i = allocimage(display, w->screenr, w->i->chan, 0, DNofill);
|
i = allocimage(display, w->screenr, w->i->chan, 0, DNofill);
|
||||||
if(i){
|
if(i){
|
||||||
if(w == input)
|
|
||||||
input = nil;
|
|
||||||
hidden[nhidden++] = w;
|
hidden[nhidden++] = w;
|
||||||
wsendctlmesg(w, Reshaped, ZR, i);
|
wsendctlmesg(w, Reshaped, ZR, i);
|
||||||
}
|
}
|
||||||
|
@ -1180,7 +1174,6 @@ wunhide(Window *w)
|
||||||
--nhidden;
|
--nhidden;
|
||||||
memmove(hidden+j, hidden+j+1, (nhidden-j)*sizeof(Window*));
|
memmove(hidden+j, hidden+j+1, (nhidden-j)*sizeof(Window*));
|
||||||
wsendctlmesg(w, Reshaped, w->i->r, i);
|
wsendctlmesg(w, Reshaped, w->i->r, i);
|
||||||
wcurrent(w);
|
|
||||||
}
|
}
|
||||||
wclose(w);
|
wclose(w);
|
||||||
return i!=0;
|
return i!=0;
|
||||||
|
@ -1257,7 +1250,6 @@ new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **ar
|
||||||
threadcreate(winctl, w, 8192);
|
threadcreate(winctl, w, 8192);
|
||||||
if(!hideit)
|
if(!hideit)
|
||||||
wcurrent(w);
|
wcurrent(w);
|
||||||
flushimage(display, 1);
|
|
||||||
if(pid == 0){
|
if(pid == 0){
|
||||||
arg = emalloc(5*sizeof(void*));
|
arg = emalloc(5*sizeof(void*));
|
||||||
arg[0] = w;
|
arg[0] = w;
|
||||||
|
|
|
@ -388,6 +388,7 @@ wctlcmd(Window *w, Rectangle r, int cmd, char *err)
|
||||||
wbottomme(w);
|
wbottomme(w);
|
||||||
return 1;
|
return 1;
|
||||||
case Current:
|
case Current:
|
||||||
|
wtopme(w);
|
||||||
wcurrent(w);
|
wcurrent(w);
|
||||||
return 1;
|
return 1;
|
||||||
case Hide:
|
case Hide:
|
||||||
|
|
|
@ -113,10 +113,7 @@ wresize(Window *w, Image *i, int move)
|
||||||
wsetselect(w, w->q0, w->q1);
|
wsetselect(w, w->q0, w->q1);
|
||||||
wscrdraw(w);
|
wscrdraw(w);
|
||||||
}
|
}
|
||||||
if(w == input)
|
wborder(w, Selborder);
|
||||||
wborder(w, Selborder);
|
|
||||||
else
|
|
||||||
wborder(w, Unselborder);
|
|
||||||
wsetname(w);
|
wsetname(w);
|
||||||
w->topped = ++topped;
|
w->topped = ++topped;
|
||||||
w->resized = TRUE;
|
w->resized = TRUE;
|
||||||
|
@ -312,7 +309,7 @@ winctl(void *arg)
|
||||||
send(mrm.cm, &m.Mouse);
|
send(mrm.cm, &m.Mouse);
|
||||||
continue;
|
continue;
|
||||||
case WCtl:
|
case WCtl:
|
||||||
if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
|
if(wctlmesg(w, wcm.type, wcm.r, wcm.p) == Exited){
|
||||||
for(i=0; i<nelem(kbdq); i++)
|
for(i=0; i<nelem(kbdq); i++)
|
||||||
free(kbdq[i]);
|
free(kbdq[i]);
|
||||||
chanfree(crm.c1);
|
chanfree(crm.c1);
|
||||||
|
@ -1058,26 +1055,29 @@ wselect(Window *w)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
|
wsendctlmesg(Window *w, int type, Rectangle r, void *p)
|
||||||
{
|
{
|
||||||
Wctlmesg wcm;
|
Wctlmesg wcm;
|
||||||
|
|
||||||
wcm.type = type;
|
wcm.type = type;
|
||||||
wcm.r = r;
|
wcm.r = r;
|
||||||
wcm.image = image;
|
wcm.p = p;
|
||||||
send(w->cctl, &wcm);
|
send(w->cctl, &wcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
wctlmesg(Window *w, int m, Rectangle r, Image *i)
|
wctlmesg(Window *w, int m, Rectangle r, void *p)
|
||||||
{
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
Image *i = p;
|
||||||
|
|
||||||
switch(m){
|
switch(m){
|
||||||
default:
|
default:
|
||||||
error("unknown control message");
|
error("unknown control message");
|
||||||
break;
|
break;
|
||||||
case Wakeup:
|
case Wakeup:
|
||||||
|
if(p!=nil)
|
||||||
|
sendp((Channel*)p, w);
|
||||||
break;
|
break;
|
||||||
case Moved:
|
case Moved:
|
||||||
case Reshaped:
|
case Reshaped:
|
||||||
|
@ -1090,6 +1090,55 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
|
||||||
wresize(w, i, m==Moved);
|
wresize(w, i, m==Moved);
|
||||||
proccreate(deletetimeoutproc, estrdup(buf), 4096);
|
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(w==input)
|
||||||
|
input = nil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through to get input if needed */
|
||||||
|
case Topped:
|
||||||
|
if(w->deleted || w==input)
|
||||||
|
break;
|
||||||
|
if(input!=nil){
|
||||||
|
Window *oi;
|
||||||
|
Channel *c;
|
||||||
|
|
||||||
|
oi = input;
|
||||||
|
incref(oi);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* have to wait until old input responds before
|
||||||
|
* changing input to us because the window might
|
||||||
|
* currently be mouse tracking and it is not
|
||||||
|
* prepared for getting its input revoked.
|
||||||
|
*/
|
||||||
|
c = chancreate(sizeof(void*), 0);
|
||||||
|
wsendctlmesg(oi, Wakeup, ZR, c);
|
||||||
|
recv(c, nil);
|
||||||
|
chanfree(c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we are still top window and nobody else has taken
|
||||||
|
* input from original window, take the input.
|
||||||
|
*/
|
||||||
|
if(!w->deleted && w->topped==topped && oi==input){
|
||||||
|
input = w;
|
||||||
|
|
||||||
|
oi->wctlready = 1;
|
||||||
|
wsendctlmesg(oi, Repaint, ZR, nil);
|
||||||
|
}
|
||||||
|
wclose(oi);
|
||||||
|
} else
|
||||||
|
input = w;
|
||||||
|
w->wctlready = 1;
|
||||||
|
if(m!=Topped && w==input)
|
||||||
|
break;
|
||||||
|
/* fall thrugh for redraw after input change */
|
||||||
|
case Repaint:
|
||||||
|
if(w->deleted || Dx(w->screenr)<=0)
|
||||||
|
break;
|
||||||
|
wrepaint(w);
|
||||||
|
flushimage(display, 1);
|
||||||
break;
|
break;
|
||||||
case Refresh:
|
case Refresh:
|
||||||
if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r) || w->mouseopen)
|
if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r) || w->mouseopen)
|
||||||
|
@ -1114,12 +1163,10 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
|
||||||
break;
|
break;
|
||||||
case Holdon:
|
case Holdon:
|
||||||
case Holdoff:
|
case Holdoff:
|
||||||
if(w == input)
|
|
||||||
wsetcursor(w, 0);
|
|
||||||
/* no break */
|
|
||||||
case Repaint:
|
|
||||||
if(w->deleted)
|
if(w->deleted)
|
||||||
break;
|
break;
|
||||||
|
if(w==input)
|
||||||
|
wsetcursor(w, 0);
|
||||||
wrepaint(w);
|
wrepaint(w);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
break;
|
break;
|
||||||
|
@ -1206,22 +1253,8 @@ wpointto(Point pt)
|
||||||
void
|
void
|
||||||
wcurrent(Window *w)
|
wcurrent(Window *w)
|
||||||
{
|
{
|
||||||
Window *oi;
|
if(w!=nil && w!=input)
|
||||||
|
wsendctlmesg(w, Topped, ZR, nil);
|
||||||
if(wkeyboard!=nil && w==wkeyboard)
|
|
||||||
return;
|
|
||||||
oi = input;
|
|
||||||
input = w;
|
|
||||||
if(w != oi){
|
|
||||||
if(oi){
|
|
||||||
oi->wctlready = 1;
|
|
||||||
wsendctlmesg(oi, Repaint, ZR, nil);
|
|
||||||
}
|
|
||||||
if(w){
|
|
||||||
w->wctlready = 1;
|
|
||||||
wsendctlmesg(w, Repaint, ZR, nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -190,7 +190,6 @@ xfidattach(Xfid *x)
|
||||||
if(pid == 0)
|
if(pid == 0)
|
||||||
pid = -1; /* make sure we don't pop a shell! - UGH */
|
pid = -1; /* make sure we don't pop a shell! - UGH */
|
||||||
w = new(i, hideit, scrollit, pid, nil, nil, nil);
|
w = new(i, hideit, scrollit, pid, nil, nil, nil);
|
||||||
flushimage(display, 1);
|
|
||||||
newlymade = TRUE;
|
newlymade = TRUE;
|
||||||
}else
|
}else
|
||||||
err = Ewindow;
|
err = Ewindow;
|
||||||
|
@ -550,7 +549,6 @@ xfidwrite(Xfid *x)
|
||||||
filsysrespond(x->fs, x, &fc, buf);
|
filsysrespond(x->fs, x, &fc, buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flushimage(display, 1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue