code: plan9front

Download patch

ref: 4d69aacea023546a7150d92e147e531c38de822f
parent: 1efad2d8fb4fc964198e30b483492f0465627f7d
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* */