2086 lines · 41.0 KB · C
RawDownload
#include	<u.h>#include	<libc.h>#include	"compat.h"#include	"error.h" #define	Image	IMAGE#include	<draw.h>#include	<memdraw.h>#include	<memlayer.h>#include	<cursor.h>#include	"screen.h" enum{	Qtopdir		= 0,	Qnew,	Q3rd,	Q2nd,	Qcolormap,	Qctl,	Qdata,	Qrefresh,}; /* * Qid path is: *	 4 bits of file type (qids above) *	24 bits of mux slot number +1; 0 means not attached to client */#define	QSHIFT	4	/* location in qid of client # */ #define	QID(q)		((((ulong)(q).path)&0x0000000F)>>0)#define	CLIENTPATH(q)	((((ulong)q)&0x7FFFFFF0)>>QSHIFT)#define	CLIENT(q)	CLIENTPATH((q).path) #define	NHASH		(1<<5)#define	HASHMASK	(NHASH-1) typedef struct Client Client;typedef struct Draw Draw;typedef struct DImage DImage;typedef struct DScreen DScreen;typedef struct CScreen CScreen;typedef struct FChar FChar;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;	int		vers;	int		softscreen;	int		blanked;	/* screen turned off */	ulong		blanktime;	/* time of last operation */	ulong		savemap[3*256];}; struct Client{	Ref		r;	DImage*		dimage[NHASH];	CScreen*	cscreen;	Refresh*	refresh;	Rendez		refrend;	uchar*		readdata;	int		nreaddata;	int		busy;	int		clientid;	int		slot;	int		refreshme;	int		infoid;	int		op;}; struct Refresh{	DImage*		dimage;	Rectangle	r;	Refresh*	next;}; struct Refx{	Client*		client;	DImage*		dimage;}; struct DName{	char			*name;	Client	*client;	DImage*		dimage;	int			vers;}; struct FChar{	int		minx;	/* left edge of bits */	int		maxx;	/* right edge of bits */	uchar		miny;	/* first non-zero scan-line */	uchar		maxy;	/* last non-zero scan-line + 1 */	schar		left;	/* offset of baseline */	uchar		width;	/* width of baseline */}; /* * Reference counts in DImages: *	one per open by original client *	one per screen image or fill * 	one per image derived from this one by name */struct DImage{	int		id;	int		ref;	char		*name;	int		vers;	Memimage*	image;	int		ascent;	int		nfchar;	FChar*		fchar;	DScreen*	dscreen;	/* 0 if not a window */	DImage*	fromname;	/* image this one is derived from, by name */	DImage*		next;}; struct CScreen{	DScreen*	dscreen;	CScreen*	next;}; struct DScreen{	int		id;	int		public;	int		ref;	DImage	*dimage;	DImage	*dfill;	Memscreen*	screen;	Client*		owner;	DScreen*	next;}; static	Draw		sdraw;static	Memimage	*screenimage;static	Memdata	screendata;static	Rectangle	flushrect;static	int		waste;static	DScreen*	dscreen;extern	void		flushmemscreen(Rectangle);	void		drawmesg(Client*, void*, int);	void		drawuninstall(Client*, int);	void		drawfreedimage(DImage*);	Client*		drawclientofpath(ulong); static	char Enodrawimage[] =	"unknown id for draw image";static	char Enodrawscreen[] =	"unknown id for draw screen";static	char Eshortdraw[] =	"short draw message";static	char Eshortread[] =	"draw read too short";static	char Eimageexists[] =	"image id in use";static	char Escreenexists[] =	"screen id in use";static	char Edrawmem[] =	"image memory allocation failed";static	char Ereadoutside[] =	"readimage outside image";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"; voiddrawlock(void){	qlock(&sdraw);} voiddrawunlock(void){	qunlock(&sdraw);} intcandrawlock(void){	return canqlock(&sdraw);} static intdrawgen(Chan *c, Dirtab*, int, int s, Dir *dp){	int t;	Qid q;	ulong path;	Client *cl; 	q.vers = 0; 	if(s == DEVDOTDOT){		switch(QID(c->qid)){		case Qtopdir:		case Q2nd:			mkqid(&q, Qtopdir, 0, QTDIR);			devdir(c, q, "#i", 0, eve, 0500, dp);			break;		case Q3rd:			cl = drawclientofpath(c->qid.path);			if(cl == nil)				strcpy(up->genbuf, "??");			else				sprint(up->genbuf, "%d", cl->clientid);			mkqid(&q, Q2nd, 0, QTDIR);			devdir(c, q, up->genbuf, 0, eve, 0500, dp);			break;		default:			panic("drawwalk %#llux", c->qid.path);		}		return 1;	} 	/*	 * Top level directory contains the name of the device.	 */	t = QID(c->qid);	if(t == Qtopdir){		switch(s){		case 0:			mkqid(&q, Q2nd, 0, QTDIR);			devdir(c, q, "draw", 0, eve, 0555, dp);			break;		default:			return -1;		}		return 1;	} 	/*	 * Second level contains "new" plus all the clients.	 */	if(t == Q2nd || t == Qnew){		if(s == 0){			mkqid(&q, Qnew, 0, QTFILE);			devdir(c, q, "new", 0, eve, 0666, dp);		}		else if(s <= sdraw.nclient){			cl = sdraw.client[s-1];			if(cl == 0)				return 0;			sprint(up->genbuf, "%d", cl->clientid);			mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		}		else			return -1;		return 1;	} 	/*	 * Third level.	 */	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */	q.vers = c->qid.vers;	q.type = QTFILE;	switch(s){	case 0:		q.path = path|Qcolormap;		devdir(c, q, "colormap", 0, eve, 0600, dp);		break;	case 1:		q.path = path|Qctl;		devdir(c, q, "ctl", 0, eve, 0600, dp);		break;	case 2:		q.path = path|Qdata;		devdir(c, q, "data", 0, eve, 0600, dp);		break;	case 3:		q.path = path|Qrefresh;		devdir(c, q, "refresh", 0, eve, 0400, dp);		break;	default:		return -1;	}	return 1;} staticintdrawrefactive(void *a){	Client *c; 	c = a;	return c->refreshme || c->refresh!=0;} staticvoiddrawrefreshscreen(DImage *l, Client *client){	while(l != nil && l->dscreen == nil)		l = l->fromname;	if(l != nil && l->dscreen->owner != client)		l->dscreen->owner->refreshme = 1;} staticvoiddrawrefresh(Memimage *l, Rectangle r, void *v){	Refx *x;	DImage *d;	Client *c;	Refresh *ref; 	USED(l);	if(v == 0)		return;	x = v;	c = x->client;	d = x->dimage;	for(ref=c->refresh; ref; ref=ref->next)		if(ref->dimage == d){			combinerect(&ref->r, r);			return;		}	ref = malloc(sizeof(Refresh));	if(ref){		ref->dimage = d;		ref->r = r;		ref->next = c->refresh;		c->refresh = ref;	}} static voidaddflush(Rectangle r){	int abb, ar, anbb;	Rectangle nbb; 	if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))		return; 	if(flushrect.min.x >= flushrect.max.x){		flushrect = r;		waste = 0;		return;	}	/* VNC uses a region to compute the minimum bounding area.	 * The waste is far less than that of a bounding box. see region.c	 */	if(1){		flushmemscreen(flushrect);		flushrect = r;		return;	}	nbb = flushrect;	combinerect(&nbb, r);	ar = Dx(r)*Dy(r);	abb = Dx(flushrect)*Dy(flushrect);	anbb = Dx(nbb)*Dy(nbb);	/*	 * Area of new waste is area of new bb minus area of old bb,	 * less the area of the new segment, which we assume is not waste.	 * This could be negative, but that's OK.	 */	waste += anbb-abb - ar;	if(waste < 0)		waste = 0;	/*	 * absorb if:	 *	total area is small	 *	waste is less than half total area	 * 	rectangles touch	 */	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){		flushrect = nbb;		return;	}	/* emit current state */	flushmemscreen(flushrect);	flushrect = r;	waste = 0;} staticvoiddstflush(int dstid, Memimage *dst, Rectangle r){	Memlayer *l; 	if(dstid == 0){		//combinerect(&flushrect, r);		addflush(r); // for VNC, see comments in addflush		return;	}	l = dst->layer;	if(l == nil)		return;	do{		if(l->screen->image->data != screenimage->data)			return;		r = rectaddpt(r, l->delta);		l = l->screen->image->layer;	}while(l);	addflush(r);} staticvoiddrawflush(void){	flushmemscreen(flushrect);	flushrect = Rect(10000, 10000, -10000, -10000);} staticintdrawcmp(char *a, char *b, int n){	if(strlen(a) != n)		return 1;	return memcmp(a, b, n);} DName*drawlookupname(int n, char *str){	DName *name, *ename; 	name = sdraw.name;	ename = &name[sdraw.nname];	for(; name<ename; name++)		if(drawcmp(name->name, str, n) == 0)			return name;	return 0;} intdrawgoodname(DImage *d){	DName *n; 	/* if window, validate the screen's own images */	if(d->dscreen)		if(drawgoodname(d->dscreen->dimage) == 0		|| drawgoodname(d->dscreen->dfill) == 0)			return 0;	if(d->name == nil)		return 1;	n = drawlookupname(strlen(d->name), d->name);	if(n==nil || n->vers!=d->vers)		return 0;	return 1;} DImage*drawlookup(Client *client, int id, int checkname){	DImage *d; 	d = client->dimage[id&HASHMASK];	while(d){		if(d->id == id){			if(checkname && !drawgoodname(d))				error(Eoldname);			return d;		}		d = d->next;	}	return 0;} DScreen*drawlookupdscreen(int id){	DScreen *s; 	s = dscreen;	while(s){		if(s->id == id)			return s;		s = s->next;	}	return 0;

Lines 1–500 of 2086.