git: 9front

Download patch

ref: 9b96680bedd82942a93548f78cb4659270f23d46
parent: 901af7d49f2aeffd616808df3759a9afff63cffc
author: Igor Böhm <igor@9lab.org>
date: Sun Jan 7 20:27:43 EST 2024

vncv: implement autoscaling via -a flag (thanks unobe)

Add vncv option '-a' to autoscale remote frame buffer to
local screen window size; useful when remote frame buffer
is larger than the local screen.

If the remote frame buffer is larger than the local screen,
and autoscaling is disabled, only the upper left corner is
accessible.

--- a/sys/man/1/vnc
+++ b/sys/man/1/vnc
@@ -44,7 +44,7 @@
 .PP
 .B vncv
 [
-.B -cstv
+.B -acstv
 ]
 [
 .B -e
@@ -146,10 +146,14 @@
 provides access to remote display
 .IB host : n \fR.
 It resizes its window to be the smaller of the
-remote frame buffer size and the local screen.
+remote frame buffer size and the local screen
+when not using the autoscaling option.
 .PP
 The options are:
 .TP
+.B -a
+autoscale remote frame buffer to local screen window size.
+.TP
 .B -c
 when connecting to 8-bit displays, request
 .B r4g4b4
@@ -166,7 +170,10 @@
 .B corre
 .B hextile
 .B rre
-.BR raw .
+.B raw
+.B mousewarp
+.B desktopsize
+.BR xdesktopsize .
 The encodings should be given as a single space-separated argument
 (quoted when using the shell).
 .TP
@@ -199,7 +206,8 @@
 .B http://www.uk.research.att.com/vnc
 .SH BUGS
 If the remote frame buffer is larger than the local screen,
-only the upper left corner can be accessed.
+and autoscaling is disabled, only the upper left corner can be accessed.
+Autoscaling is only implemented for raw encoding.
 .PP
 .I Vncs
 and
--- a/sys/src/cmd/vnc/draw.c
+++ b/sys/src/cmd/vnc/draw.c
@@ -20,8 +20,18 @@
 static	int	vpixb;
 static	int	pixb;
 static	void	(*pixcp)(uchar*, uchar*);
+static double scalex;
+static double scaley;
 
 static void
+vncsetscale(Vnc *v)
+{
+	scalex = (v->dim.max.x - v->dim.min.x) / (double)(screen->r.max.x - screen->r.min.x);
+	scaley = (v->dim.max.y - v->dim.min.y) / (double)(screen->r.max.y - screen->r.min.y);
+	if(verbose > 1) fprint(2, "scaling %fx%f\n", scalex, scaley);
+}
+
+static void
 vncsetdim(Vnc *v, Rectangle dim)
 {
 	v->dim = rectsubpt(dim, dim.min);
@@ -79,7 +89,7 @@
 
 	lockdisplay(display);
 	flushimage(display, 1);
-	r = rectsubpt(screen->r, screen->r.min);
+	r = autoscale ? v->dim : rectsubpt(screen->r, screen->r.min);
 	unlockdisplay(display);
 	vnclock(v);
 	if(incremental == 0 && (v->canresize&2)!=0 && !eqrect(r, v->dim)){
@@ -94,7 +104,7 @@
 	} else 
 		rectclip(&r, v->dim);
 	vncwrchar(v, MFrameReq);
-	vncwrchar(v, incremental);
+	vncwrchar(v, autoscale ? 0 : incremental);
 	vncwrrect(v, r);
 	vncflush(v);
 	vncunlock(v);
@@ -167,7 +177,8 @@
 static void
 loadbuf(Vnc *v, Rectangle r, int stride)
 {
-	int off, y;
+	int off;
+	double x, y, endy;
 
 	if(cvtpixels){
 		y = r.min.y;
@@ -185,6 +196,12 @@
 			off += stride;
 		}
 	}
+	if(autoscale){
+		endy = off/(double)stride;
+		for(y = 0; y < endy; y += scaley)
+			for(x = 0; x < stride; x+=scalex)
+				memmove(&pixbuf[(int)(y/scaley)*stride+(int)(x/scalex)/pixb*pixb], &pixbuf[(int)(y)*stride+(int)(x/pixb)*pixb], pixb);
+	}
 }
 
 static Rectangle
@@ -286,12 +303,15 @@
 
 	if(!rectinrect(r, v->dim))
 		sysfatal("bad rectangle from server: %R not in %R", r, v->dim);
-	maxr = rectsubpt(r, r.min);
+	maxr = autoscale ? rectsubpt(v->dim, v->dim.min) : rectsubpt( r, r.min );
+	maxr.max.x = Dx(maxr); maxr.min.x = 0;
+	maxr.max.y = Dy(maxr); maxr.min.y = 0;
 	stride = maxr.max.x * pixb;
+	if(verbose > 2) fprint(2, "maxr.max.x %d; maxr.max.y %d; maxr.min.x %d; maxr.min.y %d, pixb: %d, stride: %ld, type: %lx\n", maxr.max.x, maxr.max.y, maxr.min.x, maxr.min.y, pixb, stride, type);
 
 	switch(type){
 	default:
-		sysfatal("bad rectangle encoding from server");
+		sysfatal("bad rectangle encoding from server: %lx", type);
 		break;
 	case EncRaw:
 		loadbuf(v, maxr, stride);
@@ -399,6 +419,8 @@
 			sysfatal("bad message from server: %x", type);
 			break;
 		case MFrameUpdate:
+			if(autoscale)
+				vncsetscale(v);
 			vncrdchar(v);
 			n = vncrdshort(v);
 			while(n-- > 0)
--- a/sys/src/cmd/vnc/vncv.c
+++ b/sys/src/cmd/vnc/vncv.c
@@ -4,6 +4,7 @@
 
 char*		charset = "utf-8";
 char*		encodings = "copyrect hextile corre rre raw mousewarp desktopsize xdesktopsize";
+int		autoscale;
 int		bpp12;
 int		shared;
 int		verbose;
@@ -74,7 +75,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: vncv [-e encodings] [-k keypattern] [-l charset] [-csv] host[:n]\n");
+	fprint(2, "usage: vncv [-acstv] [-e encodings] [-l charset] [-k keypattern] host[:n]\n");
 	exits("usage");
 }
 
@@ -87,6 +88,9 @@
 	keypattern = nil;
 	shared = 0;
 	ARGBEGIN{
+	case 'a':
+		autoscale = 1;
+		break;
 	case 'c':
 		bpp12 = 1;
 		break;
--- a/sys/src/cmd/vnc/vncv.h
+++ b/sys/src/cmd/vnc/vncv.h
@@ -13,6 +13,7 @@
 /* vncv.c */
 extern	char		*charset;
 extern	char		*encodings;
+extern	int		autoscale;
 extern	int		bpp12;
 extern	Vnc*		vnc;
 extern	int		mousefd;
--- a/sys/src/cmd/vnc/wsys.c
+++ b/sys/src/cmd/vnc/wsys.c
@@ -48,7 +48,7 @@
 	if(getwindow(display, Refnone) < 0)
 		sysfatal("internal error: can't get the window image");
 	if((vnc->canresize&2) == 0)
-		adjustwin(vnc, first);
+		adjustwin(vnc, !autoscale && first);
 	unlockdisplay(display);
 	requestupdate(vnc, 0);
 }
@@ -154,8 +154,12 @@
 			if(*start == 'm'){
 				m.xy.x = atoi(start+1);
 				m.xy.y = atoi(start+1+12);
-				m.buttons = atoi(start+1+2*12) & 0x1F;
 				m.xy = subpt(m.xy, screen->r.min);
+				if(autoscale){
+					m.xy.x *= (v->dim.max.x - v->dim.min.x) / (double)(screen->r.max.x - screen->r.min.x);
+					m.xy.y *= (v->dim.max.y - v->dim.min.y) / (double)(screen->r.max.y - screen->r.min.y);
+				}
+				m.buttons = atoi(start+1+2*12) & 0x1F;
 				if(ptinrect(m.xy, v->dim)){
 					mouseevent(v, m);
 					/* send wheel button *release* */ 
--