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())
This commit is contained in:
cinap_lenrek 2017-12-03 18:54:25 +01:00
parent a08727d9da
commit 65566dda8e
2 changed files with 26 additions and 30 deletions

View file

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

View file

@ -193,6 +193,7 @@ vgascreenwin(VGAscr* scr)
freememimage(i); freememimage(i);
} }
r = scr->gscreen->clipr;
window = insetrect(r, 20); window = insetrect(r, 20);
memimagedraw(scr->gscreen, window, conscol, ZP, memopaque, ZP, S); memimagedraw(scr->gscreen, window, conscol, ZP, memopaque, ZP, S);
window = insetrect(window, 4); window = insetrect(window, 4);