shithub: riscv

Download patch

ref: 47b7dc5ccd77bc247ab15cfab3a7a8f955771c70
parent: 369cba5f938d3f804210b6e09d36c6f7ecb017fa
author: Igor Böhm <igor@9lab.org>
date: Tue Jan 4 14:11:07 EST 2022

acme: fix window and scrollbar display glitches at bottom fringe of column

The following patch fixes acme display glitches at the bottom fringe
of columns when adding/moving/resizing windows.

Here an example of an easy to reproduce case:

• https://invidio.xamh.de/watch?v=iLekQrxycaM

…opening acme and resizing a column to the right is all that is needed.

The functions winresize(…) and textresize(…) are extended with an
additional parameter `fillfringe` to indicate if a window/tag shall
fill a potential fringe area that would otherwise remain white.

The changes have been inspired by the approach taken in plan9port
acme.

--- a/sys/src/cmd/acme/acme.c
+++ b/sys/src/cmd/acme/acme.c
@@ -295,9 +295,6 @@
 	Command *c;
 
 	fsysclose();
-//	if(display)
-//		flushimage(display, 1);
-
 	for(c=command; c; c=c->next)
 		postnote(PNGROUP, c->pid, "hangup");
 	remove(acmeerrorfile);
--- a/sys/src/cmd/acme/cols.c
+++ b/sys/src/cmd/acme/cols.c
@@ -77,7 +77,7 @@
 		r1 = r;
 		y = min(y, t-(v->tag.font->height+v->body.font->height+Border+1));
 		r1.max.y = min(y, v->body.r.min.y+v->body.nlines*v->body.font->height);
-		r1.min.y = winresize(v, r1, FALSE);
+		r1.min.y = winresize(v, r1, FALSE, FALSE);
 		r1.max.y = r1.min.y+Border;
 		draw(screen, r1, display->black, nil, ZP);
 		r.min.y = r1.max.y;
@@ -90,7 +90,7 @@
 		wininit(w, clone, r);
 	}else{
 		w->col = c;
-		winresize(w, r, FALSE);
+		winresize(w, r, FALSE, TRUE);
 	}
 	w->tag.col = c;
 	w->tag.row = c->row;
@@ -152,7 +152,7 @@
 	if(c->safe) {
 		if(!didmouse && up)
 			w->showdel = TRUE;
-		winresize(w, r, FALSE);
+		winresize(w, r, FALSE, TRUE);
 		if(!didmouse && up)
 			movetodel(w);
 	}
@@ -193,7 +193,7 @@
 	clearmouse();
 	r1 = r;
 	r1.max.y = r1.min.y + c->tag.font->height;
-	textresize(&c->tag, r1);
+	textresize(&c->tag, r1, TRUE);
 	draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
 	r1.min.y = r1.max.y;
 	r1.max.y += Border;
@@ -208,14 +208,15 @@
 			r1.max.y = r.max.y;
 		else {
 			r1.max.y = r1.min.y;
-			if(new > 0 && old > 0 && Dy(w->r) > font->height)
-				r1.max.y += (Dy(w->r)-font->height)*new/old + Border + font->height;
+			if(new > 0 && old > 0 && Dy(w->r) > Border+font->height)
+				r1.max.y += (Dy(w->r)-Border-font->height)*new/old + Border + font->height;
 		}
+		r1.max.y = max(r1.max.y, r1.min.y + Border+font->height);
 		r2 = r1;
 		r2.max.y = r2.min.y+Border;
 		draw(screen, r2, display->black, nil, ZP);
 		r1.min.y = r2.max.y;
-		r1.min.y = winresize(w, r1, FALSE);
+		r1.min.y = winresize(w, r1, FALSE, i==c->nw-1);
 	}
 	c->r = r;
 }
@@ -271,7 +272,7 @@
 		r1.max.y = r1.min.y+Border;
 		draw(screen, r1, display->black, nil, ZP);
 		r.min.y = r1.max.y;
-		y = winresize(w, r, FALSE);
+		y = winresize(w, r, FALSE, i==c->nw-1);
 	}
 	free(rp);
 	free(c->w);
@@ -297,8 +298,8 @@
 		if(i==c->nw-1 || c->safe==FALSE)
 			r.max.y = cr.max.y;
 		else
-			r.max.y = c->w[i+1]->r.min.y;
-		winresize(w, r, FALSE);
+			r.max.y = c->w[i+1]->r.min.y - Border;
+		winresize(w, r, FALSE, TRUE);
 		return;
 	}
 	cr.min.y = c->w[0]->r.min.y;
@@ -309,7 +310,7 @@
 			c->w[i] = v;
 		}
 		draw(screen, cr, textcols[BACK], nil, ZP);
-		winresize(w, cr, FALSE);
+		winresize(w, cr, FALSE, TRUE);
 		for(i=1; i<c->nw; i++)
 			c->w[i]->body.maxlines = 0;
 		c->safe = FALSE;
@@ -367,9 +368,9 @@
 			r.max.y += 1 + nl[j]*v->body.font->height;
 		if(!c->safe || !eqrect(v->r, r)){
 			draw(screen, r, textcols[BACK], nil, ZP);
-			winresize(v, r, c->safe);
-		}
-		r.min.y = v->r.max.y;
+			r.min.y = winresize(v, r, c->safe, FALSE);
+		}else
+			r.min.y = v->r.max.y;
 		r.max.y += Border;
 		draw(screen, r, display->black, nil, ZP);
 		y1 = r.max.y;
@@ -389,17 +390,13 @@
 	/* compute new size of window */
 	r = w->r;
 	r.min.y = y1;
-	r.max.y = r.min.y+Dy(w->tag.all);
+	r.max.y = y2;
 	h = w->body.font->height;
-	if(y2-r.max.y >= 1+h+Border){
-		r.max.y += 1;
-		r.max.y += h*((y2-r.max.y)/h);
-	}
+	if(Dy(r) < Dy(w->tagtop)+1+h+Border)
+		r.max.y = r.min.y + Dy(w->tagtop)+1+h+Border;
 	/* draw window */
-	if(!c->safe || !eqrect(w->r, r)){
-		draw(screen, r, textcols[BACK], nil, ZP);
-		winresize(w, r, c->safe);
-	}
+	draw(screen, r, textcols[BACK], nil, ZP);
+	r.max.y = winresize(w, r, c->safe, TRUE);
 	if(i < c->nw-1){
 		r.min.y = r.max.y;
 		r.max.y += Border;
@@ -416,21 +413,15 @@
 		r.max.y = y1+Dy(v->tag.all);
 		if(nl[j])
 			r.max.y += 1 + nl[j]*v->body.font->height;
-		if(!c->safe || !eqrect(v->r, r)){
-			draw(screen, r, textcols[BACK], nil, ZP);
-			winresize(v, r, c->safe);
-		}
+		draw(screen, r, textcols[BACK], nil, ZP);
+		y1 = winresize(v, r, c->safe, j==c->nw-1);
 		if(j < c->nw-1){	/* no border on last window */
-			r.min.y = v->r.max.y;
-			r.max.y = r.min.y + Border;
+			r.min.y = y1;
+			r.max.y += Border;
 			draw(screen, r, display->black, nil, ZP);
+			y1 = r.max.y;
 		}
-		y1 = r.max.y;
 	}
-	r = w->r;
-	r.min.y = y1;
-	r.max.y = c->r.max.y;
-	draw(screen, r, textcols[BACK], nil, ZP);
 	free(nl);
 	free(ny);
 	c->safe = TRUE;
@@ -465,6 +456,8 @@
 	error("can't find window");
 
   Found:
+	if(w->tagexpand)	/* force recomputation of window tag size */
+		w->taglines = 1;
 	p = mouse->xy;
 	if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
 		colgrow(c, w, but);
@@ -505,11 +498,8 @@
 		if(v->body.r.min.y == v->body.r.max.y)
 			r.max.y++;
 	}
-	if(!eqrect(v->r, r)){
-		draw(screen, r, textcols[BACK], nil, ZP);
-		winresize(v, r, c->safe);
-	}
-	r.min.y = v->r.max.y;
+	draw(screen, r, textcols[BACK], nil, ZP);
+	r.min.y = winresize(v, r, c->safe, FALSE);
 	r.max.y = r.min.y+Border;
 	draw(screen, r, display->black, nil, ZP);
 	r.min.y = r.max.y;
@@ -519,10 +509,10 @@
 		r.max.y = c->w[i+1]->r.min.y-Border;
 	if(!eqrect(w->r, r)){
 		draw(screen, r, textcols[BACK], nil, ZP);
-		winresize(w, r, c->safe);
+		winresize(w, r, c->safe, TRUE);
 	}
 	c->safe = TRUE;
-    	winmousebut(w);
+    winmousebut(w);
 }
 
 Text*
--- a/sys/src/cmd/acme/dat.h
+++ b/sys/src/cmd/acme/dat.h
@@ -213,7 +213,7 @@
 Rune		textreadc(Text*, uint);
 void		textredraw(Text*, Rectangle, Font*, Image*, int);
 void		textreset(Text*);
-int		textresize(Text*, Rectangle);
+int		textresize(Text*, Rectangle, int);
 void		textscrdraw(Text*);
 void		textscroll(Text*, int);
 void		textselect(Text*);
@@ -245,7 +245,6 @@
 	uchar	dirty;
 	uchar	indent[NINDENT];
 	uchar	showdel;
-	uint		noredraw;
 	int		id;
 	Range	addr;
 	Range	limit;
@@ -290,7 +289,7 @@
 void	winsettag(Window*);
 void	winsettag1(Window*);
 void	wincommit(Window*, Text*);
-int	winresize(Window*, Rectangle, int);
+int	winresize(Window*, Rectangle, int, int);
 void	winclose(Window*);
 void	windelete(Window*);
 int	winclean(Window*, int);
--- a/sys/src/cmd/acme/exec.c
+++ b/sys/src/cmd/acme/exec.c
@@ -1217,7 +1217,7 @@
 	if(tab > 0){
 		if(w->body.tabstop != tab){
 			w->body.tabstop = tab;
-			winresize(w, w->r, 1);
+			winresize(w, w->r, FALSE, TRUE);
 		}
 	}else
 		warning(nil, "%.*S: Tab %d\n", w->body.file->nname, w->body.file->name, w->body.tabstop);
--- a/sys/src/cmd/acme/rows.c
+++ b/sys/src/cmd/acme/rows.c
@@ -102,7 +102,7 @@
 	row->r = r;
 	r1 = r;
 	r1.max.y = r1.min.y + font->height;
-	textresize(&row->tag, r1);
+	textresize(&row->tag, r1, TRUE);
 	r1.min.y = r1.max.y;
 	r1.max.y += Border;
 	draw(screen, r1, display->black, nil, ZP);
--- a/sys/src/cmd/acme/text.c
+++ b/sys/src/cmd/acme/text.c
@@ -68,14 +68,14 @@
 }
 
 int
-textresize(Text *t, Rectangle r)
+textresize(Text *t, Rectangle r, int fillfringe)
 {
 	int odx;
 
-	if(Dy(r) > 0)
-		r.max.y -= Dy(r)%t->font->height;
-	else
+	if(Dy(r) <= 0)
 		r.max.y = r.min.y;
+	else if(!fillfringe)
+		r.max.y -= Dy(r)%t->font->height;
 	odx = Dx(t->all);
 	t->all = r;
 	t->scrollr = r;
@@ -84,7 +84,14 @@
 	r.min.x += Scrollwid+Scrollgap;
 	frclear(t, 0);
 	textredraw(t, r, t->font, t->b, odx);
-	return r.max.y;
+	if(fillfringe && t->r.max.y < t->all.max.y){
+		/* draw background in bottom fringe of text window */
+		r.min.x -= Scrollgap;
+		r.min.y = t->r.max.y;
+		r.max.y = t->all.max.y;
+		draw(screen, r, t->cols[BACK], nil, ZP);		
+	}
+	return t->all.max.y;
 }
 
 void
@@ -276,7 +283,7 @@
 		if(u != t){
 			if(u->org > u->file->nc)	/* will be 0 because of reset(), but safety first */
 				u->org = 0;
-			textresize(u, u->all);
+			textresize(u, u->all, TRUE);
 			textbacknl(u, u->org, 0);	/* go to beginning of line */
 		}
 		textsetselect(u, q0, q0);
--- a/sys/src/cmd/acme/wind.c
+++ b/sys/src/cmd/acme/wind.c
@@ -136,9 +136,7 @@
 	if(!w->tagexpand && !w->showdel)
 		return 1;
 	w->showdel = FALSE;
-	w->noredraw = 1;
-	textresize(&w->tag, r);
-	w->noredraw = 0;
+	textresize(&w->tag, r, TRUE);
 	w->tagsafe = FALSE;
 	
 	if(!w->tagexpand) {
@@ -167,12 +165,11 @@
 }
 
 int
-winresize(Window *w, Rectangle r, int safe)
+winresize(Window *w, Rectangle r, int safe, int fillfringe)
 {
-	int oy, mouseintag, mouseinbody;
+	int oy, y, mouseintag, mouseinbody;
 	Point p;
 	Rectangle r1;
-	int y;
 	Image *b;
 	Rectangle br;
 
@@ -179,22 +176,22 @@
 	mouseintag = ptinrect(mouse->xy, w->tag.all);
 	mouseinbody = ptinrect(mouse->xy, w->body.all);
 
+	/* Tagtop is first line of tag. */
 	w->tagtop = r;
 	w->tagtop.max.y = r.min.y+font->height;
 
 	r1 = r;
-	r1.max.y = r1.min.y + font->height;
 	r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height);
 
-	if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){
+	/* If needed, recompute number of lines in tag. */
+	if(!safe || !w->tagsafe || !eqrect(w->tag.r, r1)){
 		w->taglines = wintaglines(w, r);
 		r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height);
 	}
-	if(Dy(r1) < font->height)
-		r1.max.y = r1.min.y+font->height;
+	/* If needed, resize & redraw tag. */
 	y = r1.max.y;
-	if(!safe || !eqrect(w->tag.r, r1)){
-		textresize(&w->tag, r1);
+	if(!safe || !w->tagsafe || !eqrect(w->tag.r, r1)){
+		textresize(&w->tag, r1, TRUE);
 		y = w->tag.r.max.y;
 		b = button;
 		if(w->body.file->mod && !w->isdir && !w->isscratch)
@@ -219,8 +216,10 @@
 			p.y = w->tag.all.max.y+3;
 			moveto(mousectl, p);
 		}
-
 	}
+	/* If needed, resize & redraw body. */
+	r1 = r;
+	r1.min.y = y;
 	if(!safe || !eqrect(w->body.r, r1)){
 		oy = y;
 		if(y+1+w->body.font->height <= r.max.y){	/* room for one line */
@@ -234,7 +233,7 @@
 			r1.min.y = y;
 			r1.max.y = y;
 		}
-		y = textresize(&w->body, r1);
+		y = textresize(&w->body, r1, fillfringe);
 		w->r = r;
 		w->r.max.y = y;
 		textscrdraw(&w->body);
@@ -539,7 +538,7 @@
 	br.max.y = br.min.y + Dy(b->r);
 	draw(screen, br, b, nil, b->r.min);
 	if(w->tagsafe == FALSE)
-		winresize(w, w->r, TRUE);
+		winresize(w, w->r, TRUE, TRUE);
 }
 
 void