git: 9front

Download patch

ref: 03040ba3c0f62b0ea0ac86b84d63cda4f59f970b
parent: 78e2f69c0d7e4c17227e1ec0545cbb2a0ae1e96e
author: Aidan Wiggins <akw@oneiri.one>
date: Sat Oct 25 10:57:47 EDT 2025

samterm: Simplify scrolling mechanics

This keeps Torigin messages contained to mostly center().  So now
center() takes an origin and line offset, to then move either locally
on the terminal (n > 0), or via messages to & from the host (n <= 0).

With this, Kup/Kdown go by 1/3 of the screen (as in rio), and
Kpgup/Kpgdown go by # of lines on the screen, so a Kpgup undoes a Kpgdown.

This also makes scrolling look smoother by flushing the display only
when necessary.

--- a/sys/src/cmd/samterm/io.c
+++ b/sys/src/cmd/samterm/io.c
@@ -15,6 +15,7 @@
 int	block;
 int	kbdc;
 int	resized;
+int	scrselecting;
 uchar	*hostp;
 uchar	*hoststop;
 uchar	*plumbbase;
@@ -47,6 +48,13 @@
 }
 
 void
+flushdisplay(void)
+{
+	if(display->bufp > display->buf)
+		flushimage(display, 1);
+}
+
+void
 getmouse(void)
 {
 	if(readmouse(mousectl) < 0)
@@ -128,8 +136,8 @@
 
 	if(got & ~block)
 		return got & ~block;
-	if(display->bufp > display->buf)
-		flushimage(display, 1);
+	if(!scrselecting)
+		flushdisplay();
 	type = alt(alts);
 	switch(type){
 	case RHost:
@@ -182,7 +190,6 @@
 {
 	Flayer *l = which;
 	Text *t = l->user1;
-	long p;
 
 	if(nbrecv(mousectl->c, &mousectl->Mouse) < 0)
 		panic("mouse");
@@ -195,11 +202,14 @@
 			l->p0 = sel;
 			l->p1 = l->origin+f->p0;
 		}
-		scrorigin(l, 1, -n+1);
 	}else if(n == 0){
+		flushdisplay();
 		sleep(25);
 		return;
 	}else{
+		/* don't scroll off the end */
+		if(l->origin+f->nchars == t->rasp.nrunes)
+			return;
 		if(sel >= l->origin+f->p1){
 			l->p0 = l->origin+f->p1;
 			l->p1 = sel;
@@ -207,20 +217,24 @@
 			l->p0 = sel;
 			l->p1 = l->origin+f->p1;
 		}
-		p = l->origin;
-		if(l->origin+f->nchars != t->rasp.nrunes)
-			p += frcharofpt(f, Pt(l->scroll.max.x, l->scroll.min.y + n * f->font->height));
-		scrorigin(l, 2, p);
 	}
 
+	flushdisplay();
+	center(l, l->origin, n);
+	if(n > 0 && !t->lock)
+		/* no msg sent */
+		return;
+
 	/*
 	 * we must pull io from host while we are in frame(2)
 	 */
+	scrselecting = 1;
 	do{
 		block = ~(1 << RHost);
 		waitforio();
 		rcv();
 	}while(t->lock);
+	scrselecting = 0;
 }
 
 int
--- a/sys/src/cmd/samterm/main.c
+++ b/sys/src/cmd/samterm/main.c
@@ -312,26 +312,6 @@
 	}
 }
 
-void
-scrorigin(Flayer *l, int but, long p0)
-{
-	Text *t=(Text *)l->user1;
-
-	if(t->tag == Untagged)
-		return;
-
-	switch(but){
-	case 1:
-		outTsll(Torigin, t->tag, l->origin, p0);
-		break;
-	case 2:
-		outTsll(Torigin, t->tag, p0, 1L);
-		break;
-	case 3:
-		horigin(t->tag,p0);
-	}
-}
-
 int
 alnum(int c)
 {
@@ -415,40 +395,25 @@
 	return p>=o? p : o;
 }
 
-int
-center(Flayer *l, long a)
+void
+center(Flayer *l, long a, int n)
 {
 	Text *t;
 
 	t = l->user1;
-	if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
-		if(a > t->rasp.nrunes)
-			a = t->rasp.nrunes;
-		outTsll(Torigin, t->tag, a, 2L);
-		return 1;
-	}
-	return 0;
-}
+	if(t->lock || t->tag == Untagged)
+		return;
 
-int
-onethird(Flayer *l, long a)
-{
-	Text *t;
-	Rectangle s;
-	long lines;
+	if(n > 0)
+		a += frcharofpt(&l->f, Pt(l->scroll.max.x, l->scroll.min.y + n * l->f.font->height));
+	if(a > t->rasp.nrunes)
+		a = t->rasp.nrunes;
 
-	t = l->user1;
-	if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
-		if(a > t->rasp.nrunes)
-			a = t->rasp.nrunes;
-		s = insetrect(l->scroll, 1);
-		lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3;
-		if (lines < 2)
-			lines = 2;
-		outTsll(Torigin, t->tag, a, lines);
-		return 1;
-	}
-	return 0;
+	if(n > 0)
+		/* we can center locally */
+		horigin(t->tag, a);
+	else
+		outTsll(Torigin, t->tag, a, -n+1);
 }
 
 void
@@ -506,7 +471,7 @@
 	Rune buf[100];
 	Rune *p = buf;
 	int c, backspacing;
-	long a, a0;
+	long a;
 	int scrollkey;
 
 	scrollkey = 0;
@@ -571,38 +536,46 @@
 		typeend = a;
 		if(c=='\n' || typeend-typestart>100)
 			flushtyping(0);
-		onethird(l, a);
+		if(a < l->origin || a > l->origin+l->f.nchars)
+			center(l, a, -(l->f.maxlines/3));
 	}
-	if(c==Kdown || c==Kpgdown){
+	if(c==Kdown){
 		flushtyping(0);
-		center(l, l->origin+l->f.nchars+1);
+		center(l, l->origin, l->f.maxlines/3);
+	}else if(c==Kpgdown){
+		flushtyping(0);
+		center(l, l->origin, l->f.maxlines);
 		/* backspacing immediately after outcmd(): sorry */
-	}else if(c==Kup || c==Kpgup){
+	}else if(c==Kup){
 		flushtyping(0);
-		a0 = l->origin-l->f.nchars;
-		if(a0 < 0)
-			a0 = 0;
-		center(l, a0);
-	}else if(c == Kright){
+		center(l, l->origin, -(l->f.maxlines/3));
+	}else if(c==Kpgup){
 		flushtyping(0);
-		a0 = l->p1;
-		if(a0 < t->rasp.nrunes)
-			a0++;
-		flsetselect(l, a0, a0);
-		center(l, a0);
+		center(l, l->origin, -l->f.maxlines);
 	}else if(c == Kleft){
 		flushtyping(0);
-		a0 = l->p0;
-		if(a0 > 0)
-			a0--;
-		flsetselect(l, a0, a0);
-		center(l, a0);
-	}else if(c == Khome){
+		if(l->p0 > 0){
+			l->p0--;
+			flsetselect(l, l->p0, l->p0);
+			if(l->p0 < l->origin || l->p0 > l->origin+l->f.nchars)
+				center(l, l->p0, 0);
+		}
+	}else if(c == Kright){
 		flushtyping(0);
-		center(l, 0);
+		if(l->p1 < t->rasp.nrunes){
+			l->p1++;
+			if(l->p1 == l->origin+l->f.nchars && l->p1 != t->rasp.nrunes)
+				center(l, l->origin, 1);
+			else if(l->p1 < l->origin || l->p1 > l->origin+l->f.nchars)
+				center(l, l->p1, 0);
+			flsetselect(l, l->p1, l->p1);
+		}
+ 	}else if(c == Khome){
+		flushtyping(0);
+		center(l, 0, 0);
 	}else if(c == Kend){
 		flushtyping(0);
-		center(l, t->rasp.nrunes);
+		center(l, t->rasp.nrunes, -(l->f.maxlines/3));
 	}else if(c == Ksoh || c == Kenq){
 		flushtyping(1);
 		if(c == Ksoh)
@@ -664,7 +637,7 @@
 		flushtyping(0);
 		a = t->rasp.nrunes;
 		flsetselect(l, a, a);
-		center(l, a);
+		center(l, a, 0);
  	}else if(c == Kbel){
  		int i;
  		if(work == nil)
--- a/sys/src/cmd/samterm/mesg.c
+++ b/sys/src/cmd/samterm/mesg.c
@@ -207,8 +207,11 @@
 		if(m == cmd.tag){
 			for(i=0; i<NL; i++){
 				lp = &cmd.l[i];
-				if(lp->textfn)
-					center(lp, l>=0? l : lp->p1);
+				if(lp->textfn){
+					l = l >= 0? l: lp->p1;
+					if(l < lp->origin || l > lp->origin+lp->f.nchars)
+						center(lp, l, -1);
+				}
 			}
 		}
 		break;
--- a/sys/src/cmd/samterm/samterm.h
+++ b/sys/src/cmd/samterm/samterm.h
@@ -116,7 +116,7 @@
 void	cut(Text*, int, int, int);
 void	paste(Text*, int);
 void	snarf(Text*, int);
-int	center(Flayer*, long);
+void	center(Flayer*, long, int);
 int	xmenuhit(int, Menu*);
 void	buttons(int);
 int	getr(Rectangle*);
@@ -154,7 +154,6 @@
 void	rresize(Rasp *, long, long, long);
 void	rdata(Rasp*, long, long, Rune*);
 void	rclean(Rasp*);
-void	scrorigin(Flayer*, int, long);
 long	scrtotal(Flayer*);
 void	flnewlyvisible(Flayer*);
 char	*rcvstring(void);
--- a/sys/src/cmd/samterm/scroll.c
+++ b/sys/src/cmd/samterm/scroll.c
@@ -108,8 +108,8 @@
 	int in = 0, oin;
 	long tot = scrtotal(l);
 	Rectangle scr, r, s, rt;
-	int x, y, my, oy, h;
-	long p0;
+	int x, y, my, oy, n;
+	long p0, o;
 
 	if(l->visible==None)
 		return;
@@ -155,23 +155,15 @@
 		}
 	}while(but <= 3 && button(but));
 	if(in){
-		h = s.max.y-s.min.y;
 		scrunmark(l, r);
-		p0 = 0;
-		if(but == 1 || but == 4){
-			but = 1;
-			p0 = (long)(my-s.min.y)/l->f.font->height+1;
-		}else if(but == 2){
-			if(tot > 1024L*1024L)
-				p0 = ((tot>>10)*(y-s.min.y)/h)<<10;
-			else
-				p0 = tot*(y-s.min.y)/h;
-		}else if(but == 3 || but == 5){
-			but = 3;
-			p0 = l->origin+frcharofpt(&l->f, Pt(s.max.x, my));
-			if(p0 > tot)
-				p0 = tot;
+		if(but == 2){
+			n = 0;
+			o = (tot / (s.max.y - s.min.y)) * (my - s.min.y);
+		}else{
+			n = (my - s.min.y)/l->f.font->height;
+			n *= (but == 1 || but == 4)? -1: 1;
+			o = l->origin;
 		}
-		scrorigin(l, but, p0);
+		center(l, o, n);
 	}
 }
--