shithub: riscv

Download patch

ref: 65566dda8ebbfddc3732c9c8caae972dd1fc9561
parent: a08727d9da8334c3c96de41dafc5820aac9013da
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Dec 3 13:54:25 EST 2017

devvga: properly handle physical screen size and panning

- remove arbitrary limits on screen size, just check with badrect()
- post resize when physgscreenr is changed (actualsize ctl command)
- preserve physgscreenr across softscreen flag toggle
- honor panning flag on resize
- fix nil dereference in panning ctl command when scr->gscreen == nil
- use clipr when drawing vga plan 9 console (vgascreenwin())

--- a/sys/src/9/pc/devvga.c
+++ b/sys/src/9/pc/devvga.c
@@ -212,11 +212,13 @@
 }
 
 static char Ebusy[] = "vga already configured";
+static char Enoscreen[] = "set the screen size first";
 
 static void
 vgactl(Cmdbuf *cb)
 {
 	int align, i, size, x, y, z;
+	Rectangle r;
 	char *chanstr, *p;
 	ulong chan;
 	Cmdtab *ct;
@@ -229,8 +231,7 @@
 	switch(ct->index){
 	case CMhwgc:
 		if(scr->gscreen == nil)
-			error("hwgc: no gscreen");
-
+			error(Enoscreen);
 		if(strcmp(cb->f[1], "off") == 0){
 			lock(&cursor);
 			if(scr->cur){
@@ -305,26 +306,19 @@
 
 	case CMsize:
 		x = strtoul(cb->f[1], &p, 0);
-		if(x == 0 || x > 10240)
-			error(Ebadarg);
 		if(*p)
 			p++;
-
 		y = strtoul(p, &p, 0);
-		if(y == 0 || y > 10240)
-			error(Ebadarg);
 		if(*p)
 			p++;
-
 		z = strtoul(p, &p, 0);
-
+		if(badrect(Rect(0,0,x,y)))
+			error(Ebadarg);
 		chanstr = cb->f[2];
 		if((chan = strtochan(chanstr)) == 0)
 			error("bad channel");
-
 		if(chantodepth(chan) != z)
 			error("depth, channel do not match");
-
 		cursoroff();
 		deletescreenimage();
 		if(screensize(x, y, z, chan))
@@ -334,30 +328,25 @@
 
 	case CMactualsize:
 		if(scr->gscreen == nil)
-			error("set the screen size first");
-
+			error(Enoscreen);
 		x = strtoul(cb->f[1], &p, 0);
-		if(x == 0 || x > 2048)
-			error(Ebadarg);
 		if(*p)
 			p++;
-
 		y = strtoul(p, nil, 0);
-		if(y == 0 || y > 2048)
+		r = Rect(0,0,x,y);
+		if(badrect(r))
 			error(Ebadarg);
-
-		if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
+		if(!rectinrect(r, scr->gscreen->r))
 			error("physical screen bigger than virtual");
-
-		physgscreenr = Rect(0,0,x,y);
-		scr->gscreen->clipr = physgscreenr;
-		return;
+		cursoroff();
+		deletescreenimage();
+		physgscreenr = r;
+		goto Resized;
 	
 	case CMpalettedepth:
 		x = strtoul(cb->f[1], &p, 0);
 		if(x != 8 && x != 6)
 			error(Ebadarg);
-
 		scr->palettedepth = x;
 		return;
 
@@ -370,6 +359,7 @@
 			break;
 		if(scr->gscreen == nil)
 			return;
+		r = physgscreenr;
 		x = scr->gscreen->r.max.x;
 		y = scr->gscreen->r.max.y;
 		z = scr->gscreen->depth;
@@ -378,14 +368,17 @@
 		deletescreenimage();
 		if(screensize(x, y, z, chan))
 			error(Egreg);
+		physgscreenr = r;
 		/* no break */
 	case CMdrawinit:
 		if(scr->gscreen == nil)
-			error("drawinit: no gscreen");
+			error(Enoscreen);
 		if(scr->dev && scr->dev->drawinit)
 			scr->dev->drawinit(scr);
 		hwblank = scr->blank != nil;
 		hwaccel = scr->fill != nil || scr->scroll != nil;
+	Resized:
+		scr->gscreen->clipr = panning ? scr->gscreen->r : physgscreenr;
 		vgascreenwin(scr);
 		resetscreenimage();
 		cursoron();
@@ -405,19 +398,21 @@
 
 	case CMpanning:
 		if(strcmp(cb->f[1], "on") == 0){
-			if(scr == nil || scr->cur == nil)
-				error("set screen first");
+			if(scr->cur == nil)
+				error("set cursor first");
 			if(!scr->cur->doespanning)
 				error("panning not supported");
-			scr->gscreen->clipr = scr->gscreen->r;
 			panning = 1;
 		}
 		else if(strcmp(cb->f[1], "off") == 0){
-			scr->gscreen->clipr = physgscreenr;
 			panning = 0;
 		}else
 			break;
-		return;
+		if(scr->gscreen == nil)
+			return;
+		cursoroff();
+		deletescreenimage();
+		goto Resized;
 
 	case CMhwaccel:
 		if(strcmp(cb->f[1], "on") == 0)
--- a/sys/src/9/pc/vga.c
+++ b/sys/src/9/pc/vga.c
@@ -193,6 +193,7 @@
 		freememimage(i);
 	}
 
+	r = scr->gscreen->clipr;
 	window = insetrect(r, 20);
 	memimagedraw(scr->gscreen, window, conscol, ZP, memopaque, ZP, S);
 	window = insetrect(window, 4);