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* */