rio: preserve window z-order on resize, fix race conditions

sort the window array by w->topped before reshaping all
windows. this preserves the window z-order.

remove implicit focus change on reshape/move. it called
wcurrent() in wtcl thread which might send a wctl message
to itself, bad... also we might not want to change focus
on reshape, like for the rio resize. so we set the input
window explicitely in all call sites.

window deletion was racy. wclosewin() destroys w->i, but
it is called outside the wctl thread so it might just
free the image under libframe doing some text selection.
this is fixed the following: add wclunk() function,
which basically just marks the window as deleted and
removes the reference from the window[] and hidden[]
arrays. (called on wclose() when refcount drops to
zero). wclosewin() now just frees the image and is only
called from the wctl thread on exit or when handing
the Deleted message.

get a reference to the window when doing sweeping or
moving as the filesystem might just clunk it under
us and we might end up sending wctl messages to
a Exited window.

wctl resize message has to fail if the window is not
current as it might be hidden... would also be annoying.
This commit is contained in:
cinap_lenrek 2012-10-20 22:42:01 +02:00
parent 558b9558d4
commit 624c9f5112
5 changed files with 223 additions and 183 deletions

View file

@ -67,6 +67,7 @@ enum /* control messages */
Rawoff, Rawoff,
Holdon, Holdon,
Holdoff, Holdoff,
Repaint,
Deleted, Deleted,
Exited, Exited,
}; };
@ -194,6 +195,7 @@ 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);
void wborder(Window*, int); void wborder(Window*, int);
void wclunk(Window*);
void wclosewin(Window*); void wclosewin(Window*);
void wcurrent(Window*); void wcurrent(Window*);
void wcut(Window*); void wcut(Window*);

View file

@ -1,6 +1,6 @@
void keyboardsend(char*, int); void keyboardsend(char*, int);
int whide(Window*); int whide(Window*);
int wunhide(int); int wunhide(Window*);
void freescrtemps(void); void freescrtemps(void);
int parsewctl(char**, Rectangle, Rectangle*, int*, int*, int*, int*, char**, char*, char*); int parsewctl(char**, Rectangle, Rectangle*, int*, int*, int*, int*, char**, char*, char*);
int writewctl(Xfid*, char*); int writewctl(Xfid*, char*);

View file

@ -347,7 +347,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 || sendp(input->ck, s) <= 0) if(input == nil || input->deleted || sendp(input->ck, s) <= 0)
free(s); free(s);
} }
} }
@ -470,7 +470,7 @@ void
mousethread(void*) mousethread(void*)
{ {
int sending, inside, scrolling, moving, band; int sending, inside, scrolling, moving, band;
Window *oin, *w, *winput; Window *w, *winput;
Image *i; Image *i;
Rectangle r; Rectangle r;
Point xy; Point xy;
@ -513,7 +513,7 @@ mousethread(void*)
wtopme(wkeyboard); wtopme(wkeyboard);
winput = wkeyboard; winput = wkeyboard;
} }
if(winput!=nil && winput->i!=nil){ if(winput!=nil && !winput->deleted && winput->i!=nil){
/* convert to logical coordinates */ /* convert to logical coordinates */
xy.x = mouse->xy.x + (winput->i->r.min.x-winput->screenr.min.x); xy.x = mouse->xy.x + (winput->i->r.min.x-winput->screenr.min.x);
xy.y = mouse->xy.y + (winput->i->r.min.y-winput->screenr.min.y); xy.y = mouse->xy.y + (winput->i->r.min.y-winput->screenr.min.y);
@ -555,7 +555,7 @@ mousethread(void*)
else else
riosetcursor(nil, 0); riosetcursor(nil, 0);
if(moving && (mouse->buttons&7)){ if(moving && (mouse->buttons&7)){
oin = winput; incref(winput);
band = mouse->buttons & 3; band = mouse->buttons & 3;
sweeping = 1; sweeping = 1;
if(band) if(band)
@ -564,18 +564,19 @@ mousethread(void*)
i = drag(winput, &r); i = drag(winput, &r);
sweeping = 0; sweeping = 0;
if(i != nil){ if(i != nil){
if(winput == oin){ if(band)
if(band) wsendctlmesg(winput, Reshaped, i->r, i);
wsendctlmesg(winput, Reshaped, i->r, i); else
else wsendctlmesg(winput, Moved, r, i);
wsendctlmesg(winput, Moved, r, i); cornercursor(winput, mouse->xy, 1);
cornercursor(winput, mouse->xy, 1); }
}else if(wclose(winput) == 0)
freeimage(i); w = winput;
else {
riosetcursor(nil, 0);
w = nil;
} }
} }
if(w != nil)
cornercursor(w, mouse->xy, 0);
/* we're not sending the event, but if button is down maybe we should */ /* we're not sending the event, but if button is down maybe we should */
if(mouse->buttons){ if(mouse->buttons){
/* w->topped will be zero or less if window has been bottomed */ /* w->topped will be zero or less if window has been bottomed */
@ -583,8 +584,11 @@ mousethread(void*)
if(mouse->buttons & 1){ if(mouse->buttons & 1){
; ;
}else if(mouse->buttons & 2){ }else if(mouse->buttons & 2){
if(winput && !winput->mouseopen) if(winput && !winput->deleted && !winput->mouseopen){
incref(winput);
button2menu(winput); button2menu(winput);
wclose(winput);
}
}else if(mouse->buttons & 4) }else if(mouse->buttons & 4)
button3menu(); button3menu();
}else{ }else{
@ -607,11 +611,17 @@ mousethread(void*)
} }
} }
int
wtopcmp(void *a, void *b)
{
return (*(Window**)a)->topped - (*(Window**)b)->topped;
}
void void
resized(void) resized(void)
{ {
Image *im; Image *im;
int i, j, ishidden; int i, j;
Rectangle r; Rectangle r;
Point o, n; Point o, n;
Window *w; Window *w;
@ -627,10 +637,9 @@ resized(void)
draw(view, view->r, background, nil, ZP); draw(view, view->r, background, nil, ZP);
o = subpt(viewr.max, viewr.min); o = subpt(viewr.max, viewr.min);
n = subpt(view->clipr.max, view->clipr.min); n = subpt(view->clipr.max, view->clipr.min);
qsort(window, nwindow, sizeof(window[0]), wtopcmp);
for(i=0; i<nwindow; i++){ for(i=0; i<nwindow; i++){
w = window[i]; w = window[i];
if(w->deleted)
continue;
r = rectsubpt(w->i->r, viewr.min); r = rectsubpt(w->i->r, viewr.min);
r.min.x = (r.min.x*n.x)/o.x; r.min.x = (r.min.x*n.x)/o.x;
r.min.y = (r.min.y*n.y)/o.y; r.min.y = (r.min.y*n.y)/o.y;
@ -639,26 +648,25 @@ resized(void)
if(!goodrect(r)) if(!goodrect(r))
r = rectsubpt(w->i->r, viewr.min); r = rectsubpt(w->i->r, viewr.min);
r = rectaddpt(r, screen->clipr.min); r = rectaddpt(r, screen->clipr.min);
ishidden = 0;
for(j=0; j<nhidden; j++) for(j=0; j<nhidden; j++)
if(w == hidden[j]){ if(w == hidden[j])
ishidden = 1;
break; break;
} incref(w);
if(ishidden){ if(j < nhidden){
im = allocimage(display, r, screen->chan, 0, DWhite); im = allocimage(display, r, screen->chan, 0, DWhite);
r = ZR; r = ZR;
}else } else
im = allocwindow(wscreen, r, Refbackup, DWhite); im = allocwindow(wscreen, r, Refbackup, DWhite);
if(im) if(im)
wsendctlmesg(w, Reshaped, r, im); wsendctlmesg(w, Reshaped, r, im);
wclose(w);
} }
viewr = screen->r; viewr = screen->r;
flushimage(display, 1); flushimage(display, 1);
} }
static int int
wcovered(Window *w, Rectangle r, int i) obscured(Window *w, Rectangle r, int i)
{ {
Window *t; Window *t;
@ -668,21 +676,21 @@ wcovered(Window *w, Rectangle r, int i)
return 1; return 1;
for(; i<nwindow; i++){ for(; i<nwindow; i++){
t = window[i]; t = window[i];
if(t == w || t->topped <= w->topped || t->deleted) if(t == w || t->topped <= w->topped)
continue; continue;
if(Dx(t->screenr) == 0 || Dy(t->screenr) == 0 || rectXrect(r, t->screenr) == 0) if(Dx(t->screenr) == 0 || Dy(t->screenr) == 0 || rectXrect(r, t->screenr) == 0)
continue; continue;
if(r.min.y < t->screenr.min.y) if(r.min.y < t->screenr.min.y)
if(!wcovered(w, Rect(r.min.x, r.min.y, r.max.x, t->screenr.min.y), i)) if(!obscured(w, Rect(r.min.x, r.min.y, r.max.x, t->screenr.min.y), i))
return 0; return 0;
if(r.min.x < t->screenr.min.x) if(r.min.x < t->screenr.min.x)
if(!wcovered(w, Rect(r.min.x, r.min.y, t->screenr.min.x, r.max.y), i)) if(!obscured(w, Rect(r.min.x, r.min.y, t->screenr.min.x, r.max.y), i))
return 0; return 0;
if(r.max.y > t->screenr.max.y) if(r.max.y > t->screenr.max.y)
if(!wcovered(w, Rect(r.min.x, t->screenr.max.y, r.max.x, r.max.y), i)) if(!obscured(w, Rect(r.min.x, t->screenr.max.y, r.max.x, r.max.y), i))
return 0; return 0;
if(r.max.x > t->screenr.max.x) if(r.max.x > t->screenr.max.x)
if(!wcovered(w, Rect(t->screenr.max.x, r.min.y, r.max.x, r.max.y), i)) if(!obscured(w, Rect(t->screenr.max.x, r.min.y, r.max.x, r.max.y), i))
return 0; return 0;
return 1; return 1;
} }
@ -699,13 +707,12 @@ button3menu(void)
for(j=0; j<n; j++) for(j=0; j<n; j++)
if(window[i] == hidden[j]) if(window[i] == hidden[j])
break; break;
if(j < n || window[i]->deleted) if(j == n)
continue; if(obscured(window[i], window[i]->screenr, 0)){
if(wcovered(window[i], window[i]->screenr, 0)){ hidden[n++] = window[i];
hidden[n++] = window[i]; if(n >= nelem(hidden))
if(n >= nelem(hidden)) break;
break; }
}
} }
if(n >= nelem(menu3str)-Hidden) if(n >= nelem(menu3str)-Hidden)
n = nelem(menu3str)-Hidden-1; n = nelem(menu3str)-Hidden-1;
@ -752,9 +759,6 @@ button3menu(void)
void void
button2menu(Window *w) button2menu(Window *w)
{ {
if(w->deleted)
return;
incref(w);
if(w->scrolling) if(w->scrolling)
menu2str[Scroll] = "noscroll"; menu2str[Scroll] = "noscroll";
else else
@ -803,7 +807,6 @@ button2menu(Window *w)
wshow(w, w->nr); wshow(w, w->nr);
break; break;
} }
wclose(w);
wsendctlmesg(w, Wakeup, ZR, nil); wsendctlmesg(w, Wakeup, ZR, nil);
flushimage(display, 1); flushimage(display, 1);
} }
@ -1113,9 +1116,13 @@ resize(void)
w = pointto(TRUE); w = pointto(TRUE);
if(w == nil) if(w == nil)
return; return;
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);
} }
void void
@ -1128,10 +1135,14 @@ move(void)
w = pointto(FALSE); w = pointto(FALSE);
if(w == nil) if(w == nil)
return; return;
incref(w);
i = drag(w, &r); i = drag(w, &r);
if(i) if(i){
wsendctlmesg(w, Moved, r, i); wsendctlmesg(w, Moved, r, i);
cornercursor(input, mouse->xy, 1); wcurrent(w);
}
cornercursor(w, mouse->xy, 1);
wclose(w);
} }
int int
@ -1145,38 +1156,39 @@ whide(Window *w)
return -1; return -1;
if(nhidden >= nelem(hidden)) if(nhidden >= nelem(hidden))
return 0; return 0;
incref(w);
i = allocimage(display, w->screenr, w->i->chan, 0, DWhite); i = allocimage(display, w->screenr, w->i->chan, 0, DWhite);
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);
return 1;
} }
return 0; wclose(w);
return i!=0;
} }
int int
wunhide(int h) wunhide(Window *w)
{ {
int j;
Image *i; Image *i;
Window *w;
w = hidden[h]; for(j=0; j<nhidden; j++)
if(w == nil) if(hidden[j] == w)
return 0; break;
if(h >= nhidden){ if(j == nhidden)
wtopme(w); return -1; /* not hidden */
wcurrent(w); incref(w);
flushimage(display, 1);
return 1;
}
i = allocwindow(wscreen, w->i->r, Refbackup, DWhite); i = allocwindow(wscreen, w->i->r, Refbackup, DWhite);
if(i){ if(i){
--nhidden; --nhidden;
memmove(hidden+h, hidden+h+1, (nhidden-h)*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);
return 1; wcurrent(w);
} }
return 0; wclose(w);
return i!=0;
} }
void void
@ -1185,16 +1197,34 @@ hide(void)
Window *w; Window *w;
w = pointto(TRUE); w = pointto(TRUE);
if(w == nil) if(w)
return; whide(w);
whide(w);
} }
void void
unhide(int h) unhide(int j)
{ {
if(h >= Hidden) Window *w;
wunhide(h - Hidden);
if(j < Hidden)
return;
j -= Hidden;
w = hidden[j];
if(w == nil)
return;
if(j < nhidden){
wunhide(w);
return;
}
/* uncover obscured window */
for(j=0; j<nwindow; j++)
if(window[j] == w){
incref(w);
wcurrent(w);
wtopme(w);
wclose(w);
return;
}
} }
Window* Window*
@ -1207,6 +1237,10 @@ new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **ar
if(i == nil) if(i == nil)
return nil; return nil;
if(hideit && nhidden >= nelem(hidden)){
freeimage(i);
return nil;
}
cm = chancreate(sizeof(Mouse), 0); cm = chancreate(sizeof(Mouse), 0);
ck = chancreate(sizeof(char*), 0); ck = chancreate(sizeof(char*), 0);
cctl = chancreate(sizeof(Wctlmesg), 4); cctl = chancreate(sizeof(Wctlmesg), 4);
@ -1221,8 +1255,6 @@ new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **ar
free(mc); /* wmk copies *mc */ free(mc); /* wmk copies *mc */
window = erealloc(window, ++nwindow*sizeof(Window*)); window = erealloc(window, ++nwindow*sizeof(Window*));
window[nwindow-1] = w; window[nwindow-1] = w;
if(nhidden >= nelem(hidden))
hideit = 0;
if(hideit){ if(hideit){
hidden[nhidden++] = w; hidden[nhidden++] = w;
w->screenr = ZR; w->screenr = ZR;

View file

@ -346,68 +346,32 @@ wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir,
} }
int int
writewctl(Xfid *x, char *err) wctlcmd(Window *w, Rectangle r, int cmd, char *err)
{ {
int cnt, cmd, j, id, hideit, scrollit, pid;
Image *i; Image *i;
char *arg, *dir;
Rectangle rect;
Window *w;
w = x->f->w;
cnt = x->count;
x->data[cnt] = '\0';
id = 0;
rect = rectsubpt(w->screenr, screen->r.min);
cmd = parsewctl(&arg, rect, &rect, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
if(cmd < 0)
return -1;
if(mouse->buttons!=0 && cmd>=Top){
strcpy(err, "action disallowed when mouse active");
return -1;
}
if(id != 0){
for(j=0; j<nwindow; j++)
if(window[j]->id == id)
break;
if(j == nwindow){
strcpy(err, "no such window id");
return -1;
}
w = window[j];
if(w->deleted || w->i==nil){
strcpy(err, "window deleted");
return -1;
}
}
switch(cmd){ switch(cmd){
case New:
return wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
case Set:
if(pid > 0)
wsetpid(w, pid, 0);
return 1;
case Move: case Move:
rect = Rect(rect.min.x, rect.min.y, rect.min.x+Dx(w->screenr), rect.min.y+Dy(w->screenr)); r = Rect(r.min.x, r.min.y, r.min.x+Dx(w->screenr), r.min.y+Dy(w->screenr));
rect = rectonscreen(rect); r = rectonscreen(r);
/* fall through */ /* fall through */
case Resize: case Resize:
if(!goodrect(rect)){ if(!goodrect(r)){
strcpy(err, Ebadwr); strcpy(err, Ebadwr);
return -1; return -1;
} }
if(eqrect(rect, w->screenr)) if(w != input){
strcpy(err, "window not current");
return -1;
}
if(eqrect(r, w->screenr))
return 1; return 1;
i = allocwindow(wscreen, rect, Refbackup, DWhite); i = allocwindow(wscreen, r, Refbackup, DWhite);
if(i == nil){ if(i == nil){
strcpy(err, Ewalloc); strcpy(err, Ewalloc);
return -1; return -1;
} }
border(i, rect, Selborder, red, ZP); border(i, r, Selborder, red, ZP);
wsendctlmesg(w, Reshaped, i->r, i); wsendctlmesg(w, Reshaped, i->r, i);
return 1; return 1;
case Scroll: case Scroll:
@ -441,26 +405,68 @@ writewctl(Xfid *x, char *err)
} }
return 1; return 1;
case Unhide: case Unhide:
for(j=0; j<nhidden; j++) switch(wunhide(w)){
if(hidden[j] == w) case -1:
break;
if(j == nhidden){
strcpy(err, "window not hidden"); strcpy(err, "window not hidden");
return -1; return -1;
} case 0:
if(wunhide(j) == 0){
strcpy(err, "hide failed"); strcpy(err, "hide failed");
return -1; return -1;
default:
break;
} }
return 1; return 1;
case Delete: case Delete:
wsendctlmesg(w, Deleted, ZR, nil); wsendctlmesg(w, Deleted, ZR, nil);
return 1; return 1;
} }
strcpy(err, "invalid wctl message"); strcpy(err, "invalid wctl message");
return -1; return -1;
} }
int
writewctl(Xfid *x, char *err)
{
int cnt, cmd, id, hideit, scrollit, pid;
char *arg, *dir;
Rectangle r;
Window *w;
w = x->f->w;
cnt = x->count;
x->data[cnt] = '\0';
id = 0;
r = rectsubpt(w->screenr, screen->r.min);
cmd = parsewctl(&arg, r, &r, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
if(cmd < 0)
return -1;
if(id != 0){
w = wlookid(id);
if(w == 0){
strcpy(err, "no such window id");
return -1;
}
}
switch(cmd){
case New:
return wctlnew(r, arg, pid, hideit, scrollit, dir, err);
case Set:
if(pid > 0)
wsetpid(w, pid, 0);
return 1;
}
incref(w);
id = wctlcmd(w, r, cmd, err);
wclose(w);
return id;
}
void void
wctlthread(void *v) wctlthread(void *v)
{ {

View file

@ -131,7 +131,6 @@ wresize(Window *w, Image *i, int move)
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); freeimage(w->i);
w->i = i; w->i = i;
wsetname(w);
w->mc.image = i; w->mc.image = i;
r = insetrect(i->r, Selborder+1); r = insetrect(i->r, Selborder+1);
w->scrollr = r; w->scrollr = r;
@ -151,10 +150,15 @@ wresize(Window *w, Image *i, int move)
wsetselect(w, w->q0, w->q1); wsetselect(w, w->q0, w->q1);
wscrdraw(w); wscrdraw(w);
} }
wborder(w, Selborder); if(w == input)
wborder(w, Selborder);
else
wborder(w, Unselborder);
wsetname(w);
w->topped = ++topped; w->topped = ++topped;
w->resized = TRUE; w->resized = TRUE;
w->mouse.counter++; w->mouse.counter++;
w->wctlready = 1;
} }
void void
@ -189,7 +193,7 @@ wclose(Window *w)
if(i < 0) if(i < 0)
error("negative ref count"); error("negative ref count");
if(!w->deleted) if(!w->deleted)
wclosewin(w); wclunk(w);
wsendctlmesg(w, Exited, ZR, nil); wsendctlmesg(w, Exited, ZR, nil);
return 1; return 1;
} }
@ -1121,24 +1125,16 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
w->screenr = r; w->screenr = r;
strcpy(buf, w->name); strcpy(buf, w->name);
wresize(w, i, m==Moved); wresize(w, i, m==Moved);
w->wctlready = 1;
proccreate(deletetimeoutproc, estrdup(buf), 4096); proccreate(deletetimeoutproc, estrdup(buf), 4096);
if(Dx(r) > 0){
if(w != input)
wcurrent(w);
}else if(w == input)
wcurrent(nil);
flushimage(display, 1);
break; break;
case Refresh: case Refresh:
if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r)) if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r) || w->mouseopen)
break; break;
if(!w->mouseopen) wrefresh(w, r);
wrefresh(w, r);
flushimage(display, 1); flushimage(display, 1);
break; break;
case Movemouse: case Movemouse:
if(sweeping || !ptinrect(r.min, w->i->r)) if(w->deleted || Dx(w->screenr)<=0 || !ptinrect(r.min, w->i->r))
break; break;
wmovemouse(w, r.min); wmovemouse(w, r.min);
case Rawon: case Rawon:
@ -1154,6 +1150,7 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
break; break;
case Holdon: case Holdon:
case Holdoff: case Holdoff:
case Repaint:
if(w->deleted) if(w->deleted)
break; break;
wrepaint(w); wrepaint(w);
@ -1162,11 +1159,13 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
case Deleted: case Deleted:
if(w->deleted) if(w->deleted)
break; break;
wclunk(w);
write(w->notefd, "hangup", 6); write(w->notefd, "hangup", 6);
proccreate(deletetimeoutproc, estrdup(w->name), 4096); proccreate(deletetimeoutproc, estrdup(w->name), 4096);
wclosewin(w); wclosewin(w);
break; break;
case Exited: case Exited:
wclosewin(w);
frclear(w, TRUE); frclear(w, TRUE);
close(w->notefd); close(w->notefd);
chanfree(w->mc.c); chanfree(w->mc.c);
@ -1193,6 +1192,8 @@ wctlmesg(Window *w, int m, Rectangle r, Image *i)
void void
wmovemouse(Window *w, Point p) wmovemouse(Window *w, Point p)
{ {
if(w != input || menuing || sweeping)
return;
p.x += w->screenr.min.x-w->i->r.min.x; p.x += w->screenr.min.x-w->i->r.min.x;
p.y += w->screenr.min.y-w->i->r.min.y; p.y += w->screenr.min.y-w->i->r.min.y;
moveto(mousectl, p); moveto(mousectl, p);
@ -1216,7 +1217,6 @@ wborder(Window *w, int type)
else else
col = lighttitlecol; col = lighttitlecol;
} }
border(w->i, w->i->r, Selborder, col, ZP); border(w->i, w->i->r, Selborder, col, ZP);
} }
@ -1230,7 +1230,6 @@ wpointto(Point pt)
for(i=0; i<nwindow; i++){ for(i=0; i<nwindow; i++){
v = window[i]; v = window[i];
if(ptinrect(pt, v->screenr)) if(ptinrect(pt, v->screenr))
if(!v->deleted)
if(w==nil || v->topped>w->topped) if(w==nil || v->topped>w->topped)
w = v; w = v;
} }
@ -1246,20 +1245,14 @@ wcurrent(Window *w)
return; return;
oi = input; oi = input;
input = w; input = w;
if(oi!=w && oi!=nil)
wrepaint(oi);
if(w !=nil){
wrepaint(w);
wsetcursor(w, 0);
}
if(w != oi){ if(w != oi){
if(oi){ if(oi){
oi->wctlready = 1; oi->wctlready = 1;
wsendctlmesg(oi, Wakeup, ZR, nil); wsendctlmesg(oi, Repaint, ZR, nil);
} }
if(w){ if(w){
w->wctlready = 1; w->wctlready = 1;
wsendctlmesg(w, Wakeup, ZR, nil); wsendctlmesg(w, Repaint, ZR, nil);
} }
} }
} }
@ -1269,7 +1262,7 @@ wsetcursor(Window *w, int force)
{ {
Cursor *p; Cursor *p;
if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0) if(w==nil || w->deleted || w->i==nil || Dx(w->screenr)<=0)
p = nil; p = nil;
else if(wpointto(mouse->xy) == w){ else if(wpointto(mouse->xy) == w){
p = w->cursorp; p = w->cursorp;
@ -1290,6 +1283,27 @@ riosetcursor(Cursor *p, int force)
lastcursor = p; lastcursor = p;
} }
void
wtopme(Window *w)
{
if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
w->topped = ++topped;
topwindow(w->i);
flushimage(display, 1);
}
}
void
wbottomme(Window *w)
{
if(w!=nil && w->i!=nil && !w->deleted){
w->topped = - ++topped;
bottomwindow(w->i);
flushimage(display, 1);
}
}
Window* Window*
wtop(Point pt) wtop(Point pt)
{ {
@ -1299,34 +1313,14 @@ wtop(Point pt)
if(w){ if(w){
if(w->topped == topped) if(w->topped == topped)
return nil; return nil;
topwindow(w->i); incref(w);
wcurrent(w); wcurrent(w);
flushimage(display, 1); wtopme(w);
w->topped = ++topped; wclose(w);
} }
return w; return w;
} }
void
wtopme(Window *w)
{
if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
topwindow(w->i);
flushimage(display, 1);
w->topped = ++topped;
}
}
void
wbottomme(Window *w)
{
if(w!=nil && w->i!=nil && !w->deleted){
bottomwindow(w->i);
flushimage(display, 1);
w->topped = - ++topped;
}
}
Window* Window*
wlookid(int id) wlookid(int id)
{ {
@ -1339,12 +1333,10 @@ wlookid(int id)
} }
void void
wclosewin(Window *w) wclunk(Window *w)
{ {
Rectangle r;
int i; int i;
w->deleted = TRUE;
if(w == input){ if(w == input){
input = nil; input = nil;
wsetcursor(w, 0); wsetcursor(w, 0);
@ -1360,16 +1352,24 @@ wclosewin(Window *w)
for(i=0; i<nwindow; i++) for(i=0; i<nwindow; i++)
if(window[i] == w){ if(window[i] == w){
--nwindow; --nwindow;
memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*)); memmove(window+i, window+i+1, (nwindow-i)*sizeof(window[0]));
w->deleted = TRUE; break;
r = w->i->r;
/* move it off-screen to hide it, in case client is slow in letting it go */
MOVEIT originwindow(w->i, r.min, view->r.max);
freeimage(w->i);
w->i = nil;
return;
} }
error("unknown window in closewin"); w->deleted = TRUE;
}
void
wclosewin(Window *w)
{
Image *i;
i = w->i;
if(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);
}
} }
void void