vncs: support for desktop resize extension, update devdraw

This commit is contained in:
cinap_lenrek 2018-08-20 19:23:42 +02:00
parent 670137bf0a
commit d2089f949e
8 changed files with 409 additions and 291 deletions

View file

@ -13,7 +13,6 @@ enum{
Qcons,
Qconsctl,
Qsnarf,
Qwinname,
};
static Dirtab consdir[]={
@ -21,7 +20,6 @@ static Dirtab consdir[]={
"cons", {Qcons}, 0, 0660,
"consctl", {Qconsctl}, 0, 0220,
"snarf", {Qsnarf}, 0, 0600,
"winname", {Qwinname}, 0, 0000,
};
static Chan*

View file

@ -14,6 +14,7 @@ enum
{
Qtopdir = 0,
Qnew,
Qwinname,
Q3rd,
Q2nd,
Qcolormap,
@ -35,6 +36,7 @@ enum
#define NHASH (1<<5)
#define HASHMASK (NHASH-1)
#define IOUNIT (64*1024)
typedef struct Client Client;
typedef struct Draw Draw;
@ -46,21 +48,15 @@ typedef struct Refresh Refresh;
typedef struct Refx Refx;
typedef struct DName DName;
ulong blanktime = 30; /* in minutes; a half hour */
struct Draw
{
QLock;
int clientid;
int nclient;
Client** client;
int nname;
DName* name;
DName* name;
int vers;
int softscreen;
int blanked; /* screen turned off */
ulong blanktime; /* time of last operation */
ulong savemap[3*256];
};
struct Client
@ -70,6 +66,7 @@ struct Client
CScreen* cscreen;
Refresh* refresh;
Rendez refrend;
QLock refq;
uchar* readdata;
int nreaddata;
int busy;
@ -95,10 +92,10 @@ struct Refx
struct DName
{
char *name;
Client *client;
char *name;
Client *client;
DImage* dimage;
int vers;
int vers;
};
struct FChar
@ -128,7 +125,7 @@ struct DImage
int nfchar;
FChar* fchar;
DScreen* dscreen; /* 0 if not a window */
DImage* fromname; /* image this one is derived from, by name */
DImage* fromname; /* image this one is derived from, by name */
DImage* next;
};
@ -143,16 +140,21 @@ struct DScreen
int id;
int public;
int ref;
DImage *dimage;
DImage *dfill;
DImage *dimage;
DImage *dfill;
Memscreen* screen;
Client* owner;
DScreen* next;
};
static Draw sdraw;
QLock drawlock;
static Memimage *screenimage;
static Memdata screendata;
static DImage* screendimage;
static char screenname[40];
static int screennameid;
static Rectangle flushrect;
static int waste;
static DScreen* dscreen;
@ -161,6 +163,7 @@ extern void flushmemscreen(Rectangle);
void drawuninstall(Client*, int);
void drawfreedimage(DImage*);
Client* drawclientofpath(ulong);
DImage* allocdimage(Memimage*);
static char Enodrawimage[] = "unknown id for draw image";
static char Enodrawscreen[] = "unknown id for draw screen";
@ -174,29 +177,28 @@ static char Ewriteoutside[] = "writeimage outside image";
static char Enotfont[] = "image not a font";
static char Eindex[] = "character index out of range";
static char Enoclient[] = "no such draw client";
static char Edepth[] = "image has bad depth";
static char Enameused[] = "image name in use";
static char Enoname[] = "no image with that name";
static char Eoldname[] = "named image no longer valid";
static char Enamed[] = "image already has name";
static char Ewrongname[] = "wrong name for image";
void
drawlock(void)
static void
dlock(void)
{
qlock(&sdraw);
qlock(&drawlock);
}
void
drawunlock(void)
static int
candlock(void)
{
qunlock(&sdraw);
return canqlock(&drawlock);
}
int
candrawlock(void)
static void
dunlock(void)
{
return canqlock(&sdraw);
qunlock(&drawlock);
}
static int
@ -226,7 +228,7 @@ drawgen(Chan *c, Dirtab*, int, int s, Dir *dp)
devdir(c, q, up->genbuf, 0, eve, 0500, dp);
break;
default:
panic("drawwalk %#llux", c->qid.path);
panic("drawwalk %llux", c->qid.path);
}
return 1;
}
@ -235,15 +237,17 @@ drawgen(Chan *c, Dirtab*, int, int s, Dir *dp)
* Top level directory contains the name of the device.
*/
t = QID(c->qid);
if(t == Qtopdir){
switch(s){
case 0:
if(t == Qtopdir || t == Qwinname){
if(s == 1 || t == Qwinname){
mkqid(&q, Qwinname, 0, QTFILE);
devdir(c, q, "winname", 0, eve, 0444, dp);
}
else if(s == 0){
mkqid(&q, Q2nd, 0, QTDIR);
devdir(c, q, "draw", 0, eve, 0555, dp);
break;
default:
return -1;
}
else
return -1;
return 1;
}
@ -272,7 +276,7 @@ drawgen(Chan *c, Dirtab*, int, int s, Dir *dp)
/*
* Third level.
*/
path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */
path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */
q.vers = c->qid.vers;
q.type = QTFILE;
switch(s){
@ -320,14 +324,13 @@ drawrefreshscreen(DImage *l, Client *client)
static
void
drawrefresh(Memimage *l, Rectangle r, void *v)
drawrefresh(Memimage*, Rectangle r, void *v)
{
Refx *x;
DImage *d;
Client *c;
Refresh *ref;
USED(l);
if(v == 0)
return;
x = v;
@ -353,9 +356,8 @@ addflush(Rectangle r)
int abb, ar, anbb;
Rectangle nbb;
if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
if(sdraw.softscreen==0 || screenimage == nil || !rectclip(&r, screenimage->r))
return;
if(flushrect.min.x >= flushrect.max.x){
flushrect = r;
waste = 0;
@ -393,7 +395,8 @@ addflush(Rectangle r)
return;
}
/* emit current state */
flushmemscreen(flushrect);
if(flushrect.min.x < flushrect.max.x)
flushmemscreen(flushrect);
flushrect = r;
waste = 0;
}
@ -409,8 +412,7 @@ dstflush(int dstid, Memimage *dst, Rectangle r)
addflush(r); // for VNC, see comments in addflush
return;
}
l = dst->layer;
if(l == nil)
if(screenimage == nil || dst == nil || (l = dst->layer) == nil)
return;
do{
if(l->screen->image->data != screenimage->data)
@ -421,11 +423,11 @@ dstflush(int dstid, Memimage *dst, Rectangle r)
addflush(r);
}
static
void
drawflush(void)
{
flushmemscreen(flushrect);
if(screenimage && flushrect.min.x < flushrect.max.x)
flushmemscreen(flushrect);
flushrect = Rect(10000, 10000, -10000, -10000);
}
@ -517,22 +519,34 @@ drawlookupscreen(Client *client, int id, CScreen **cs)
return 0;
}
Memimage*
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
DImage*
allocdimage(Memimage *i)
{
DImage *d;
d = malloc(sizeof(DImage));
if(d == 0)
return 0;
d->id = id;
d->ref = 1;
d->name = 0;
d->vers = 0;
d->image = i;
d->dscreen = 0;
d->nfchar = 0;
d->fchar = 0;
d->fromname = 0;
return d;
}
Memimage*
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
{
DImage *d;
d = allocdimage(i);
if(d == 0)
return 0;
d->id = id;
d->dscreen = dscreen;
d->next = client->dimage[id&HASHMASK];
client->dimage[id&HASHMASK] = d;
@ -595,6 +609,7 @@ drawdelname(DName *name)
{
int i;
free(name->name);
i = name-sdraw.name;
memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
sdraw.nname--;
@ -656,12 +671,10 @@ drawfreedimage(DImage *dimage)
drawfreedimage(dimage->fromname);
goto Return;
}
if(dimage->image == screenimage) /* don't free the display */
goto Return;
ds = dimage->dscreen;
if(ds){
l = dimage->image;
if(l->data == screenimage->data)
if(screenimage && l->data == screenimage->data)
addflush(l->layer->screenr);
if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
free(l->layer->refreshptr);
@ -856,11 +869,12 @@ drawpoint(Point *p, uchar *a)
}
Point
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
drawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
{
FChar *fc;
Rectangle r;
Point sp1;
static Memimage *tmp;
fc = &font->fchar[index];
r.min.x = p.x+fc->left;
@ -869,69 +883,143 @@ drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int ind
r.max.y = r.min.y+(fc->maxy-fc->miny);
sp1.x = sp->x+fc->left;
sp1.y = sp->y+fc->miny;
memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
/*
* If we're drawing greyscale fonts onto a VGA screen,
* it's very costly to read the screen memory to do the
* alpha blending inside memdraw. If this is really a stringbg,
* then rdst is the bg image (in main memory) which we can
* refer to for the underlying dst pixels instead of reading dst
* directly.
*/
if(ishwimage(dst) && !ishwimage(rdst) && font->image->depth > 1){
if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){
if(tmp)
freememimage(tmp);
tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);
if(tmp == nil)
goto fallback;
}
memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);
memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);
memdraw(dst, r, tmp, ZP, memopaque, ZP, S);
}else{
fallback:
memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
}
p.x += fc->width;
sp->x += fc->width;
return p;
}
static int
initscreenimage(void)
static DImage*
makescreenimage(void)
{
int width, depth;
ulong chan;
DImage *di;
Memdata *md;
Memimage *i;
Rectangle r;
uchar *data;
if((data = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen)) == nil)
return nil;
if(sdraw.softscreen == 0xa110c){
/* hack: softscreen is memimage. */
md = *((Memdata**)(data - sizeof(ulong) - sizeof(Memdata*)));
assert(md->bdata == data);
assert(md->ref > 1);
assert(md->allocd);
if((i = allocmemimaged(r, chan, md)) == nil){
md->ref--;
return nil;
}
}else{
if((md = malloc(sizeof *md)) == nil)
return nil;
md->allocd = 1;
md->base = nil;
md->bdata = data;
md->ref = 1;
if((i = allocmemimaged(r, chan, md)) == nil){
free(md);
return nil;
}
}
i->width = width;
i->clipr = r;
di = allocdimage(i);
if(di == nil){
freememimage(i); /* frees md */
return nil;
}
if(!waserror()){
snprint(screenname, sizeof screenname, "noborder.screen.%d", ++screennameid);
drawaddname(nil, di, strlen(screenname), screenname);
poperror();
}
return di;
}
static int
initscreenimage(void)
{
if(screenimage != nil)
return 1;
screendata.base = nil;
screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen);
if(screendata.bdata == nil)
{fprint(2, "bad bdata\n");
screendimage = makescreenimage();
if(screendimage == nil)
return 0;
}
screendata.ref = 1;
screenimage = allocmemimaged(r, chan, &screendata);
if(screenimage == nil){
fprint(2, "bad memimaged: %r\n");
/* RSC: BUG: detach screen */
return 0;
}
screenimage->width = width;
screenimage->clipr = screenimage->r;
screenimage = screendimage->image;
// iprint("initscreenimage %p %p\n", screendimage, screenimage);
mouseresize();
return 1;
}
void
deletescreenimage(void)
{
qlock(&sdraw);
/* RSC: BUG: detach screen */
if(screenimage)
freememimage(screenimage);
screenimage = nil;
qunlock(&sdraw);
dlock();
if(screenimage){
/* will be freed via screendimage; disable */
screenimage->clipr = ZR;
screenimage = nil;
}
if(screendimage){
drawfreedimage(screendimage);
screendimage = nil;
}
dunlock();
}
Chan*
void
resetscreenimage(void)
{
dlock();
initscreenimage();
dunlock();
}
static Chan*
drawattach(char *spec)
{
qlock(&sdraw);
dlock();
if(!initscreenimage()){
qunlock(&sdraw);
dunlock();
error("no frame buffer");
}
qunlock(&sdraw);
dunlock();
return devattach('i', spec);
}
Walkqid*
static Walkqid*
drawwalk(Chan *c, Chan *nc, char **name, int nname)
{
if(screendata.bdata == nil)
if(screenimage == nil)
error("no frame buffer");
return devwalk(c, nc, name, nname, 0, 0, drawgen);
}
@ -946,13 +1034,17 @@ static Chan*
drawopen(Chan *c, int omode)
{
Client *cl;
DName *dn;
DImage *di;
if(c->qid.type & QTDIR)
return devopen(c, omode, 0, 0, drawgen);
if(c->qid.type & QTDIR){
c = devopen(c, omode, 0, 0, drawgen);
c->iounit = IOUNIT;
}
qlock(&sdraw);
dlock();
if(waserror()){
qunlock(&sdraw);
dunlock();
nexterror();
}
@ -964,6 +1056,9 @@ drawopen(Chan *c, int omode)
}
switch(QID(c->qid)){
case Qwinname:
break;
case Qnew:
break;
@ -973,9 +1068,22 @@ drawopen(Chan *c, int omode)
error(Einuse);
cl->busy = 1;
flushrect = Rect(10000, 10000, -10000, -10000);
drawinstall(cl, 0, screenimage, 0);
dn = drawlookupname(strlen(screenname), screenname);
if(dn == 0)
error("draw: cannot happen 2");
if(drawinstall(cl, 0, dn->dimage->image, 0) == 0)
error(Edrawmem);
di = drawlookup(cl, 0, 0);
if(di == 0)
error("draw: cannot happen 1");
di->vers = dn->vers;
di->name = smalloc(strlen(screenname)+1);
strcpy(di->name, screenname);
di->fromname = dn->dimage;
di->fromname->ref++;
incref(&cl->r);
break;
case Qcolormap:
case Qdata:
case Qrefresh:
@ -983,11 +1091,12 @@ drawopen(Chan *c, int omode)
incref(&cl->r);
break;
}
qunlock(&sdraw);
dunlock();
poperror();
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
c->iounit = IOUNIT;
return c;
}
@ -999,11 +1108,11 @@ drawclose(Chan *c)
Client *cl;
Refresh *r;
if(c->qid.type & QTDIR)
if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */
return;
qlock(&sdraw);
dlock();
if(waserror()){
qunlock(&sdraw);
dunlock();
nexterror();
}
@ -1036,7 +1145,7 @@ drawclose(Chan *c)
drawflush(); /* to erase visible, now dead windows */
free(cl);
}
qunlock(&sdraw);
dunlock();
poperror();
}
@ -1053,13 +1162,15 @@ drawread(Chan *c, void *a, long n, vlong off)
ulong offset = off;
char buf[16];
USED(offset);
if(c->qid.type & QTDIR)
return devdirread(c, a, n, 0, 0, drawgen);
if(QID(c->qid) == Qwinname)
return readstr(off, a, n, screenname);
cl = drawclient(c);
qlock(&sdraw);
dlock();
if(waserror()){
qunlock(&sdraw);
dunlock();
nexterror();
}
switch(QID(c->qid)){
@ -1078,15 +1189,15 @@ drawread(Chan *c, void *a, long n, vlong off)
error(Enodrawimage);
i = di->image;
}
n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d",
cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
((char*)a)[n++] = ' ';
cl->infoid = -1;
break;
case Qcolormap:
drawactive(1); /* to restore map from backup */
p = malloc(4*12*256+1);
if(p == 0)
error(Enomem);
@ -1116,14 +1227,21 @@ drawread(Chan *c, void *a, long n, vlong off)
for(;;){
if(cl->refreshme || cl->refresh)
break;
qunlock(&sdraw);
dunlock();
if(waserror()){
qlock(&sdraw); /* restore lock for waserror() above */
dlock();
nexterror();
}
qlock(&cl->refq);
if(waserror()){
qunlock(&cl->refq);
nexterror();
}
rendsleep(&cl->refrend, drawrefactive, cl);
poperror();
qlock(&sdraw);
qunlock(&cl->refq);
poperror();
dlock();
}
p = a;
while(cl->refresh && n>=5*4){
@ -1140,8 +1258,9 @@ drawread(Chan *c, void *a, long n, vlong off)
}
cl->refreshme = 0;
n = p-(uchar*)a;
break;
}
qunlock(&sdraw);
dunlock();
poperror();
return n;
}
@ -1160,21 +1279,19 @@ drawwakeall(void)
}
static long
drawwrite(Chan *c, void *a, long n, vlong off)
drawwrite(Chan *c, void *a, long n, vlong)
{
char buf[128], *fields[4], *q;
Client *cl;
int i, m, red, green, blue, x;
ulong offset = off;
USED(offset);
if(c->qid.type & QTDIR)
error(Eisdir);
cl = drawclient(c);
qlock(&sdraw);
dlock();
if(waserror()){
drawwakeall();
qunlock(&sdraw);
dunlock();
nexterror();
}
switch(QID(c->qid)){
@ -1185,7 +1302,6 @@ drawwrite(Chan *c, void *a, long n, vlong off)
break;
case Qcolormap:
drawactive(1); /* to restore map from backup */
m = n;
n = 0;
while(m > 0){
@ -1200,7 +1316,7 @@ drawwrite(Chan *c, void *a, long n, vlong off)
a = (char*)a + i;
m -= i;
*q = 0;
if(getfields(buf, fields, nelem(fields), 1, " ") != 4)
if(tokenize(buf, fields, nelem(fields)) != 4)
error(Ebadarg);
i = strtoul(fields[0], 0, 0);
red = strtoul(fields[1], 0, 0);
@ -1228,7 +1344,7 @@ drawwrite(Chan *c, void *a, long n, vlong off)
default:
error(Ebadusefd);
}
qunlock(&sdraw);
dunlock();
poperror();
return n;
}
@ -1265,7 +1381,7 @@ printmesg(char *fmt, uchar *a, int plsprnt)
char *p, *q;
int s;
if(1||plsprnt==0){
if(1|| plsprnt==0){
SET(s,q,p);
USED(fmt, a, buf, p, q, s);
return;
@ -1305,7 +1421,7 @@ printmesg(char *fmt, uchar *a, int plsprnt)
}
*q++ = '\n';
*q = 0;
fprint(2, "%.*s", (int)(q-buf), buf);
// iprint("%.*s", (int)(q-buf), buf);
}
void
@ -1317,7 +1433,7 @@ drawmesg(Client *client, void *av, int n)
ulong value, chan;
Rectangle r, clipr;
Point p, q, *pp, sp;
Memimage *i, *dst, *src, *mask;
Memimage *i, *bg, *dst, *src, *mask;
Memimage *l, **lp;
Memscreen *scrn;
DImage *font, *ll, *di, *ddst, *dsrc;
@ -1333,6 +1449,7 @@ drawmesg(Client *client, void *av, int n)
fmt = nil;
if(waserror()){
if(fmt) printmesg(fmt, a, 1);
/* iprint("error: %s\n", up->errstr); */
nexterror();
}
while((n-=m) > 0){
@ -1445,7 +1562,7 @@ drawmesg(Client *client, void *av, int n)
if(ddst == nil)
error(Enodrawimage);
if(ddst->name)
error("can't change repl/clipr of shared image");
error("cannot change repl/clipr of shared image");
dst = ddst->image;
if(a[5])
dst->flags |= Frepl;
@ -1543,14 +1660,16 @@ drawmesg(Client *client, void *av, int n)
error(Eshortdraw);
dstid = BGLONG(a+1);
if(dstid == 0)
error("can't use display as font");
error("cannot use display as font");
font = drawlookup(client, dstid, 1);
if(font == 0)
error(Enodrawimage);
if(font->image->layer)
error("can't use window as font");
free(font->fchar); /* should we complain if non-zero? */
error("cannot use window as font");
ni = BGLONG(a+5);
if(ni<=0 || ni>4096)
error("bad font size (4096 chars max)");
free(font->fchar); /* should we complain if non-zero? */
font->fchar = malloc(ni*sizeof(FChar));
if(font->fchar == 0)
error("no memory for font");
@ -1647,7 +1766,7 @@ drawmesg(Client *client, void *av, int n)
error(Edrawmem);
di = drawlookup(client, dstid, 0);
if(di == 0)
error("draw: can't happen");
error("draw: cannot happen");
di->vers = dn->vers;
di->name = smalloc(j+1);
di->fromname = dn->dimage;
@ -1748,7 +1867,7 @@ drawmesg(Client *client, void *av, int n)
if(pp == nil)
error(Enomem);
doflush = 0;
if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
if(dstid==0 || (screenimage && dst->layer && dst->layer->screen->image->data == screenimage->data))
doflush = 1; /* simplify test in loop */
ox = oy = 0;
esize = 0;
@ -1803,8 +1922,6 @@ drawmesg(Client *client, void *av, int n)
if(n < m)
error(Eshortdraw);
i = drawimage(client, a+1);
if(0 && i->layer)
error("readimage from window unimplemented");
drawrectangle(&r, a+5);
if(!rectinrect(r, i->r))
error(Ereadoutside);
@ -1814,7 +1931,7 @@ drawmesg(Client *client, void *av, int n)
client->readdata = mallocz(c, 0);
if(client->readdata == nil)
error("readimage malloc failed");
client->nreaddata = unloadmemimage(i, r, client->readdata, c);
client->nreaddata = memunload(i, r, client->readdata, c);
if(client->nreaddata < 0){
free(client->readdata);
client->readdata = nil;
@ -1852,9 +1969,10 @@ drawmesg(Client *client, void *av, int n)
clipr = dst->clipr;
dst->clipr = r;
op = drawclientop(client);
bg = dst;
if(*a == 'x'){
/* paint background */
l = drawimage(client, a+47);
bg = drawimage(client, a+47);
drawpoint(&q, a+51);
r.min.x = p.x;
r.min.y = p.y-font->ascent;
@ -1870,7 +1988,7 @@ drawmesg(Client *client, void *av, int n)
r.max.x += font->fchar[ci].width;
u += 2;
}
memdraw(dst, r, l, q, memopaque, ZP, op);
memdraw(dst, r, bg, q, memopaque, ZP, op);
u -= 2*ni;
}
q = p;
@ -1880,7 +1998,7 @@ drawmesg(Client *client, void *av, int n)
dst->clipr = clipr;
error(Eindex);
}
q = drawchar(dst, q, src, &sp, font, ci, op);
q = drawchar(dst, bg, q, src, &sp, font, ci, op);
u += 2;
}
dst->clipr = clipr;
@ -1938,7 +2056,7 @@ drawmesg(Client *client, void *av, int n)
memltofrontn(lp, nw);
else
memltorearn(lp, nw);
if(lp[0]->layer->screen->image->data == screenimage->data)
if(screenimage && lp[0]->layer->screen->image->data == screenimage->data)
for(j=0; j<nw; j++)
addflush(lp[j]->layer->screenr);
ll = drawlookup(client, BGLONG(a+1+1+2), 1);
@ -2009,7 +2127,6 @@ drawcmap(void)
int num, den;
int i, j;
drawactive(1); /* to restore map from backup */
for(r=0,i=0; r!=4; r++)
for(v=0; v!=4; v++,i+=16){
for(g=0,j=v-r; g!=4; g++)
@ -2032,53 +2149,3 @@ drawcmap(void)
}
}
}
void
drawblankscreen(int blank)
{
int i, nc;
ulong *p;
if(blank == sdraw.blanked)
return;
if(!canqlock(&sdraw))
return;
if(!initscreenimage()){
qunlock(&sdraw);
return;
}
p = sdraw.savemap;
nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
/*
* blankscreen uses the hardware to blank the screen
* when possible. to help in cases when it is not possible,
* we set the color map to be all black.
*/
if(blank == 0){ /* turn screen on */
for(i=0; i<nc; i++, p+=3)
setcolor(i, p[0], p[1], p[2]);
blankscreen(0);
}else{ /* turn screen off */
blankscreen(1);
for(i=0; i<nc; i++, p+=3){
getcolor(i, &p[0], &p[1], &p[2]);
setcolor(i, 0, 0, 0);
}
}
sdraw.blanked = blank;
qunlock(&sdraw);
}
/*
* record activity on screen, changing blanking as appropriate
*/
void
drawactive(int active)
{
if(active){
drawblankscreen(0);
sdraw.blanktime = 0;
}else
sdraw.blanktime++;
}

View file

@ -27,6 +27,7 @@ struct Mouseinfo
ulong lastcounter; /* value when /dev/mouse read */
Rendez r;
Ref;
int resize;
int open;
Mousestate queue[16]; /* circular buffer of click events */
ulong ri; /* read index into queue */
@ -195,6 +196,10 @@ mouseread(Chan *c, void *va, long n, vlong off)
m.xy.x, m.xy.y, m.buttons, m.msec);
mouse.lastcounter = m.counter;
if(mouse.resize){
mouse.resize = 0;
buf[0] = 'r';
}
if(n > 1+4*12)
n = 1+4*12;
@ -321,7 +326,7 @@ absmousetrack(int x, int y, int b, ulong msec)
int
mousechanged(void*)
{
return mouse.lastcounter != mouse.counter;
return mouse.lastcounter != mouse.counter || mouse.resize != 0;
}
Point
@ -329,3 +334,13 @@ mousexy(void)
{
return mouse.xy;
}
/*
* notify reader that screen has been resized
*/
void
mouseresize(void)
{
mouse.resize = 1;
rendwakeup(&mouse.r);
}

View file

@ -260,9 +260,12 @@ dorectangle(Vnc *v)
case EncMouseWarp:
mousewarp(r.min);
return;
case EncDesktopSize:
v->canresize |= 1;
vncsetdim(v, r);
return;
case EncXDesktopSize:
v->canresize = 1;
v->canresize |= 2;
n = vncrdlong(v)>>24;
if(n <= 0)
break;
@ -274,9 +277,7 @@ dorectangle(Vnc *v)
vncrdrect(v);
vncrdlong(v);
}
/* wet floor */
case EncDesktopSize:
vncsetdim(v, r);
vncsetdim(v, v->screen[0].rect);
return;
}

View file

@ -42,10 +42,7 @@ static Cursor screencursor;
void
screeninit(int x, int y, char *chanstr)
{
Point p, q;
char *greet;
char buf[128];
Memimage *grey;
Rectangle r;
int chan;
@ -78,31 +75,33 @@ screeninit(int x, int y, char *chanstr)
error(buf);
}
drawlock();
/*
* set up goo for screenputs
*/
memdefont = getmemdefont();
back = memwhite;
conscol = memblack;
/* a lot of work to get a grey color */
curscol = allocmemimage(Rect(0,0,1,1), RGBA32);
curscol->flags |= Frepl;
curscol->clipr = gscreen->r;
memfillcolor(curscol, 0xff0000ff);
memfillcolor(gscreen, 0x444488FF);
screenwin();
w = memdefont->info[' '].width;
setcursor(&arrow);
}
void
screenwin(void)
{
Point p;
char *greet;
Memimage *grey;
qlock(&drawlock);
back = memwhite;
conscol = memblack;
memfillcolor(gscreen, 0x888844FF);
memdefont = getmemdefont();
h = memdefont->height;
window.min = addpt(gscreen->r.min, Pt(20,20));
window.max.x = window.min.x + Dx(gscreen->r)*3/4-40;
window.max.y = window.min.y + Dy(gscreen->r)*3/4-100;
window = insetrect(gscreen->clipr, 20);
memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
window = insetrect(window, 4);
memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
@ -119,22 +118,18 @@ screeninit(int x, int y, char *chanstr)
greet = " Plan 9 Console ";
p = addpt(window.min, Pt(10, 0));
q = memsubfontwidth(memdefont, greet);
memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
window.min.y += h+6;
curpos = window.min;
window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
flushmemscreen(gscreen->r);
drawunlock();
setcursor(&arrow);
qunlock(&drawlock);
}
uchar*
attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
{
*r = gscreen->r;
*r = gscreen->clipr;
*d = gscreen->depth;
*chan = gscreen->chan;
*width = gscreen->width;
@ -263,7 +258,7 @@ scroll(void)
memimagedraw(gscreen, r, gscreen, p, nil, p, S);
r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
flushmemscreen(gscreen->r);
flushmemscreen(gscreen->clipr);
curpos.y -= o;
}
@ -336,7 +331,7 @@ screenputs(char *s, int n)
static int nrb;
char *e;
drawlock();
qlock(&drawlock);
e = s + n;
while(s < e){
rb[nrb++] = *s++;
@ -347,5 +342,5 @@ screenputs(char *s, int n)
}
}
screenflush();
drawunlock();
qunlock(&drawlock);
}

View file

@ -11,6 +11,7 @@ extern Memimage *gscreen;
extern int cursorver;
extern Point cursorpos;
void mouseresize(void);
Point mousexy(void);
void cursoron(void);
void cursoroff(void);
@ -19,16 +20,18 @@ void flushmemscreen(Rectangle r);
Rectangle cursorrect(void);
void cursordraw(Memimage *dst, Rectangle r);
extern QLock drawlock;
void drawactive(int);
void drawlock(void);
void drawunlock(void);
int candrawlock(void);
void getcolor(ulong, ulong*, ulong*, ulong*);
int setcolor(ulong, ulong, ulong, ulong);
#define TK2SEC(x) 0
extern void blankscreen(int);
void screeninit(int x, int y, char *chanstr);
void screenwin(void);
void absmousetrack(int x, int y, int b, ulong msec);
uchar *attachscreen(Rectangle*, ulong*, int*, int*, int*);
void deletescreenimage(void);
void resetscreenimage(void);
void fsinit(char *mntpt, int x, int y, char *chanstr);
#define ishwimage(i) 0

View file

@ -571,7 +571,7 @@ vncaccept(Vncs *v)
if(!shared)
killclients(v);
v->dim = rectsubpt(gscreen->r, gscreen->r.min);
v->dim = rectsubpt(gscreen->clipr, gscreen->clipr.min);
vncwrpoint(v, v->dim.max);
if(verbose)
fprint(2, "%V: send screen size %R\n", v, v->dim);
@ -592,6 +592,8 @@ vncaccept(Vncs *v)
if(verbose)
fprint(2, "%V: handshaking done\n", v);
v->updatereq = 0;
switch(rfork(RFPROC|RFMEM)){
case -1:
fprint(2, "%V: cannot fork: %r; hanging up\n", v);
@ -674,7 +676,10 @@ setencoding(Vncs *v)
v->canwarp = 1;
continue;
case EncDesktopSize:
v->canresize |= 1;
continue;
case EncXDesktopSize:
v->canresize |= 2;
continue;
}
if(v->countrect != nil)
@ -710,9 +715,10 @@ setencoding(Vncs *v)
}
if(verbose)
fprint(2, "Encoding with %s%s%s\n", v->encname,
fprint(2, "Encoding with %s%s%s%s\n", v->encname,
v->copyrect ? ", copyrect" : "",
v->canwarp ? ", canwarp" : "");
v->canwarp ? ", canwarp" : "",
v->canresize ? ", resize" : "");
}
/*
@ -755,18 +761,40 @@ clientreadproc(Vncs *v)
case MFrameReq:
incremental = vncrdchar(v);
r = vncrdrect(v);
if(incremental){
vnclock(v);
v->updaterequest = 1;
vncunlock(v);
}else{
drawlock(); /* protects rlist */
vnclock(v); /* protects updaterequest */
v->updaterequest = 1;
if(!incremental){
qlock(&drawlock); /* protects rlist */
addtorlist(&v->rlist, r);
vncunlock(v);
drawunlock();
qunlock(&drawlock);
}
v->updatereq++;
break;
case MSetDesktopSize:
vncrdchar(v);
vncrdpoint(v); // desktop size
n = vncrdchar(v);
vncrdchar(v);
if(n == 0)
break;
vncrdlong(v); // id
r = vncrdrect(v);
vncrdlong(v); // flags
while(--n > 0){
vncrdlong(v);
vncrdrect(v);
vncrdlong(v);
}
qlock(&drawlock);
if(!rectclip(&r, gscreen->r)){
qunlock(&drawlock);
break;
}
gscreen->clipr = r;
qunlock(&drawlock);
screenwin();
deletescreenimage();
resetscreenimage();
break;
/* send keystroke */
@ -905,7 +933,7 @@ flushmemscreen(Rectangle r)
{
Vncs *v;
if(!rectclip(&r, gscreen->r))
if(!rectclip(&r, gscreen->clipr))
return;
qlock(&clients);
for(v=clients.head; v; v=v->next)
@ -925,7 +953,7 @@ mousewarpnote(Point p)
for(v=clients.head; v; v=v->next){
if(v->canwarp){
vnclock(v);
v->needwarp = 1;
v->dowarp = 1;
v->warppt = p;
vncunlock(v);
}
@ -940,7 +968,7 @@ mousewarpnote(Point p)
static int
updateimage(Vncs *v)
{
int i, ncount, nsend, docursor, needwarp;
int i, j, ncount, nsend, docursor, dowarp, doresize;
vlong ooffset;
Point warppt;
Rectangle cr;
@ -949,20 +977,37 @@ updateimage(Vncs *v)
int (*count)(Vncs*, Rectangle);
int (*send)(Vncs*, Rectangle);
if(v->image == nil)
return 0;
/* warping info and unlock v so that updates can proceed */
needwarp = v->canwarp && v->needwarp;
vnclock(v);
dowarp = v->canwarp && v->dowarp;
warppt = v->warppt;
v->needwarp = 0;
v->dowarp = 0;
vncunlock(v);
/* copy the screen bits and then unlock the screen so updates can proceed */
drawlock();
qlock(&drawlock);
rlist = v->rlist;
memset(&v->rlist, 0, sizeof v->rlist);
if(v->canresize && !eqrect(v->screen[0].rect, gscreen->clipr)){
v->screen[0].rect = gscreen->clipr;
v->dim = rectsubpt(gscreen->clipr, gscreen->clipr.min);
doresize = 1;
} else
doresize = 0;
if(doresize
|| (v->image == nil && v->imagechan != 0)
|| (v->image != nil && v->image->chan != v->imagechan)){
if(v->image)
freememimage(v->image);
v->image = allocmemimage(v->dim, v->imagechan);
if(v->image == nil){
fprint(2, "%V: allocmemimage: %r; hanging up\n", v);
qlock(&drawlock);
vnchungup(v);
}
}
/* if the cursor has moved or changed shape, we need to redraw its square */
lock(&cursor);
if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){
@ -978,7 +1023,7 @@ updateimage(Vncs *v)
if(docursor){
addtorlist(&rlist, v->cursorr);
if(!rectclip(&cr, gscreen->r))
if(!rectclip(&cr, gscreen->clipr))
cr.max = cr.min;
addtorlist(&rlist, cr);
}
@ -996,15 +1041,7 @@ updateimage(Vncs *v)
v->cursorr = cr;
}
drawunlock();
ooffset = Boffset(&v->out);
/* no more locks are held; talk to the client */
if(rlist.nrect == 0 && needwarp == 0){
vnclock(v);
return 0;
}
qunlock(&drawlock);
count = v->countrect;
send = v->sendrect;
@ -1014,16 +1051,45 @@ updateimage(Vncs *v)
}
ncount = 0;
for(i=0; i<rlist.nrect; i++)
ncount += (*count)(v, rlist.rect[i]);
for(i=j=0; i<rlist.nrect; i++){
if(j < i)
rlist.rect[j] = rlist.rect[i];
if(rectclip(&rlist.rect[j], v->dim))
ncount += (*count)(v, rlist.rect[j++]);
}
rlist.nrect = j;
if(verbose > 1)
fprint(2, "sendupdate: rlist.nrect=%d, ncount=%d", rlist.nrect, ncount);
if(doresize == 0 && ncount == 0 && dowarp == 0)
return 0;
if(verbose > 1){
fprint(2, "sendupdate: rlist.nrect=%d, ncount=%d\n", rlist.nrect, ncount);
t1 = nsec();
ooffset = Boffset(&v->out);
}
if(doresize && v->canresize == 1){
doresize = 0;
vncwrchar(v, MFrameUpdate);
vncwrchar(v, 0);
vncwrshort(v, 1);
vncwrrect(v, v->dim);
vncwrlong(v, EncDesktopSize);
}
t1 = nsec();
vncwrchar(v, MFrameUpdate);
vncwrchar(v, 0);
vncwrshort(v, ncount+needwarp);
vncwrshort(v, doresize+ncount+dowarp);
if(doresize){
vncwrrect(v, gscreen->r);
vncwrlong(v, EncXDesktopSize);
vncwrlong(v, 1<<24);
vncwrlong(v, v->screen[0].id);
vncwrrect(v, v->screen[0].rect);
vncwrlong(v, v->screen[0].flags);
}
nsend = 0;
for(i=0; i<rlist.nrect; i++)
@ -1034,17 +1100,17 @@ updateimage(Vncs *v)
vnchungup(v);
}
if(needwarp){
if(dowarp){
vncwrrect(v, Rect(warppt.x, warppt.y, warppt.x+1, warppt.y+1));
vncwrlong(v, EncMouseWarp);
}
t1 = nsec() - t1;
if(verbose > 1)
if(verbose > 1){
t1 = nsec() - t1;
fprint(2, " in %lldms, %lld bytes\n", t1/1000000, Boffset(&v->out) - ooffset);
}
freerlist(&rlist);
vnclock(v);
return 1;
}
@ -1059,13 +1125,11 @@ updatesnarf(Vncs *v)
if(v->snarfvers == snarf.vers)
return;
vncunlock(v);
qlock(&snarf);
len = snarf.n;
buf = malloc(len);
if(buf == nil){
qunlock(&snarf);
vnclock(v);
return;
}
memmove(buf, snarf.buf, len);
@ -1077,7 +1141,6 @@ updatesnarf(Vncs *v)
vncwrlong(v, len);
vncwrbytes(v, buf, len);
free(buf);
vnclock(v);
}
/*
@ -1086,41 +1149,16 @@ updatesnarf(Vncs *v)
static void
clientwriteproc(Vncs *v)
{
char buf[32], buf2[32];
int sent;
ulong last = 0;
vncname("write %V", v);
for(;;){
vnclock(v);
if(v->ndead)
break;
if((v->image == nil && v->imagechan!=0)
|| (v->image && v->image->chan != v->imagechan)){
if(v->image)
freememimage(v->image);
v->image = allocmemimage(v->dim, v->imagechan);
if(v->image == nil){
fprint(2, "%V: allocmemimage: %r; hanging up\n", v);
vnchungup(v);
}
if(verbose)
fprint(2, "%V: translating image from chan=%s to chan=%s\n",
v, chantostr(buf, gscreen->chan), chantostr(buf2, v->imagechan));
}
sent = 0;
if(v->updaterequest){
v->updaterequest = 0;
updatesnarf(v);
sent = updateimage(v);
if(!sent)
v->updaterequest = 1;
}
vncunlock(v);
while(!v->ndead){
sleep(sleeptime);
updatesnarf(v);
if(v->updatereq != last && updateimage(v))
last++;
vncflush(v);
if(!sent)
sleep(sleeptime);
}
vncunlock(v);
vnchungup(v);
}

View file

@ -22,10 +22,11 @@ struct Vncs
int (*sendrect)(Vncs*, Rectangle);
int copyrect;
int canwarp;
int needwarp;
int dowarp;
Point warppt;
int updaterequest;
ulong updatereq;
Rlist rlist;
int ndead;
int nproc;