From 624c9f51125ded8cc3e2aa715558cf9c4a6f7108 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 20 Oct 2012 22:42:01 +0200 Subject: 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. --- sys/src/cmd/rio/dat.h | 2 + sys/src/cmd/rio/fns.h | 2 +- sys/src/cmd/rio/rio.c | 170 +++++++++++++++++++++++++++++-------------------- sys/src/cmd/rio/wctl.c | 112 +++++++++++++++++--------------- sys/src/cmd/rio/wind.c | 110 ++++++++++++++++---------------- 5 files changed, 218 insertions(+), 178 deletions(-) diff --git a/sys/src/cmd/rio/dat.h b/sys/src/cmd/rio/dat.h index 17d0747ae..d74d6e425 100644 --- a/sys/src/cmd/rio/dat.h +++ b/sys/src/cmd/rio/dat.h @@ -67,6 +67,7 @@ enum /* control messages */ Rawoff, Holdon, Holdoff, + Repaint, Deleted, Exited, }; @@ -194,6 +195,7 @@ uint wbacknl(Window*, uint, uint); uint winsert(Window*, Rune*, int, uint); void waddraw(Window*, Rune*, int); void wborder(Window*, int); +void wclunk(Window*); void wclosewin(Window*); void wcurrent(Window*); void wcut(Window*); diff --git a/sys/src/cmd/rio/fns.h b/sys/src/cmd/rio/fns.h index d6e152e35..702eb101e 100644 --- a/sys/src/cmd/rio/fns.h +++ b/sys/src/cmd/rio/fns.h @@ -1,6 +1,6 @@ void keyboardsend(char*, int); int whide(Window*); -int wunhide(int); +int wunhide(Window*); void freescrtemps(void); int parsewctl(char**, Rectangle, Rectangle*, int*, int*, int*, int*, char**, char*, char*); int writewctl(Xfid*, char*); diff --git a/sys/src/cmd/rio/rio.c b/sys/src/cmd/rio/rio.c index 87137e483..98d3dd10b 100644 --- a/sys/src/cmd/rio/rio.c +++ b/sys/src/cmd/rio/rio.c @@ -347,7 +347,7 @@ keyboardthread(void*) while(s = recvp(kbdchan)){ if(*s == 'k' || *s == 'K') 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); } } @@ -470,7 +470,7 @@ void mousethread(void*) { int sending, inside, scrolling, moving, band; - Window *oin, *w, *winput; + Window *w, *winput; Image *i; Rectangle r; Point xy; @@ -513,7 +513,7 @@ mousethread(void*) wtopme(wkeyboard); winput = wkeyboard; } - if(winput!=nil && winput->i!=nil){ + if(winput!=nil && !winput->deleted && winput->i!=nil){ /* convert to logical coordinates */ 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); @@ -555,7 +555,7 @@ mousethread(void*) else riosetcursor(nil, 0); if(moving && (mouse->buttons&7)){ - oin = winput; + incref(winput); band = mouse->buttons & 3; sweeping = 1; if(band) @@ -564,18 +564,19 @@ mousethread(void*) i = drag(winput, &r); sweeping = 0; if(i != nil){ - if(winput == oin){ - if(band) - wsendctlmesg(winput, Reshaped, i->r, i); - else - wsendctlmesg(winput, Moved, r, i); - cornercursor(winput, mouse->xy, 1); - }else - freeimage(i); + if(band) + wsendctlmesg(winput, Reshaped, i->r, i); + else + wsendctlmesg(winput, Moved, r, i); + cornercursor(winput, mouse->xy, 1); + } + if(wclose(winput) == 0) + 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 */ if(mouse->buttons){ /* w->topped will be zero or less if window has been bottomed */ @@ -583,8 +584,11 @@ mousethread(void*) if(mouse->buttons & 1){ ; }else if(mouse->buttons & 2){ - if(winput && !winput->mouseopen) + if(winput && !winput->deleted && !winput->mouseopen){ + incref(winput); button2menu(winput); + wclose(winput); + } }else if(mouse->buttons & 4) button3menu(); }else{ @@ -607,11 +611,17 @@ mousethread(void*) } } +int +wtopcmp(void *a, void *b) +{ + return (*(Window**)a)->topped - (*(Window**)b)->topped; +} + void resized(void) { Image *im; - int i, j, ishidden; + int i, j; Rectangle r; Point o, n; Window *w; @@ -627,10 +637,9 @@ resized(void) draw(view, view->r, background, nil, ZP); o = subpt(viewr.max, viewr.min); n = subpt(view->clipr.max, view->clipr.min); + qsort(window, nwindow, sizeof(window[0]), wtopcmp); for(i=0; ideleted) - continue; r = rectsubpt(w->i->r, viewr.min); r.min.x = (r.min.x*n.x)/o.x; r.min.y = (r.min.y*n.y)/o.y; @@ -639,26 +648,25 @@ resized(void) if(!goodrect(r)) r = rectsubpt(w->i->r, viewr.min); r = rectaddpt(r, screen->clipr.min); - ishidden = 0; for(j=0; jchan, 0, DWhite); r = ZR; - }else + } else im = allocwindow(wscreen, r, Refbackup, DWhite); if(im) wsendctlmesg(w, Reshaped, r, im); + wclose(w); } viewr = screen->r; flushimage(display, 1); } -static int -wcovered(Window *w, Rectangle r, int i) +int +obscured(Window *w, Rectangle r, int i) { Window *t; @@ -668,21 +676,21 @@ wcovered(Window *w, Rectangle r, int i) return 1; for(; itopped <= w->topped || t->deleted) + if(t == w || t->topped <= w->topped) continue; if(Dx(t->screenr) == 0 || Dy(t->screenr) == 0 || rectXrect(r, t->screenr) == 0) continue; 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; 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; 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; 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 1; } @@ -699,13 +707,12 @@ button3menu(void) for(j=0; jdeleted) - continue; - if(wcovered(window[i], window[i]->screenr, 0)){ - hidden[n++] = window[i]; - if(n >= nelem(hidden)) - break; - } + if(j == n) + if(obscured(window[i], window[i]->screenr, 0)){ + hidden[n++] = window[i]; + if(n >= nelem(hidden)) + break; + } } if(n >= nelem(menu3str)-Hidden) n = nelem(menu3str)-Hidden-1; @@ -752,9 +759,6 @@ button3menu(void) void button2menu(Window *w) { - if(w->deleted) - return; - incref(w); if(w->scrolling) menu2str[Scroll] = "noscroll"; else @@ -803,7 +807,6 @@ button2menu(Window *w) wshow(w, w->nr); break; } - wclose(w); wsendctlmesg(w, Wakeup, ZR, nil); flushimage(display, 1); } @@ -1113,9 +1116,13 @@ resize(void) w = pointto(TRUE); if(w == nil) return; + incref(w); i = sweep(); - if(i) + if(i){ wsendctlmesg(w, Reshaped, i->r, i); + wcurrent(w); + } + wclose(w); } void @@ -1128,10 +1135,14 @@ move(void) w = pointto(FALSE); if(w == nil) return; + incref(w); i = drag(w, &r); - if(i) + if(i){ wsendctlmesg(w, Moved, r, i); - cornercursor(input, mouse->xy, 1); + wcurrent(w); + } + cornercursor(w, mouse->xy, 1); + wclose(w); } int @@ -1145,38 +1156,39 @@ whide(Window *w) return -1; if(nhidden >= nelem(hidden)) return 0; + incref(w); i = allocimage(display, w->screenr, w->i->chan, 0, DWhite); if(i){ + if(w == input) + input = nil; hidden[nhidden++] = w; wsendctlmesg(w, Reshaped, ZR, i); - return 1; } - return 0; + wclose(w); + return i!=0; } int -wunhide(int h) +wunhide(Window *w) { + int j; Image *i; - Window *w; - w = hidden[h]; - if(w == nil) - return 0; - if(h >= nhidden){ - wtopme(w); - wcurrent(w); - flushimage(display, 1); - return 1; - } + for(j=0; j