1607 lines · 31.6 KB · C
RawDownload
/* * /dev/draw simulator -- handles the messages prepared by the draw library. * Doesn't simulate the file system part, just the messages. */ #include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <memlayer.h>#include "devdraw.h" extern void _flushmemscreen(Rectangle); #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; struct Draw{	QLock		lk;	int		clientid;	int		nclient;	Client*		client[1];	int		nname;	DName*		name;	int		vers;	int		softscreen;}; 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	Client		*client0;static	Memimage	*screenimage;static	Rectangle	flushrect;static	int		waste;static	DScreen*	dscreen;static	int		drawuninstall(Client*, int);static	Memimage*	drawinstall(Client*, int, Memimage*, DScreen*);static	void		drawfreedimage(DImage*); void_initdisplaymemimage(Memimage *m){	screenimage = m;	m->screenref = 1;	client0 = mallocz(sizeof(Client), 1);	if(client0 == nil){		fprint(2, "initdraw: allocating client0: out of memory");		abort();	}	client0->slot = 0;	client0->clientid = ++sdraw.clientid;	client0->op = SoverD;	sdraw.client[0] = client0;	sdraw.nclient = 1;	sdraw.softscreen = 1;} void_drawreplacescreenimage(Memimage *m){	/*	 * Replace the screen image because the screen	 * was resized.	 * 	 * In theory there should only be one reference	 * to the current screen image, and that's through	 * client0's image 0, installed a few lines above.	 * Once the client drops the image, the underlying backing 	 * store freed properly.  The client is being notified	 * about the resize through external means, so all we	 * need to do is this assignment.	 */	Memimage *om; 	qlock(&sdraw.lk);	om = screenimage;	screenimage = m;	m->screenref = 1;	if(om && --om->screenref == 0){		_freememimage(om);	}	qunlock(&sdraw.lk);} 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 *m, Rectangle r, void *v){	Refx *x;	DImage *d;	Client *c;	Refresh *ref; 	USED(m); 	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 = mallocz(sizeof(Refresh), 1);	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;	}	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 */	if(flushrect.min.x < flushrect.max.x)		_flushmemscreen(flushrect);	flushrect = r;	waste = 0;} staticvoiddstflush(int dstid, Memimage *dst, Rectangle r){	Memlayer *l; 	if(dstid == 0){		combinerect(&flushrect, r);		return;	}	/* how can this happen? -rsc, dec 12 2002 */	if(dst == 0){		fprint(2, "nil dstflush\n");		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){	if(flushrect.min.x < flushrect.max.x)		_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);} staticDName*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;} staticintdrawgoodname(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;} staticDImage*drawlookup(Client *client, int id, int checkname){	DImage *d; 	d = client->dimage[id&HASHMASK];	while(d){		if(d->id == id){			/*			 * BUG: should error out but too hard.			 * Return 0 instead.			 */			if(checkname && !drawgoodname(d))				return 0;			return d;		}		d = d->next;	}	return 0;} staticDScreen*drawlookupdscreen(int id){	DScreen *s; 	s = dscreen;	while(s){		if(s->id == id)			return s;		s = s->next;	}	return 0;} staticDScreen*drawlookupscreen(Client *client, int id, CScreen **cs){	CScreen *s; 	s = client->cscreen;	while(s){		if(s->dscreen->id == id){			*cs = s;			return s->dscreen;		}		s = s->next;	}	/* caller must check! */	return 0;} staticMemimage*drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen){	DImage *d; 	d = mallocz(sizeof(DImage), 1);	if(d == 0)		return 0;	d->id = id;	d->ref = 1;	d->name = 0;	d->vers = 0;	d->image = i;	if(i->screenref)		++i->screenref;	d->nfchar = 0;	d->fchar = 0;	d->fromname = 0;	d->dscreen = dscreen;	d->next = client->dimage[id&HASHMASK];	client->dimage[id&HASHMASK] = d;	return i;} staticMemscreen*drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public){	Memscreen *s;	CScreen *c; 	c = mallocz(sizeof(CScreen), 1);	if(dimage && dimage->image && dimage->image->chan == 0){		fprint(2, "bad image %p in drawinstallscreen", dimage->image);		abort();	} 	if(c == 0)		return 0;	if(d == 0){		d = mallocz(sizeof(DScreen), 1);		if(d == 0){			free(c);			return 0;		}		s = mallocz(sizeof(Memscreen), 1);		if(s == 0){			free(c);			free(d);			return 0;		}		s->frontmost = 0;		s->rearmost = 0;		d->dimage = dimage;		if(dimage){			s->image = dimage->image;			dimage->ref++;		}		d->dfill = dfill;		if(dfill){			s->fill = dfill->image;			dfill->ref++;		}		d->ref = 0;		d->id = id;		d->screen = s;		d->public = public;		d->next = dscreen;		d->owner = client;		dscreen = d;	}	c->dscreen = d;	d->ref++;	c->next = client->cscreen;	client->cscreen = c;	return d->screen;} staticvoiddrawdelname(DName *name){	int i; 	i = name-sdraw.name;	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));	sdraw.nname--;} staticvoiddrawfreedscreen(DScreen *this){	DScreen *ds, *next; 	this->ref--;	if(this->ref < 0)		fprint(2, "negative ref in drawfreedscreen\n");	if(this->ref > 0)		return;	ds = dscreen;

Lines 1–500 of 1607.