xref: /plan9/sys/src/cmd/vnc/devdraw.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
19a747e4fSDavid du Colombier #include	<u.h>
29a747e4fSDavid du Colombier #include	<libc.h>
39a747e4fSDavid du Colombier #include	"compat.h"
49a747e4fSDavid du Colombier #include	"error.h"
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier #define	Image	IMAGE
79a747e4fSDavid du Colombier #include	<draw.h>
89a747e4fSDavid du Colombier #include	<memdraw.h>
99a747e4fSDavid du Colombier #include	<memlayer.h>
109a747e4fSDavid du Colombier #include	<cursor.h>
119a747e4fSDavid du Colombier #include	"screen.h"
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier enum
149a747e4fSDavid du Colombier {
159a747e4fSDavid du Colombier 	Qtopdir		= 0,
169a747e4fSDavid du Colombier 	Qnew,
179a747e4fSDavid du Colombier 	Q3rd,
189a747e4fSDavid du Colombier 	Q2nd,
199a747e4fSDavid du Colombier 	Qcolormap,
209a747e4fSDavid du Colombier 	Qctl,
219a747e4fSDavid du Colombier 	Qdata,
229a747e4fSDavid du Colombier 	Qrefresh,
239a747e4fSDavid du Colombier };
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier /*
269a747e4fSDavid du Colombier  * Qid path is:
279a747e4fSDavid du Colombier  *	 4 bits of file type (qids above)
289a747e4fSDavid du Colombier  *	24 bits of mux slot number +1; 0 means not attached to client
299a747e4fSDavid du Colombier  */
309a747e4fSDavid du Colombier #define	QSHIFT	4	/* location in qid of client # */
319a747e4fSDavid du Colombier 
329a747e4fSDavid du Colombier #define	QID(q)		((((ulong)(q).path)&0x0000000F)>>0)
339a747e4fSDavid du Colombier #define	CLIENTPATH(q)	((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
349a747e4fSDavid du Colombier #define	CLIENT(q)	CLIENTPATH((q).path)
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier #define	NHASH		(1<<5)
379a747e4fSDavid du Colombier #define	HASHMASK	(NHASH-1)
389a747e4fSDavid du Colombier 
399a747e4fSDavid du Colombier typedef struct Client Client;
409a747e4fSDavid du Colombier typedef struct Draw Draw;
419a747e4fSDavid du Colombier typedef struct DImage DImage;
429a747e4fSDavid du Colombier typedef struct DScreen DScreen;
439a747e4fSDavid du Colombier typedef struct CScreen CScreen;
449a747e4fSDavid du Colombier typedef struct FChar FChar;
459a747e4fSDavid du Colombier typedef struct Refresh Refresh;
469a747e4fSDavid du Colombier typedef struct Refx Refx;
479a747e4fSDavid du Colombier typedef struct DName DName;
489a747e4fSDavid du Colombier 
499a747e4fSDavid du Colombier ulong blanktime = 30;	/* in minutes; a half hour */
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier struct Draw
529a747e4fSDavid du Colombier {
539a747e4fSDavid du Colombier 	QLock;
549a747e4fSDavid du Colombier 	int		clientid;
559a747e4fSDavid du Colombier 	int		nclient;
569a747e4fSDavid du Colombier 	Client**	client;
579a747e4fSDavid du Colombier 	int		nname;
589a747e4fSDavid du Colombier 	DName*	name;
599a747e4fSDavid du Colombier 	int		vers;
609a747e4fSDavid du Colombier 	int		softscreen;
619a747e4fSDavid du Colombier 	int		blanked;	/* screen turned off */
629a747e4fSDavid du Colombier 	ulong		blanktime;	/* time of last operation */
639a747e4fSDavid du Colombier 	ulong		savemap[3*256];
649a747e4fSDavid du Colombier };
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier struct Client
679a747e4fSDavid du Colombier {
689a747e4fSDavid du Colombier 	Ref		r;
699a747e4fSDavid du Colombier 	DImage*		dimage[NHASH];
709a747e4fSDavid du Colombier 	CScreen*	cscreen;
719a747e4fSDavid du Colombier 	Refresh*	refresh;
729a747e4fSDavid du Colombier 	Rendez		refrend;
739a747e4fSDavid du Colombier 	uchar*		readdata;
749a747e4fSDavid du Colombier 	int		nreaddata;
759a747e4fSDavid du Colombier 	int		busy;
769a747e4fSDavid du Colombier 	int		clientid;
779a747e4fSDavid du Colombier 	int		slot;
789a747e4fSDavid du Colombier 	int		refreshme;
799a747e4fSDavid du Colombier 	int		infoid;
806a9fc400SDavid du Colombier 	int		op;
819a747e4fSDavid du Colombier };
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier struct Refresh
849a747e4fSDavid du Colombier {
859a747e4fSDavid du Colombier 	DImage*		dimage;
869a747e4fSDavid du Colombier 	Rectangle	r;
879a747e4fSDavid du Colombier 	Refresh*	next;
889a747e4fSDavid du Colombier };
899a747e4fSDavid du Colombier 
909a747e4fSDavid du Colombier struct Refx
919a747e4fSDavid du Colombier {
929a747e4fSDavid du Colombier 	Client*		client;
939a747e4fSDavid du Colombier 	DImage*		dimage;
949a747e4fSDavid du Colombier };
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier struct DName
979a747e4fSDavid du Colombier {
989a747e4fSDavid du Colombier 	char			*name;
999a747e4fSDavid du Colombier 	Client	*client;
1009a747e4fSDavid du Colombier 	DImage*		dimage;
1019a747e4fSDavid du Colombier 	int			vers;
1029a747e4fSDavid du Colombier };
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier struct FChar
1059a747e4fSDavid du Colombier {
1069a747e4fSDavid du Colombier 	int		minx;	/* left edge of bits */
1079a747e4fSDavid du Colombier 	int		maxx;	/* right edge of bits */
1089a747e4fSDavid du Colombier 	uchar		miny;	/* first non-zero scan-line */
1099a747e4fSDavid du Colombier 	uchar		maxy;	/* last non-zero scan-line + 1 */
1109a747e4fSDavid du Colombier 	schar		left;	/* offset of baseline */
1119a747e4fSDavid du Colombier 	uchar		width;	/* width of baseline */
1129a747e4fSDavid du Colombier };
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier /*
1159a747e4fSDavid du Colombier  * Reference counts in DImages:
1169a747e4fSDavid du Colombier  *	one per open by original client
1179a747e4fSDavid du Colombier  *	one per screen image or fill
1189a747e4fSDavid du Colombier  * 	one per image derived from this one by name
1199a747e4fSDavid du Colombier  */
1209a747e4fSDavid du Colombier struct DImage
1219a747e4fSDavid du Colombier {
1229a747e4fSDavid du Colombier 	int		id;
1239a747e4fSDavid du Colombier 	int		ref;
1249a747e4fSDavid du Colombier 	char		*name;
1259a747e4fSDavid du Colombier 	int		vers;
1269a747e4fSDavid du Colombier 	Memimage*	image;
1279a747e4fSDavid du Colombier 	int		ascent;
1289a747e4fSDavid du Colombier 	int		nfchar;
1299a747e4fSDavid du Colombier 	FChar*		fchar;
1309a747e4fSDavid du Colombier 	DScreen*	dscreen;	/* 0 if not a window */
1319a747e4fSDavid du Colombier 	DImage*	fromname;	/* image this one is derived from, by name */
1329a747e4fSDavid du Colombier 	DImage*		next;
1339a747e4fSDavid du Colombier };
1349a747e4fSDavid du Colombier 
1359a747e4fSDavid du Colombier struct CScreen
1369a747e4fSDavid du Colombier {
1379a747e4fSDavid du Colombier 	DScreen*	dscreen;
1389a747e4fSDavid du Colombier 	CScreen*	next;
1399a747e4fSDavid du Colombier };
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier struct DScreen
1429a747e4fSDavid du Colombier {
1439a747e4fSDavid du Colombier 	int		id;
1449a747e4fSDavid du Colombier 	int		public;
1459a747e4fSDavid du Colombier 	int		ref;
1469a747e4fSDavid du Colombier 	DImage	*dimage;
1479a747e4fSDavid du Colombier 	DImage	*dfill;
1489a747e4fSDavid du Colombier 	Memscreen*	screen;
1499a747e4fSDavid du Colombier 	Client*		owner;
1509a747e4fSDavid du Colombier 	DScreen*	next;
1519a747e4fSDavid du Colombier };
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier static	Draw		sdraw;
1549a747e4fSDavid du Colombier static	Memimage	*screenimage;
1559a747e4fSDavid du Colombier static	Memdata	screendata;
1569a747e4fSDavid du Colombier static	Rectangle	flushrect;
1579a747e4fSDavid du Colombier static	int		waste;
1589a747e4fSDavid du Colombier static	DScreen*	dscreen;
1599a747e4fSDavid du Colombier extern	void		flushmemscreen(Rectangle);
1609a747e4fSDavid du Colombier 	void		drawmesg(Client*, void*, int);
1619a747e4fSDavid du Colombier 	void		drawuninstall(Client*, int);
1629a747e4fSDavid du Colombier 	void		drawfreedimage(DImage*);
1639a747e4fSDavid du Colombier 	Client*		drawclientofpath(ulong);
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier static	char Enodrawimage[] =	"unknown id for draw image";
1669a747e4fSDavid du Colombier static	char Enodrawscreen[] =	"unknown id for draw screen";
1679a747e4fSDavid du Colombier static	char Eshortdraw[] =	"short draw message";
1689a747e4fSDavid du Colombier static	char Eshortread[] =	"draw read too short";
1699a747e4fSDavid du Colombier static	char Eimageexists[] =	"image id in use";
1709a747e4fSDavid du Colombier static	char Escreenexists[] =	"screen id in use";
1719a747e4fSDavid du Colombier static	char Edrawmem[] =	"image memory allocation failed";
1729a747e4fSDavid du Colombier static	char Ereadoutside[] =	"readimage outside image";
1739a747e4fSDavid du Colombier static	char Ewriteoutside[] =	"writeimage outside image";
1749a747e4fSDavid du Colombier static	char Enotfont[] =	"image not a font";
1759a747e4fSDavid du Colombier static	char Eindex[] =		"character index out of range";
1769a747e4fSDavid du Colombier static	char Enoclient[] =	"no such draw client";
1779a747e4fSDavid du Colombier static	char Edepth[] =	"image has bad depth";
1789a747e4fSDavid du Colombier static	char Enameused[] =	"image name in use";
1799a747e4fSDavid du Colombier static	char Enoname[] =	"no image with that name";
1809a747e4fSDavid du Colombier static	char Eoldname[] =	"named image no longer valid";
1819a747e4fSDavid du Colombier static	char Enamed[] = 	"image already has name";
1829a747e4fSDavid du Colombier static	char Ewrongname[] = 	"wrong name for image";
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier void
drawlock(void)1859a747e4fSDavid du Colombier drawlock(void)
1869a747e4fSDavid du Colombier {
1879a747e4fSDavid du Colombier 	qlock(&sdraw);
1889a747e4fSDavid du Colombier }
1899a747e4fSDavid du Colombier 
1909a747e4fSDavid du Colombier void
drawunlock(void)1919a747e4fSDavid du Colombier drawunlock(void)
1929a747e4fSDavid du Colombier {
1939a747e4fSDavid du Colombier 	qunlock(&sdraw);
1949a747e4fSDavid du Colombier }
1959a747e4fSDavid du Colombier 
1969a747e4fSDavid du Colombier int
candrawlock(void)1979a747e4fSDavid du Colombier candrawlock(void)
1989a747e4fSDavid du Colombier {
1999a747e4fSDavid du Colombier 	return canqlock(&sdraw);
2009a747e4fSDavid du Colombier }
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier static int
drawgen(Chan * c,Dirtab *,int,int s,Dir * dp)2039a747e4fSDavid du Colombier drawgen(Chan *c, Dirtab*, int, int s, Dir *dp)
2049a747e4fSDavid du Colombier {
2059a747e4fSDavid du Colombier 	int t;
2069a747e4fSDavid du Colombier 	Qid q;
2079a747e4fSDavid du Colombier 	ulong path;
2089a747e4fSDavid du Colombier 	Client *cl;
2099a747e4fSDavid du Colombier 
2109a747e4fSDavid du Colombier 	q.vers = 0;
2119a747e4fSDavid du Colombier 
2129a747e4fSDavid du Colombier 	if(s == DEVDOTDOT){
2139a747e4fSDavid du Colombier 		switch(QID(c->qid)){
2149a747e4fSDavid du Colombier 		case Qtopdir:
2159a747e4fSDavid du Colombier 		case Q2nd:
2169a747e4fSDavid du Colombier 			mkqid(&q, Qtopdir, 0, QTDIR);
2179a747e4fSDavid du Colombier 			devdir(c, q, "#i", 0, eve, 0500, dp);
2189a747e4fSDavid du Colombier 			break;
2199a747e4fSDavid du Colombier 		case Q3rd:
2209a747e4fSDavid du Colombier 			cl = drawclientofpath(c->qid.path);
2219a747e4fSDavid du Colombier 			if(cl == nil)
2229a747e4fSDavid du Colombier 				strcpy(up->genbuf, "??");
2239a747e4fSDavid du Colombier 			else
2249a747e4fSDavid du Colombier 				sprint(up->genbuf, "%d", cl->clientid);
2259a747e4fSDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
2269a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0500, dp);
2279a747e4fSDavid du Colombier 			break;
2289a747e4fSDavid du Colombier 		default:
229*74f16c81SDavid du Colombier 			panic("drawwalk %#llux", c->qid.path);
2309a747e4fSDavid du Colombier 		}
2319a747e4fSDavid du Colombier 		return 1;
2329a747e4fSDavid du Colombier 	}
2339a747e4fSDavid du Colombier 
2349a747e4fSDavid du Colombier 	/*
2359a747e4fSDavid du Colombier 	 * Top level directory contains the name of the device.
2369a747e4fSDavid du Colombier 	 */
2379a747e4fSDavid du Colombier 	t = QID(c->qid);
2389a747e4fSDavid du Colombier 	if(t == Qtopdir){
2399a747e4fSDavid du Colombier 		switch(s){
2409a747e4fSDavid du Colombier 		case 0:
2419a747e4fSDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
2429a747e4fSDavid du Colombier 			devdir(c, q, "draw", 0, eve, 0555, dp);
2439a747e4fSDavid du Colombier 			break;
2449a747e4fSDavid du Colombier 		default:
2459a747e4fSDavid du Colombier 			return -1;
2469a747e4fSDavid du Colombier 		}
2479a747e4fSDavid du Colombier 		return 1;
2489a747e4fSDavid du Colombier 	}
2499a747e4fSDavid du Colombier 
2509a747e4fSDavid du Colombier 	/*
2519a747e4fSDavid du Colombier 	 * Second level contains "new" plus all the clients.
2529a747e4fSDavid du Colombier 	 */
2539a747e4fSDavid du Colombier 	if(t == Q2nd || t == Qnew){
2549a747e4fSDavid du Colombier 		if(s == 0){
2559a747e4fSDavid du Colombier 			mkqid(&q, Qnew, 0, QTFILE);
2569a747e4fSDavid du Colombier 			devdir(c, q, "new", 0, eve, 0666, dp);
2579a747e4fSDavid du Colombier 		}
2589a747e4fSDavid du Colombier 		else if(s <= sdraw.nclient){
2599a747e4fSDavid du Colombier 			cl = sdraw.client[s-1];
2609a747e4fSDavid du Colombier 			if(cl == 0)
2619a747e4fSDavid du Colombier 				return 0;
2629a747e4fSDavid du Colombier 			sprint(up->genbuf, "%d", cl->clientid);
2639a747e4fSDavid du Colombier 			mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
2649a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
2659a747e4fSDavid du Colombier 			return 1;
2669a747e4fSDavid du Colombier 		}
2679a747e4fSDavid du Colombier 		else
2689a747e4fSDavid du Colombier 			return -1;
2699a747e4fSDavid du Colombier 		return 1;
2709a747e4fSDavid du Colombier 	}
2719a747e4fSDavid du Colombier 
2729a747e4fSDavid du Colombier 	/*
2739a747e4fSDavid du Colombier 	 * Third level.
2749a747e4fSDavid du Colombier 	 */
2759a747e4fSDavid du Colombier 	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
2769a747e4fSDavid du Colombier 	q.vers = c->qid.vers;
2779a747e4fSDavid du Colombier 	q.type = QTFILE;
2789a747e4fSDavid du Colombier 	switch(s){
2799a747e4fSDavid du Colombier 	case 0:
2809a747e4fSDavid du Colombier 		q.path = path|Qcolormap;
2819a747e4fSDavid du Colombier 		devdir(c, q, "colormap", 0, eve, 0600, dp);
2829a747e4fSDavid du Colombier 		break;
2839a747e4fSDavid du Colombier 	case 1:
2849a747e4fSDavid du Colombier 		q.path = path|Qctl;
2859a747e4fSDavid du Colombier 		devdir(c, q, "ctl", 0, eve, 0600, dp);
2869a747e4fSDavid du Colombier 		break;
2879a747e4fSDavid du Colombier 	case 2:
2889a747e4fSDavid du Colombier 		q.path = path|Qdata;
2899a747e4fSDavid du Colombier 		devdir(c, q, "data", 0, eve, 0600, dp);
2909a747e4fSDavid du Colombier 		break;
2919a747e4fSDavid du Colombier 	case 3:
2929a747e4fSDavid du Colombier 		q.path = path|Qrefresh;
2939a747e4fSDavid du Colombier 		devdir(c, q, "refresh", 0, eve, 0400, dp);
2949a747e4fSDavid du Colombier 		break;
2959a747e4fSDavid du Colombier 	default:
2969a747e4fSDavid du Colombier 		return -1;
2979a747e4fSDavid du Colombier 	}
2989a747e4fSDavid du Colombier 	return 1;
2999a747e4fSDavid du Colombier }
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier static
3029a747e4fSDavid du Colombier int
drawrefactive(void * a)3039a747e4fSDavid du Colombier drawrefactive(void *a)
3049a747e4fSDavid du Colombier {
3059a747e4fSDavid du Colombier 	Client *c;
3069a747e4fSDavid du Colombier 
3079a747e4fSDavid du Colombier 	c = a;
3089a747e4fSDavid du Colombier 	return c->refreshme || c->refresh!=0;
3099a747e4fSDavid du Colombier }
3109a747e4fSDavid du Colombier 
3119a747e4fSDavid du Colombier static
3129a747e4fSDavid du Colombier void
drawrefreshscreen(DImage * l,Client * client)3139a747e4fSDavid du Colombier drawrefreshscreen(DImage *l, Client *client)
3149a747e4fSDavid du Colombier {
3159a747e4fSDavid du Colombier 	while(l != nil && l->dscreen == nil)
3169a747e4fSDavid du Colombier 		l = l->fromname;
3179a747e4fSDavid du Colombier 	if(l != nil && l->dscreen->owner != client)
3189a747e4fSDavid du Colombier 		l->dscreen->owner->refreshme = 1;
3199a747e4fSDavid du Colombier }
3209a747e4fSDavid du Colombier 
3219a747e4fSDavid du Colombier static
3229a747e4fSDavid du Colombier void
drawrefresh(Memimage * l,Rectangle r,void * v)3239a747e4fSDavid du Colombier drawrefresh(Memimage *l, Rectangle r, void *v)
3249a747e4fSDavid du Colombier {
3259a747e4fSDavid du Colombier 	Refx *x;
3269a747e4fSDavid du Colombier 	DImage *d;
3279a747e4fSDavid du Colombier 	Client *c;
3289a747e4fSDavid du Colombier 	Refresh *ref;
3299a747e4fSDavid du Colombier 
3309a747e4fSDavid du Colombier 	USED(l);
3319a747e4fSDavid du Colombier 	if(v == 0)
3329a747e4fSDavid du Colombier 		return;
3339a747e4fSDavid du Colombier 	x = v;
3349a747e4fSDavid du Colombier 	c = x->client;
3359a747e4fSDavid du Colombier 	d = x->dimage;
3369a747e4fSDavid du Colombier 	for(ref=c->refresh; ref; ref=ref->next)
3379a747e4fSDavid du Colombier 		if(ref->dimage == d){
3389a747e4fSDavid du Colombier 			combinerect(&ref->r, r);
3399a747e4fSDavid du Colombier 			return;
3409a747e4fSDavid du Colombier 		}
3419a747e4fSDavid du Colombier 	ref = malloc(sizeof(Refresh));
3429a747e4fSDavid du Colombier 	if(ref){
3439a747e4fSDavid du Colombier 		ref->dimage = d;
3449a747e4fSDavid du Colombier 		ref->r = r;
3459a747e4fSDavid du Colombier 		ref->next = c->refresh;
3469a747e4fSDavid du Colombier 		c->refresh = ref;
3479a747e4fSDavid du Colombier 	}
3489a747e4fSDavid du Colombier }
3499a747e4fSDavid du Colombier 
3509a747e4fSDavid du Colombier static void
addflush(Rectangle r)3519a747e4fSDavid du Colombier addflush(Rectangle r)
3529a747e4fSDavid du Colombier {
3539a747e4fSDavid du Colombier 	int abb, ar, anbb;
3549a747e4fSDavid du Colombier 	Rectangle nbb;
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 	if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
3579a747e4fSDavid du Colombier 		return;
3589a747e4fSDavid du Colombier 
3599a747e4fSDavid du Colombier 	if(flushrect.min.x >= flushrect.max.x){
3609a747e4fSDavid du Colombier 		flushrect = r;
3619a747e4fSDavid du Colombier 		waste = 0;
3629a747e4fSDavid du Colombier 		return;
3639a747e4fSDavid du Colombier 	}
3649a747e4fSDavid du Colombier 	/* VNC uses a region to compute the minimum bounding area.
3659a747e4fSDavid du Colombier 	 * The waste is far less than that of a bounding box. see region.c
3669a747e4fSDavid du Colombier 	 */
3679a747e4fSDavid du Colombier 	if(1){
3689a747e4fSDavid du Colombier 		flushmemscreen(flushrect);
3699a747e4fSDavid du Colombier 		flushrect = r;
3709a747e4fSDavid du Colombier 		return;
3719a747e4fSDavid du Colombier 	}
3729a747e4fSDavid du Colombier 	nbb = flushrect;
3739a747e4fSDavid du Colombier 	combinerect(&nbb, r);
3749a747e4fSDavid du Colombier 	ar = Dx(r)*Dy(r);
3759a747e4fSDavid du Colombier 	abb = Dx(flushrect)*Dy(flushrect);
3769a747e4fSDavid du Colombier 	anbb = Dx(nbb)*Dy(nbb);
3779a747e4fSDavid du Colombier 	/*
3789a747e4fSDavid du Colombier 	 * Area of new waste is area of new bb minus area of old bb,
3799a747e4fSDavid du Colombier 	 * less the area of the new segment, which we assume is not waste.
3809a747e4fSDavid du Colombier 	 * This could be negative, but that's OK.
3819a747e4fSDavid du Colombier 	 */
3829a747e4fSDavid du Colombier 	waste += anbb-abb - ar;
3839a747e4fSDavid du Colombier 	if(waste < 0)
3849a747e4fSDavid du Colombier 		waste = 0;
3859a747e4fSDavid du Colombier 	/*
3869a747e4fSDavid du Colombier 	 * absorb if:
3879a747e4fSDavid du Colombier 	 *	total area is small
3889a747e4fSDavid du Colombier 	 *	waste is less than half total area
3899a747e4fSDavid du Colombier 	 * 	rectangles touch
3909a747e4fSDavid du Colombier 	 */
3919a747e4fSDavid du Colombier 	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
3929a747e4fSDavid du Colombier 		flushrect = nbb;
3939a747e4fSDavid du Colombier 		return;
3949a747e4fSDavid du Colombier 	}
3959a747e4fSDavid du Colombier 	/* emit current state */
3969a747e4fSDavid du Colombier 	flushmemscreen(flushrect);
3979a747e4fSDavid du Colombier 	flushrect = r;
3989a747e4fSDavid du Colombier 	waste = 0;
3999a747e4fSDavid du Colombier }
4009a747e4fSDavid du Colombier 
4019a747e4fSDavid du Colombier static
4029a747e4fSDavid du Colombier void
dstflush(int dstid,Memimage * dst,Rectangle r)4039a747e4fSDavid du Colombier dstflush(int dstid, Memimage *dst, Rectangle r)
4049a747e4fSDavid du Colombier {
4059a747e4fSDavid du Colombier 	Memlayer *l;
4069a747e4fSDavid du Colombier 
4079a747e4fSDavid du Colombier 	if(dstid == 0){
4089a747e4fSDavid du Colombier 		//combinerect(&flushrect, r);
4099a747e4fSDavid du Colombier 		addflush(r); // for VNC, see comments in addflush
4109a747e4fSDavid du Colombier 		return;
4119a747e4fSDavid du Colombier 	}
4129a747e4fSDavid du Colombier 	l = dst->layer;
4139a747e4fSDavid du Colombier 	if(l == nil)
4149a747e4fSDavid du Colombier 		return;
4159a747e4fSDavid du Colombier 	do{
4169a747e4fSDavid du Colombier 		if(l->screen->image->data != screenimage->data)
4179a747e4fSDavid du Colombier 			return;
4189a747e4fSDavid du Colombier 		r = rectaddpt(r, l->delta);
4199a747e4fSDavid du Colombier 		l = l->screen->image->layer;
4209a747e4fSDavid du Colombier 	}while(l);
4219a747e4fSDavid du Colombier 	addflush(r);
4229a747e4fSDavid du Colombier }
4239a747e4fSDavid du Colombier 
4249a747e4fSDavid du Colombier static
4259a747e4fSDavid du Colombier void
drawflush(void)4269a747e4fSDavid du Colombier drawflush(void)
4279a747e4fSDavid du Colombier {
4289a747e4fSDavid du Colombier 	flushmemscreen(flushrect);
4299a747e4fSDavid du Colombier 	flushrect = Rect(10000, 10000, -10000, -10000);
4309a747e4fSDavid du Colombier }
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier static
4339a747e4fSDavid du Colombier int
drawcmp(char * a,char * b,int n)4349a747e4fSDavid du Colombier drawcmp(char *a, char *b, int n)
4359a747e4fSDavid du Colombier {
4369a747e4fSDavid du Colombier 	if(strlen(a) != n)
4379a747e4fSDavid du Colombier 		return 1;
4389a747e4fSDavid du Colombier 	return memcmp(a, b, n);
4399a747e4fSDavid du Colombier }
4409a747e4fSDavid du Colombier 
4419a747e4fSDavid du Colombier DName*
drawlookupname(int n,char * str)4429a747e4fSDavid du Colombier drawlookupname(int n, char *str)
4439a747e4fSDavid du Colombier {
4449a747e4fSDavid du Colombier 	DName *name, *ename;
4459a747e4fSDavid du Colombier 
4469a747e4fSDavid du Colombier 	name = sdraw.name;
4479a747e4fSDavid du Colombier 	ename = &name[sdraw.nname];
4489a747e4fSDavid du Colombier 	for(; name<ename; name++)
4499a747e4fSDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
4509a747e4fSDavid du Colombier 			return name;
4519a747e4fSDavid du Colombier 	return 0;
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier int
drawgoodname(DImage * d)4559a747e4fSDavid du Colombier drawgoodname(DImage *d)
4569a747e4fSDavid du Colombier {
4579a747e4fSDavid du Colombier 	DName *n;
4589a747e4fSDavid du Colombier 
4599a747e4fSDavid du Colombier 	/* if window, validate the screen's own images */
4609a747e4fSDavid du Colombier 	if(d->dscreen)
4619a747e4fSDavid du Colombier 		if(drawgoodname(d->dscreen->dimage) == 0
4629a747e4fSDavid du Colombier 		|| drawgoodname(d->dscreen->dfill) == 0)
4639a747e4fSDavid du Colombier 			return 0;
4649a747e4fSDavid du Colombier 	if(d->name == nil)
4659a747e4fSDavid du Colombier 		return 1;
4669a747e4fSDavid du Colombier 	n = drawlookupname(strlen(d->name), d->name);
4679a747e4fSDavid du Colombier 	if(n==nil || n->vers!=d->vers)
4689a747e4fSDavid du Colombier 		return 0;
4699a747e4fSDavid du Colombier 	return 1;
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier 
4729a747e4fSDavid du Colombier DImage*
drawlookup(Client * client,int id,int checkname)4739a747e4fSDavid du Colombier drawlookup(Client *client, int id, int checkname)
4749a747e4fSDavid du Colombier {
4759a747e4fSDavid du Colombier 	DImage *d;
4769a747e4fSDavid du Colombier 
4779a747e4fSDavid du Colombier 	d = client->dimage[id&HASHMASK];
4789a747e4fSDavid du Colombier 	while(d){
4799a747e4fSDavid du Colombier 		if(d->id == id){
4809a747e4fSDavid du Colombier 			if(checkname && !drawgoodname(d))
4819a747e4fSDavid du Colombier 				error(Eoldname);
4829a747e4fSDavid du Colombier 			return d;
4839a747e4fSDavid du Colombier 		}
4849a747e4fSDavid du Colombier 		d = d->next;
4859a747e4fSDavid du Colombier 	}
4869a747e4fSDavid du Colombier 	return 0;
4879a747e4fSDavid du Colombier }
4889a747e4fSDavid du Colombier 
4899a747e4fSDavid du Colombier DScreen*
drawlookupdscreen(int id)4909a747e4fSDavid du Colombier drawlookupdscreen(int id)
4919a747e4fSDavid du Colombier {
4929a747e4fSDavid du Colombier 	DScreen *s;
4939a747e4fSDavid du Colombier 
4949a747e4fSDavid du Colombier 	s = dscreen;
4959a747e4fSDavid du Colombier 	while(s){
4969a747e4fSDavid du Colombier 		if(s->id == id)
4979a747e4fSDavid du Colombier 			return s;
4989a747e4fSDavid du Colombier 		s = s->next;
4999a747e4fSDavid du Colombier 	}
5009a747e4fSDavid du Colombier 	return 0;
5019a747e4fSDavid du Colombier }
5029a747e4fSDavid du Colombier 
5039a747e4fSDavid du Colombier DScreen*
drawlookupscreen(Client * client,int id,CScreen ** cs)5049a747e4fSDavid du Colombier drawlookupscreen(Client *client, int id, CScreen **cs)
5059a747e4fSDavid du Colombier {
5069a747e4fSDavid du Colombier 	CScreen *s;
5079a747e4fSDavid du Colombier 
5089a747e4fSDavid du Colombier 	s = client->cscreen;
5099a747e4fSDavid du Colombier 	while(s){
5109a747e4fSDavid du Colombier 		if(s->dscreen->id == id){
5119a747e4fSDavid du Colombier 			*cs = s;
5129a747e4fSDavid du Colombier 			return s->dscreen;
5139a747e4fSDavid du Colombier 		}
5149a747e4fSDavid du Colombier 		s = s->next;
5159a747e4fSDavid du Colombier 	}
5169a747e4fSDavid du Colombier 	error(Enodrawscreen);
5179a747e4fSDavid du Colombier 	return 0;
5189a747e4fSDavid du Colombier }
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier Memimage*
drawinstall(Client * client,int id,Memimage * i,DScreen * dscreen)5219a747e4fSDavid du Colombier drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
5229a747e4fSDavid du Colombier {
5239a747e4fSDavid du Colombier 	DImage *d;
5249a747e4fSDavid du Colombier 
5259a747e4fSDavid du Colombier 	d = malloc(sizeof(DImage));
5269a747e4fSDavid du Colombier 	if(d == 0)
5279a747e4fSDavid du Colombier 		return 0;
5289a747e4fSDavid du Colombier 	d->id = id;
5299a747e4fSDavid du Colombier 	d->ref = 1;
5309a747e4fSDavid du Colombier 	d->name = 0;
5319a747e4fSDavid du Colombier 	d->vers = 0;
5329a747e4fSDavid du Colombier 	d->image = i;
5339a747e4fSDavid du Colombier 	d->nfchar = 0;
5349a747e4fSDavid du Colombier 	d->fchar = 0;
5359a747e4fSDavid du Colombier 	d->fromname = 0;
5369a747e4fSDavid du Colombier 	d->dscreen = dscreen;
5379a747e4fSDavid du Colombier 	d->next = client->dimage[id&HASHMASK];
5389a747e4fSDavid du Colombier 	client->dimage[id&HASHMASK] = d;
5399a747e4fSDavid du Colombier 	return i;
5409a747e4fSDavid du Colombier }
5419a747e4fSDavid du Colombier 
5429a747e4fSDavid du Colombier Memscreen*
drawinstallscreen(Client * client,DScreen * d,int id,DImage * dimage,DImage * dfill,int public)5439a747e4fSDavid du Colombier drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
5449a747e4fSDavid du Colombier {
5459a747e4fSDavid du Colombier 	Memscreen *s;
5469a747e4fSDavid du Colombier 	CScreen *c;
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	c = malloc(sizeof(CScreen));
5499a747e4fSDavid du Colombier 	if(dimage && dimage->image && dimage->image->chan == 0)
5509a747e4fSDavid du Colombier 		panic("bad image %p in drawinstallscreen", dimage->image);
5519a747e4fSDavid du Colombier 
5529a747e4fSDavid du Colombier 	if(c == 0)
5539a747e4fSDavid du Colombier 		return 0;
5549a747e4fSDavid du Colombier 	if(d == 0){
5559a747e4fSDavid du Colombier 		d = malloc(sizeof(DScreen));
5569a747e4fSDavid du Colombier 		if(d == 0){
5579a747e4fSDavid du Colombier 			free(c);
5589a747e4fSDavid du Colombier 			return 0;
5599a747e4fSDavid du Colombier 		}
5609a747e4fSDavid du Colombier 		s = malloc(sizeof(Memscreen));
5619a747e4fSDavid du Colombier 		if(s == 0){
5629a747e4fSDavid du Colombier 			free(c);
5639a747e4fSDavid du Colombier 			free(d);
5649a747e4fSDavid du Colombier 			return 0;
5659a747e4fSDavid du Colombier 		}
5669a747e4fSDavid du Colombier 		s->frontmost = 0;
5679a747e4fSDavid du Colombier 		s->rearmost = 0;
5689a747e4fSDavid du Colombier 		d->dimage = dimage;
5699a747e4fSDavid du Colombier 		if(dimage){
5709a747e4fSDavid du Colombier 			s->image = dimage->image;
5719a747e4fSDavid du Colombier 			dimage->ref++;
5729a747e4fSDavid du Colombier 		}
5739a747e4fSDavid du Colombier 		d->dfill = dfill;
5749a747e4fSDavid du Colombier 		if(dfill){
5759a747e4fSDavid du Colombier 			s->fill = dfill->image;
5769a747e4fSDavid du Colombier 			dfill->ref++;
5779a747e4fSDavid du Colombier 		}
5789a747e4fSDavid du Colombier 		d->ref = 0;
5799a747e4fSDavid du Colombier 		d->id = id;
5809a747e4fSDavid du Colombier 		d->screen = s;
5819a747e4fSDavid du Colombier 		d->public = public;
5829a747e4fSDavid du Colombier 		d->next = dscreen;
5839a747e4fSDavid du Colombier 		d->owner = client;
5849a747e4fSDavid du Colombier 		dscreen = d;
5859a747e4fSDavid du Colombier 	}
5869a747e4fSDavid du Colombier 	c->dscreen = d;
5879a747e4fSDavid du Colombier 	d->ref++;
5889a747e4fSDavid du Colombier 	c->next = client->cscreen;
5899a747e4fSDavid du Colombier 	client->cscreen = c;
5909a747e4fSDavid du Colombier 	return d->screen;
5919a747e4fSDavid du Colombier }
5929a747e4fSDavid du Colombier 
5939a747e4fSDavid du Colombier void
drawdelname(DName * name)5949a747e4fSDavid du Colombier drawdelname(DName *name)
5959a747e4fSDavid du Colombier {
5969a747e4fSDavid du Colombier 	int i;
5979a747e4fSDavid du Colombier 
5989a747e4fSDavid du Colombier 	i = name-sdraw.name;
5999a747e4fSDavid du Colombier 	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
6009a747e4fSDavid du Colombier 	sdraw.nname--;
6019a747e4fSDavid du Colombier }
6029a747e4fSDavid du Colombier 
6039a747e4fSDavid du Colombier void
drawfreedscreen(DScreen * this)6049a747e4fSDavid du Colombier drawfreedscreen(DScreen *this)
6059a747e4fSDavid du Colombier {
6069a747e4fSDavid du Colombier 	DScreen *ds, *next;
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier 	this->ref--;
6099a747e4fSDavid du Colombier 	if(this->ref < 0)
6109a747e4fSDavid du Colombier 		print("negative ref in drawfreedscreen\n");
6119a747e4fSDavid du Colombier 	if(this->ref > 0)
6129a747e4fSDavid du Colombier 		return;
6139a747e4fSDavid du Colombier 	ds = dscreen;
6149a747e4fSDavid du Colombier 	if(ds == this){
6159a747e4fSDavid du Colombier 		dscreen = this->next;
6169a747e4fSDavid du Colombier 		goto Found;
6179a747e4fSDavid du Colombier 	}
6189a747e4fSDavid du Colombier 	while(next = ds->next){	/* assign = */
6199a747e4fSDavid du Colombier 		if(next == this){
6209a747e4fSDavid du Colombier 			ds->next = this->next;
6219a747e4fSDavid du Colombier 			goto Found;
6229a747e4fSDavid du Colombier 		}
6239a747e4fSDavid du Colombier 		ds = next;
6249a747e4fSDavid du Colombier 	}
6259a747e4fSDavid du Colombier 	error(Enodrawimage);
6269a747e4fSDavid du Colombier 
6279a747e4fSDavid du Colombier     Found:
6289a747e4fSDavid du Colombier 	if(this->dimage)
6299a747e4fSDavid du Colombier 		drawfreedimage(this->dimage);
6309a747e4fSDavid du Colombier 	if(this->dfill)
6319a747e4fSDavid du Colombier 		drawfreedimage(this->dfill);
6329a747e4fSDavid du Colombier 	free(this->screen);
6339a747e4fSDavid du Colombier 	free(this);
6349a747e4fSDavid du Colombier }
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier void
drawfreedimage(DImage * dimage)6379a747e4fSDavid du Colombier drawfreedimage(DImage *dimage)
6389a747e4fSDavid du Colombier {
6399a747e4fSDavid du Colombier 	int i;
6409a747e4fSDavid du Colombier 	Memimage *l;
6419a747e4fSDavid du Colombier 	DScreen *ds;
6429a747e4fSDavid du Colombier 
6439a747e4fSDavid du Colombier 	dimage->ref--;
6449a747e4fSDavid du Colombier 	if(dimage->ref < 0)
6459a747e4fSDavid du Colombier 		print("negative ref in drawfreedimage\n");
6469a747e4fSDavid du Colombier 	if(dimage->ref > 0)
6479a747e4fSDavid du Colombier 		return;
6489a747e4fSDavid du Colombier 
6499a747e4fSDavid du Colombier 	/* any names? */
6509a747e4fSDavid du Colombier 	for(i=0; i<sdraw.nname; )
6519a747e4fSDavid du Colombier 		if(sdraw.name[i].dimage == dimage)
6529a747e4fSDavid du Colombier 			drawdelname(sdraw.name+i);
6539a747e4fSDavid du Colombier 		else
6549a747e4fSDavid du Colombier 			i++;
6559a747e4fSDavid du Colombier 	if(dimage->fromname){	/* acquired by name; owned by someone else*/
6569a747e4fSDavid du Colombier 		drawfreedimage(dimage->fromname);
6579a747e4fSDavid du Colombier 		goto Return;
6589a747e4fSDavid du Colombier 	}
6599a747e4fSDavid du Colombier 	if(dimage->image == screenimage)	/* don't free the display */
6609a747e4fSDavid du Colombier 		goto Return;
6619a747e4fSDavid du Colombier 	ds = dimage->dscreen;
6629a747e4fSDavid du Colombier 	if(ds){
6639a747e4fSDavid du Colombier 		l = dimage->image;
6649a747e4fSDavid du Colombier 		if(l->data == screenimage->data)
6659a747e4fSDavid du Colombier 			addflush(l->layer->screenr);
6669a747e4fSDavid du Colombier 		if(l->layer->refreshfn == drawrefresh)	/* else true owner will clean up */
6679a747e4fSDavid du Colombier 			free(l->layer->refreshptr);
6689a747e4fSDavid du Colombier 		l->layer->refreshptr = nil;
6699a747e4fSDavid du Colombier 		if(drawgoodname(dimage))
6709a747e4fSDavid du Colombier 			memldelete(l);
6719a747e4fSDavid du Colombier 		else
6729a747e4fSDavid du Colombier 			memlfree(l);
6739a747e4fSDavid du Colombier 		drawfreedscreen(ds);
6749a747e4fSDavid du Colombier 	}else
6759a747e4fSDavid du Colombier 		freememimage(dimage->image);
6769a747e4fSDavid du Colombier     Return:
6779a747e4fSDavid du Colombier 	free(dimage->fchar);
6789a747e4fSDavid du Colombier 	free(dimage);
6799a747e4fSDavid du Colombier }
6809a747e4fSDavid du Colombier 
6819a747e4fSDavid du Colombier void
drawuninstallscreen(Client * client,CScreen * this)6829a747e4fSDavid du Colombier drawuninstallscreen(Client *client, CScreen *this)
6839a747e4fSDavid du Colombier {
6849a747e4fSDavid du Colombier 	CScreen *cs, *next;
6859a747e4fSDavid du Colombier 
6869a747e4fSDavid du Colombier 	cs = client->cscreen;
6879a747e4fSDavid du Colombier 	if(cs == this){
6889a747e4fSDavid du Colombier 		client->cscreen = this->next;
6899a747e4fSDavid du Colombier 		drawfreedscreen(this->dscreen);
6909a747e4fSDavid du Colombier 		free(this);
6919a747e4fSDavid du Colombier 		return;
6929a747e4fSDavid du Colombier 	}
6939a747e4fSDavid du Colombier 	while(next = cs->next){	/* assign = */
6949a747e4fSDavid du Colombier 		if(next == this){
6959a747e4fSDavid du Colombier 			cs->next = this->next;
6969a747e4fSDavid du Colombier 			drawfreedscreen(this->dscreen);
6979a747e4fSDavid du Colombier 			free(this);
6989a747e4fSDavid du Colombier 			return;
6999a747e4fSDavid du Colombier 		}
7009a747e4fSDavid du Colombier 		cs = next;
7019a747e4fSDavid du Colombier 	}
7029a747e4fSDavid du Colombier }
7039a747e4fSDavid du Colombier 
7049a747e4fSDavid du Colombier void
drawuninstall(Client * client,int id)7059a747e4fSDavid du Colombier drawuninstall(Client *client, int id)
7069a747e4fSDavid du Colombier {
7079a747e4fSDavid du Colombier 	DImage *d, *next;
7089a747e4fSDavid du Colombier 
7099a747e4fSDavid du Colombier 	d = client->dimage[id&HASHMASK];
7109a747e4fSDavid du Colombier 	if(d == 0)
7119a747e4fSDavid du Colombier 		error(Enodrawimage);
7129a747e4fSDavid du Colombier 	if(d->id == id){
7139a747e4fSDavid du Colombier 		client->dimage[id&HASHMASK] = d->next;
7149a747e4fSDavid du Colombier 		drawfreedimage(d);
7159a747e4fSDavid du Colombier 		return;
7169a747e4fSDavid du Colombier 	}
7179a747e4fSDavid du Colombier 	while(next = d->next){	/* assign = */
7189a747e4fSDavid du Colombier 		if(next->id == id){
7199a747e4fSDavid du Colombier 			d->next = next->next;
7209a747e4fSDavid du Colombier 			drawfreedimage(next);
7219a747e4fSDavid du Colombier 			return;
7229a747e4fSDavid du Colombier 		}
7239a747e4fSDavid du Colombier 		d = next;
7249a747e4fSDavid du Colombier 	}
7259a747e4fSDavid du Colombier 	error(Enodrawimage);
7269a747e4fSDavid du Colombier }
7279a747e4fSDavid du Colombier 
7289a747e4fSDavid du Colombier void
drawaddname(Client * client,DImage * di,int n,char * str)7299a747e4fSDavid du Colombier drawaddname(Client *client, DImage *di, int n, char *str)
7309a747e4fSDavid du Colombier {
7319a747e4fSDavid du Colombier 	DName *name, *ename, *new, *t;
7329a747e4fSDavid du Colombier 
7339a747e4fSDavid du Colombier 	name = sdraw.name;
7349a747e4fSDavid du Colombier 	ename = &name[sdraw.nname];
7359a747e4fSDavid du Colombier 	for(; name<ename; name++)
7369a747e4fSDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
7379a747e4fSDavid du Colombier 			error(Enameused);
7389a747e4fSDavid du Colombier 	t = smalloc((sdraw.nname+1)*sizeof(DName));
7399a747e4fSDavid du Colombier 	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
7409a747e4fSDavid du Colombier 	free(sdraw.name);
7419a747e4fSDavid du Colombier 	sdraw.name = t;
7429a747e4fSDavid du Colombier 	new = &sdraw.name[sdraw.nname++];
7439a747e4fSDavid du Colombier 	new->name = smalloc(n+1);
7449a747e4fSDavid du Colombier 	memmove(new->name, str, n);
7459a747e4fSDavid du Colombier 	new->name[n] = 0;
7469a747e4fSDavid du Colombier 	new->dimage = di;
7479a747e4fSDavid du Colombier 	new->client = client;
7489a747e4fSDavid du Colombier 	new->vers = ++sdraw.vers;
7499a747e4fSDavid du Colombier }
7509a747e4fSDavid du Colombier 
7519a747e4fSDavid du Colombier Client*
drawnewclient(void)7529a747e4fSDavid du Colombier drawnewclient(void)
7539a747e4fSDavid du Colombier {
7549a747e4fSDavid du Colombier 	Client *cl, **cp;
7559a747e4fSDavid du Colombier 	int i;
7569a747e4fSDavid du Colombier 
7579a747e4fSDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
7589a747e4fSDavid du Colombier 		cl = sdraw.client[i];
7599a747e4fSDavid du Colombier 		if(cl == 0)
7609a747e4fSDavid du Colombier 			break;
7619a747e4fSDavid du Colombier 	}
7629a747e4fSDavid du Colombier 	if(i == sdraw.nclient){
7639a747e4fSDavid du Colombier 		cp = malloc((sdraw.nclient+1)*sizeof(Client*));
7649a747e4fSDavid du Colombier 		if(cp == 0)
7659a747e4fSDavid du Colombier 			return 0;
7669a747e4fSDavid du Colombier 		memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
7679a747e4fSDavid du Colombier 		free(sdraw.client);
7689a747e4fSDavid du Colombier 		sdraw.client = cp;
7699a747e4fSDavid du Colombier 		sdraw.nclient++;
7709a747e4fSDavid du Colombier 		cp[i] = 0;
7719a747e4fSDavid du Colombier 	}
7729a747e4fSDavid du Colombier 	cl = malloc(sizeof(Client));
7739a747e4fSDavid du Colombier 	if(cl == 0)
7749a747e4fSDavid du Colombier 		return 0;
7759a747e4fSDavid du Colombier 	memset(cl, 0, sizeof(Client));
7769a747e4fSDavid du Colombier 	cl->slot = i;
7779a747e4fSDavid du Colombier 	cl->clientid = ++sdraw.clientid;
7786a9fc400SDavid du Colombier 	cl->op = SoverD;
7799a747e4fSDavid du Colombier 	sdraw.client[i] = cl;
7809a747e4fSDavid du Colombier 	return cl;
7819a747e4fSDavid du Colombier }
7829a747e4fSDavid du Colombier 
7836a9fc400SDavid du Colombier static int
drawclientop(Client * cl)7846a9fc400SDavid du Colombier drawclientop(Client *cl)
7856a9fc400SDavid du Colombier {
7866a9fc400SDavid du Colombier 	int op;
7876a9fc400SDavid du Colombier 
7886a9fc400SDavid du Colombier 	op = cl->op;
7896a9fc400SDavid du Colombier 	cl->op = SoverD;
7906a9fc400SDavid du Colombier 	return op;
7916a9fc400SDavid du Colombier }
7926a9fc400SDavid du Colombier 
7939a747e4fSDavid du Colombier int
drawhasclients(void)7949a747e4fSDavid du Colombier drawhasclients(void)
7959a747e4fSDavid du Colombier {
7969a747e4fSDavid du Colombier 	/*
7979a747e4fSDavid du Colombier 	 * if draw has ever been used, we can't resize the frame buffer,
7989a747e4fSDavid du Colombier 	 * even if all clients have exited (nclients is cumulative); it's too
7999a747e4fSDavid du Colombier 	 * hard to make work.
8009a747e4fSDavid du Colombier 	 */
8019a747e4fSDavid du Colombier 	return sdraw.nclient != 0;
8029a747e4fSDavid du Colombier }
8039a747e4fSDavid du Colombier 
8049a747e4fSDavid du Colombier Client*
drawclientofpath(ulong path)8059a747e4fSDavid du Colombier drawclientofpath(ulong path)
8069a747e4fSDavid du Colombier {
8079a747e4fSDavid du Colombier 	Client *cl;
8089a747e4fSDavid du Colombier 	int slot;
8099a747e4fSDavid du Colombier 
8109a747e4fSDavid du Colombier 	slot = CLIENTPATH(path);
8119a747e4fSDavid du Colombier 	if(slot == 0)
8129a747e4fSDavid du Colombier 		return nil;
8139a747e4fSDavid du Colombier 	cl = sdraw.client[slot-1];
8149a747e4fSDavid du Colombier 	if(cl==0 || cl->clientid==0)
8159a747e4fSDavid du Colombier 		return nil;
8169a747e4fSDavid du Colombier 	return cl;
8179a747e4fSDavid du Colombier }
8189a747e4fSDavid du Colombier 
8199a747e4fSDavid du Colombier 
8209a747e4fSDavid du Colombier Client*
drawclient(Chan * c)8219a747e4fSDavid du Colombier drawclient(Chan *c)
8229a747e4fSDavid du Colombier {
8239a747e4fSDavid du Colombier 	Client *client;
8249a747e4fSDavid du Colombier 
8259a747e4fSDavid du Colombier 	client = drawclientofpath(c->qid.path);
8269a747e4fSDavid du Colombier 	if(client == nil)
8279a747e4fSDavid du Colombier 		error(Enoclient);
8289a747e4fSDavid du Colombier 	return client;
8299a747e4fSDavid du Colombier }
8309a747e4fSDavid du Colombier 
8319a747e4fSDavid du Colombier Memimage*
drawimage(Client * client,uchar * a)8329a747e4fSDavid du Colombier drawimage(Client *client, uchar *a)
8339a747e4fSDavid du Colombier {
8349a747e4fSDavid du Colombier 	DImage *d;
8359a747e4fSDavid du Colombier 
8369a747e4fSDavid du Colombier 	d = drawlookup(client, BGLONG(a), 1);
8379a747e4fSDavid du Colombier 	if(d == nil)
8389a747e4fSDavid du Colombier 		error(Enodrawimage);
8399a747e4fSDavid du Colombier 	return d->image;
8409a747e4fSDavid du Colombier }
8419a747e4fSDavid du Colombier 
8429a747e4fSDavid du Colombier void
drawrectangle(Rectangle * r,uchar * a)8439a747e4fSDavid du Colombier drawrectangle(Rectangle *r, uchar *a)
8449a747e4fSDavid du Colombier {
8459a747e4fSDavid du Colombier 	r->min.x = BGLONG(a+0*4);
8469a747e4fSDavid du Colombier 	r->min.y = BGLONG(a+1*4);
8479a747e4fSDavid du Colombier 	r->max.x = BGLONG(a+2*4);
8489a747e4fSDavid du Colombier 	r->max.y = BGLONG(a+3*4);
8499a747e4fSDavid du Colombier }
8509a747e4fSDavid du Colombier 
8519a747e4fSDavid du Colombier void
drawpoint(Point * p,uchar * a)8529a747e4fSDavid du Colombier drawpoint(Point *p, uchar *a)
8539a747e4fSDavid du Colombier {
8549a747e4fSDavid du Colombier 	p->x = BGLONG(a+0*4);
8559a747e4fSDavid du Colombier 	p->y = BGLONG(a+1*4);
8569a747e4fSDavid du Colombier }
8579a747e4fSDavid du Colombier 
8589a747e4fSDavid du Colombier Point
drawchar(Memimage * dst,Point p,Memimage * src,Point * sp,DImage * font,int index,int op)8596a9fc400SDavid du Colombier drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
8609a747e4fSDavid du Colombier {
8619a747e4fSDavid du Colombier 	FChar *fc;
8629a747e4fSDavid du Colombier 	Rectangle r;
8639a747e4fSDavid du Colombier 	Point sp1;
8649a747e4fSDavid du Colombier 
8659a747e4fSDavid du Colombier 	fc = &font->fchar[index];
8669a747e4fSDavid du Colombier 	r.min.x = p.x+fc->left;
8679a747e4fSDavid du Colombier 	r.min.y = p.y-(font->ascent-fc->miny);
8689a747e4fSDavid du Colombier 	r.max.x = r.min.x+(fc->maxx-fc->minx);
8699a747e4fSDavid du Colombier 	r.max.y = r.min.y+(fc->maxy-fc->miny);
8709a747e4fSDavid du Colombier 	sp1.x = sp->x+fc->left;
8719a747e4fSDavid du Colombier 	sp1.y = sp->y+fc->miny;
8726a9fc400SDavid du Colombier 	memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
8739a747e4fSDavid du Colombier 	p.x += fc->width;
8749a747e4fSDavid du Colombier 	sp->x += fc->width;
8759a747e4fSDavid du Colombier 	return p;
8769a747e4fSDavid du Colombier }
8779a747e4fSDavid du Colombier 
8789a747e4fSDavid du Colombier static int
initscreenimage(void)8799a747e4fSDavid du Colombier initscreenimage(void)
8809a747e4fSDavid du Colombier {
8819a747e4fSDavid du Colombier 	int width, depth;
8829a747e4fSDavid du Colombier 	ulong chan;
8839a747e4fSDavid du Colombier 	Rectangle r;
8849a747e4fSDavid du Colombier 
8859a747e4fSDavid du Colombier 	if(screenimage != nil)
8869a747e4fSDavid du Colombier 		return 1;
8879a747e4fSDavid du Colombier 
8889a747e4fSDavid du Colombier 	screendata.base = nil;
8899a747e4fSDavid du Colombier 	screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen);
8909a747e4fSDavid du Colombier 	if(screendata.bdata == nil)
8919a747e4fSDavid du Colombier {fprint(2, "bad bdata\n");
8929a747e4fSDavid du Colombier 		return 0;
8939a747e4fSDavid du Colombier }
8949a747e4fSDavid du Colombier 	screendata.ref = 1;
8959a747e4fSDavid du Colombier 
8969a747e4fSDavid du Colombier 	screenimage = allocmemimaged(r, chan, &screendata);
8979a747e4fSDavid du Colombier 	if(screenimage == nil){
8989a747e4fSDavid du Colombier fprint(2, "bad memimaged: %r\n");
8999a747e4fSDavid du Colombier 		/* RSC: BUG: detach screen */
9009a747e4fSDavid du Colombier 		return 0;
9019a747e4fSDavid du Colombier 	}
9029a747e4fSDavid du Colombier 
9039a747e4fSDavid du Colombier 	screenimage->width = width;
9049a747e4fSDavid du Colombier 	screenimage->clipr  = screenimage->r;
9059a747e4fSDavid du Colombier 	return 1;
9069a747e4fSDavid du Colombier }
9079a747e4fSDavid du Colombier 
9089a747e4fSDavid du Colombier void
deletescreenimage(void)9099a747e4fSDavid du Colombier deletescreenimage(void)
9109a747e4fSDavid du Colombier {
9119a747e4fSDavid du Colombier 	qlock(&sdraw);
9129a747e4fSDavid du Colombier 	/* RSC: BUG: detach screen */
9139a747e4fSDavid du Colombier 	if(screenimage)
9149a747e4fSDavid du Colombier 		freememimage(screenimage);
9159a747e4fSDavid du Colombier 	screenimage = nil;
9169a747e4fSDavid du Colombier 	qunlock(&sdraw);
9179a747e4fSDavid du Colombier }
9189a747e4fSDavid du Colombier 
9199a747e4fSDavid du Colombier Chan*
drawattach(char * spec)9209a747e4fSDavid du Colombier drawattach(char *spec)
9219a747e4fSDavid du Colombier {
9229a747e4fSDavid du Colombier 	qlock(&sdraw);
9239a747e4fSDavid du Colombier 	if(!initscreenimage()){
9249a747e4fSDavid du Colombier 		qunlock(&sdraw);
9259a747e4fSDavid du Colombier 		error("no frame buffer");
9269a747e4fSDavid du Colombier 	}
9279a747e4fSDavid du Colombier 	qunlock(&sdraw);
9289a747e4fSDavid du Colombier 	return devattach('i', spec);
9299a747e4fSDavid du Colombier }
9309a747e4fSDavid du Colombier 
9319a747e4fSDavid du Colombier Walkqid*
drawwalk(Chan * c,Chan * nc,char ** name,int nname)9329a747e4fSDavid du Colombier drawwalk(Chan *c, Chan *nc, char **name, int nname)
9339a747e4fSDavid du Colombier {
9349a747e4fSDavid du Colombier 	if(screendata.bdata == nil)
9359a747e4fSDavid du Colombier 		error("no frame buffer");
9369a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, drawgen);
9379a747e4fSDavid du Colombier }
9389a747e4fSDavid du Colombier 
9399a747e4fSDavid du Colombier static int
drawstat(Chan * c,uchar * db,int n)9409a747e4fSDavid du Colombier drawstat(Chan *c, uchar *db, int n)
9419a747e4fSDavid du Colombier {
9429a747e4fSDavid du Colombier 	return devstat(c, db, n, 0, 0, drawgen);
9439a747e4fSDavid du Colombier }
9449a747e4fSDavid du Colombier 
9459a747e4fSDavid du Colombier static Chan*
drawopen(Chan * c,int omode)9469a747e4fSDavid du Colombier drawopen(Chan *c, int omode)
9479a747e4fSDavid du Colombier {
9489a747e4fSDavid du Colombier 	Client *cl;
9499a747e4fSDavid du Colombier 
9509a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
9519a747e4fSDavid du Colombier 		return devopen(c, omode, 0, 0, drawgen);
9529a747e4fSDavid du Colombier 
9539a747e4fSDavid du Colombier 	qlock(&sdraw);
9549a747e4fSDavid du Colombier 	if(waserror()){
9559a747e4fSDavid du Colombier 		qunlock(&sdraw);
9569a747e4fSDavid du Colombier 		nexterror();
9579a747e4fSDavid du Colombier 	}
9589a747e4fSDavid du Colombier 
9599a747e4fSDavid du Colombier 	if(QID(c->qid) == Qnew){
9609a747e4fSDavid du Colombier 		cl = drawnewclient();
9619a747e4fSDavid du Colombier 		if(cl == 0)
9629a747e4fSDavid du Colombier 			error(Enodev);
9639a747e4fSDavid du Colombier 		c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
9649a747e4fSDavid du Colombier 	}
9659a747e4fSDavid du Colombier 
9669a747e4fSDavid du Colombier 	switch(QID(c->qid)){
9679a747e4fSDavid du Colombier 	case Qnew:
9689a747e4fSDavid du Colombier 		break;
9699a747e4fSDavid du Colombier 
9709a747e4fSDavid du Colombier 	case Qctl:
9719a747e4fSDavid du Colombier 		cl = drawclient(c);
9729a747e4fSDavid du Colombier 		if(cl->busy)
9739a747e4fSDavid du Colombier 			error(Einuse);
9749a747e4fSDavid du Colombier 		cl->busy = 1;
9759a747e4fSDavid du Colombier 		flushrect = Rect(10000, 10000, -10000, -10000);
9769a747e4fSDavid du Colombier 		drawinstall(cl, 0, screenimage, 0);
9779a747e4fSDavid du Colombier 		incref(&cl->r);
9789a747e4fSDavid du Colombier 		break;
9799a747e4fSDavid du Colombier 	case Qcolormap:
9809a747e4fSDavid du Colombier 	case Qdata:
9819a747e4fSDavid du Colombier 	case Qrefresh:
9829a747e4fSDavid du Colombier 		cl = drawclient(c);
9839a747e4fSDavid du Colombier 		incref(&cl->r);
9849a747e4fSDavid du Colombier 		break;
9859a747e4fSDavid du Colombier 	}
9869a747e4fSDavid du Colombier 	qunlock(&sdraw);
9879a747e4fSDavid du Colombier 	poperror();
9889a747e4fSDavid du Colombier 	c->mode = openmode(omode);
9899a747e4fSDavid du Colombier 	c->flag |= COPEN;
9909a747e4fSDavid du Colombier 	c->offset = 0;
9919a747e4fSDavid du Colombier 	return c;
9929a747e4fSDavid du Colombier }
9939a747e4fSDavid du Colombier 
9949a747e4fSDavid du Colombier static void
drawclose(Chan * c)9959a747e4fSDavid du Colombier drawclose(Chan *c)
9969a747e4fSDavid du Colombier {
9979a747e4fSDavid du Colombier 	int i;
9989a747e4fSDavid du Colombier 	DImage *d, **dp;
9999a747e4fSDavid du Colombier 	Client *cl;
10009a747e4fSDavid du Colombier 	Refresh *r;
10019a747e4fSDavid du Colombier 
10029a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
10039a747e4fSDavid du Colombier 		return;
10049a747e4fSDavid du Colombier 	qlock(&sdraw);
10059a747e4fSDavid du Colombier 	if(waserror()){
10069a747e4fSDavid du Colombier 		qunlock(&sdraw);
10079a747e4fSDavid du Colombier 		nexterror();
10089a747e4fSDavid du Colombier 	}
10099a747e4fSDavid du Colombier 
10109a747e4fSDavid du Colombier 	cl = drawclient(c);
10119a747e4fSDavid du Colombier 	if(QID(c->qid) == Qctl)
10129a747e4fSDavid du Colombier 		cl->busy = 0;
10139a747e4fSDavid du Colombier 	if((c->flag&COPEN) && (decref(&cl->r)==0)){
10149a747e4fSDavid du Colombier 		while(r = cl->refresh){	/* assign = */
10159a747e4fSDavid du Colombier 			cl->refresh = r->next;
10169a747e4fSDavid du Colombier 			free(r);
10179a747e4fSDavid du Colombier 		}
10189a747e4fSDavid du Colombier 		/* free names */
10199a747e4fSDavid du Colombier 		for(i=0; i<sdraw.nname; )
10209a747e4fSDavid du Colombier 			if(sdraw.name[i].client == cl)
10219a747e4fSDavid du Colombier 				drawdelname(sdraw.name+i);
10229a747e4fSDavid du Colombier 			else
10239a747e4fSDavid du Colombier 				i++;
10249a747e4fSDavid du Colombier 		while(cl->cscreen)
10259a747e4fSDavid du Colombier 			drawuninstallscreen(cl, cl->cscreen);
10269a747e4fSDavid du Colombier 		/* all screens are freed, so now we can free images */
10279a747e4fSDavid du Colombier 		dp = cl->dimage;
10289a747e4fSDavid du Colombier 		for(i=0; i<NHASH; i++){
10299a747e4fSDavid du Colombier 			while((d = *dp) != nil){
10309a747e4fSDavid du Colombier 				*dp = d->next;
10319a747e4fSDavid du Colombier 				drawfreedimage(d);
10329a747e4fSDavid du Colombier 			}
10339a747e4fSDavid du Colombier 			dp++;
10349a747e4fSDavid du Colombier 		}
10359a747e4fSDavid du Colombier 		sdraw.client[cl->slot] = 0;
10369a747e4fSDavid du Colombier 		drawflush();	/* to erase visible, now dead windows */
10379a747e4fSDavid du Colombier 		free(cl);
10389a747e4fSDavid du Colombier 	}
10399a747e4fSDavid du Colombier 	qunlock(&sdraw);
10409a747e4fSDavid du Colombier 	poperror();
10419a747e4fSDavid du Colombier }
10429a747e4fSDavid du Colombier 
10439a747e4fSDavid du Colombier long
drawread(Chan * c,void * a,long n,vlong off)10449a747e4fSDavid du Colombier drawread(Chan *c, void *a, long n, vlong off)
10459a747e4fSDavid du Colombier {
10469a747e4fSDavid du Colombier 	int index, m;
10479a747e4fSDavid du Colombier 	ulong red, green, blue;
10489a747e4fSDavid du Colombier 	Client *cl;
10499a747e4fSDavid du Colombier 	uchar *p;
10509a747e4fSDavid du Colombier 	Refresh *r;
10519a747e4fSDavid du Colombier 	DImage *di;
10529a747e4fSDavid du Colombier 	Memimage *i;
10539a747e4fSDavid du Colombier 	ulong offset = off;
10549a747e4fSDavid du Colombier 	char buf[16];
10559a747e4fSDavid du Colombier 
10569a747e4fSDavid du Colombier 	USED(offset);
10579a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
10589a747e4fSDavid du Colombier 		return devdirread(c, a, n, 0, 0, drawgen);
10599a747e4fSDavid du Colombier 	cl = drawclient(c);
10609a747e4fSDavid du Colombier 	qlock(&sdraw);
10619a747e4fSDavid du Colombier 	if(waserror()){
10629a747e4fSDavid du Colombier 		qunlock(&sdraw);
10639a747e4fSDavid du Colombier 		nexterror();
10649a747e4fSDavid du Colombier 	}
10659a747e4fSDavid du Colombier 	switch(QID(c->qid)){
10669a747e4fSDavid du Colombier 	case Qctl:
10679a747e4fSDavid du Colombier 		if(n < 12*12)
10689a747e4fSDavid du Colombier 			error(Eshortread);
10699a747e4fSDavid du Colombier 		if(cl->infoid < 0)
10709a747e4fSDavid du Colombier 			error(Enodrawimage);
10719a747e4fSDavid du Colombier 		if(cl->infoid == 0){
10729a747e4fSDavid du Colombier 			i = screenimage;
10739a747e4fSDavid du Colombier 			if(i == nil)
10749a747e4fSDavid du Colombier 				error(Enodrawimage);
10759a747e4fSDavid du Colombier 		}else{
10769a747e4fSDavid du Colombier 			di = drawlookup(cl, cl->infoid, 1);
10779a747e4fSDavid du Colombier 			if(di == nil)
10789a747e4fSDavid du Colombier 				error(Enodrawimage);
10799a747e4fSDavid du Colombier 			i = di->image;
10809a747e4fSDavid du Colombier 		}
10819a747e4fSDavid du Colombier 		n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
10829a747e4fSDavid du Colombier 			cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
10839a747e4fSDavid du Colombier 			i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
10849a747e4fSDavid du Colombier 			i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
10859a747e4fSDavid du Colombier 		cl->infoid = -1;
10869a747e4fSDavid du Colombier 		break;
10879a747e4fSDavid du Colombier 
10889a747e4fSDavid du Colombier 	case Qcolormap:
10899a747e4fSDavid du Colombier 		drawactive(1);	/* to restore map from backup */
10909a747e4fSDavid du Colombier 		p = malloc(4*12*256+1);
10919a747e4fSDavid du Colombier 		if(p == 0)
10929a747e4fSDavid du Colombier 			error(Enomem);
10939a747e4fSDavid du Colombier 		m = 0;
10949a747e4fSDavid du Colombier 		for(index = 0; index < 256; index++){
10959a747e4fSDavid du Colombier 			getcolor(index, &red, &green, &blue);
10969a747e4fSDavid du Colombier 			m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
10979a747e4fSDavid du Colombier 		}
10989a747e4fSDavid du Colombier 		n = readstr(offset, a, n, (char*)p);
10999a747e4fSDavid du Colombier 		free(p);
11009a747e4fSDavid du Colombier 		break;
11019a747e4fSDavid du Colombier 
11029a747e4fSDavid du Colombier 	case Qdata:
11039a747e4fSDavid du Colombier 		if(cl->readdata == nil)
11049a747e4fSDavid du Colombier 			error("no draw data");
11059a747e4fSDavid du Colombier 		if(n < cl->nreaddata)
11069a747e4fSDavid du Colombier 			error(Eshortread);
11079a747e4fSDavid du Colombier 		n = cl->nreaddata;
11089a747e4fSDavid du Colombier 		memmove(a, cl->readdata, cl->nreaddata);
11099a747e4fSDavid du Colombier 		free(cl->readdata);
11109a747e4fSDavid du Colombier 		cl->readdata = nil;
11119a747e4fSDavid du Colombier 		break;
11129a747e4fSDavid du Colombier 
11139a747e4fSDavid du Colombier 	case Qrefresh:
11149a747e4fSDavid du Colombier 		if(n < 5*4)
11159a747e4fSDavid du Colombier 			error(Ebadarg);
11169a747e4fSDavid du Colombier 		for(;;){
11179a747e4fSDavid du Colombier 			if(cl->refreshme || cl->refresh)
11189a747e4fSDavid du Colombier 				break;
11199a747e4fSDavid du Colombier 			qunlock(&sdraw);
11209a747e4fSDavid du Colombier 			if(waserror()){
11219a747e4fSDavid du Colombier 				qlock(&sdraw);	/* restore lock for waserror() above */
11229a747e4fSDavid du Colombier 				nexterror();
11239a747e4fSDavid du Colombier 			}
11249a747e4fSDavid du Colombier 			rendsleep(&cl->refrend, drawrefactive, cl);
11259a747e4fSDavid du Colombier 			poperror();
11269a747e4fSDavid du Colombier 			qlock(&sdraw);
11279a747e4fSDavid du Colombier 		}
11289a747e4fSDavid du Colombier 		p = a;
11299a747e4fSDavid du Colombier 		while(cl->refresh && n>=5*4){
11309a747e4fSDavid du Colombier 			r = cl->refresh;
11319a747e4fSDavid du Colombier 			BPLONG(p+0*4, r->dimage->id);
11329a747e4fSDavid du Colombier 			BPLONG(p+1*4, r->r.min.x);
11339a747e4fSDavid du Colombier 			BPLONG(p+2*4, r->r.min.y);
11349a747e4fSDavid du Colombier 			BPLONG(p+3*4, r->r.max.x);
11359a747e4fSDavid du Colombier 			BPLONG(p+4*4, r->r.max.y);
11369a747e4fSDavid du Colombier 			cl->refresh = r->next;
11379a747e4fSDavid du Colombier 			free(r);
11389a747e4fSDavid du Colombier 			p += 5*4;
11399a747e4fSDavid du Colombier 			n -= 5*4;
11409a747e4fSDavid du Colombier 		}
11419a747e4fSDavid du Colombier 		cl->refreshme = 0;
11429a747e4fSDavid du Colombier 		n = p-(uchar*)a;
11439a747e4fSDavid du Colombier 	}
11449a747e4fSDavid du Colombier 	qunlock(&sdraw);
11459a747e4fSDavid du Colombier 	poperror();
11469a747e4fSDavid du Colombier 	return n;
11479a747e4fSDavid du Colombier }
11489a747e4fSDavid du Colombier 
11499a747e4fSDavid du Colombier void
drawwakeall(void)11509a747e4fSDavid du Colombier drawwakeall(void)
11519a747e4fSDavid du Colombier {
11529a747e4fSDavid du Colombier 	Client *cl;
11539a747e4fSDavid du Colombier 	int i;
11549a747e4fSDavid du Colombier 
11559a747e4fSDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
11569a747e4fSDavid du Colombier 		cl = sdraw.client[i];
11579a747e4fSDavid du Colombier 		if(cl && (cl->refreshme || cl->refresh))
11589a747e4fSDavid du Colombier 			rendwakeup(&cl->refrend);
11599a747e4fSDavid du Colombier 	}
11609a747e4fSDavid du Colombier }
11619a747e4fSDavid du Colombier 
11629a747e4fSDavid du Colombier static long
drawwrite(Chan * c,void * a,long n,vlong off)11639a747e4fSDavid du Colombier drawwrite(Chan *c, void *a, long n, vlong off)
11649a747e4fSDavid du Colombier {
11659a747e4fSDavid du Colombier 	char buf[128], *fields[4], *q;
11669a747e4fSDavid du Colombier 	Client *cl;
11679a747e4fSDavid du Colombier 	int i, m, red, green, blue, x;
11689a747e4fSDavid du Colombier 	ulong offset = off;
11699a747e4fSDavid du Colombier 
11709a747e4fSDavid du Colombier 	USED(offset);
11719a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
11729a747e4fSDavid du Colombier 		error(Eisdir);
11739a747e4fSDavid du Colombier 	cl = drawclient(c);
11749a747e4fSDavid du Colombier 	qlock(&sdraw);
11759a747e4fSDavid du Colombier 	if(waserror()){
11769a747e4fSDavid du Colombier 		drawwakeall();
11779a747e4fSDavid du Colombier 		qunlock(&sdraw);
11789a747e4fSDavid du Colombier 		nexterror();
11799a747e4fSDavid du Colombier 	}
11809a747e4fSDavid du Colombier 	switch(QID(c->qid)){
11819a747e4fSDavid du Colombier 	case Qctl:
11829a747e4fSDavid du Colombier 		if(n != 4)
11839a747e4fSDavid du Colombier 			error("unknown draw control request");
11849a747e4fSDavid du Colombier 		cl->infoid = BGLONG((uchar*)a);
11859a747e4fSDavid du Colombier 		break;
11869a747e4fSDavid du Colombier 
11879a747e4fSDavid du Colombier 	case Qcolormap:
11889a747e4fSDavid du Colombier 		drawactive(1);	/* to restore map from backup */
11899a747e4fSDavid du Colombier 		m = n;
11909a747e4fSDavid du Colombier 		n = 0;
11919a747e4fSDavid du Colombier 		while(m > 0){
11929a747e4fSDavid du Colombier 			x = m;
11939a747e4fSDavid du Colombier 			if(x > sizeof(buf)-1)
11949a747e4fSDavid du Colombier 				x = sizeof(buf)-1;
11959a747e4fSDavid du Colombier 			q = memccpy(buf, a, '\n', x);
11969a747e4fSDavid du Colombier 			if(q == 0)
11979a747e4fSDavid du Colombier 				break;
11989a747e4fSDavid du Colombier 			i = q-buf;
11999a747e4fSDavid du Colombier 			n += i;
12009a747e4fSDavid du Colombier 			a = (char*)a + i;
12019a747e4fSDavid du Colombier 			m -= i;
12029a747e4fSDavid du Colombier 			*q = 0;
12039a747e4fSDavid du Colombier 			if(getfields(buf, fields, nelem(fields), 1, " ") != 4)
12049a747e4fSDavid du Colombier 				error(Ebadarg);
12059a747e4fSDavid du Colombier 			i = strtoul(fields[0], 0, 0);
12069a747e4fSDavid du Colombier 			red = strtoul(fields[1], 0, 0);
12079a747e4fSDavid du Colombier 			green = strtoul(fields[2], 0, 0);
12089a747e4fSDavid du Colombier 			blue = strtoul(fields[3], &q, 0);
12099a747e4fSDavid du Colombier 			if(fields[3] == q)
12109a747e4fSDavid du Colombier 				error(Ebadarg);
12119a747e4fSDavid du Colombier 			if(red>255 || green>255 || blue>255 || i<0 || i>255)
12129a747e4fSDavid du Colombier 				error(Ebadarg);
12139a747e4fSDavid du Colombier 			red |= red<<8;
12149a747e4fSDavid du Colombier 			red |= red<<16;
12159a747e4fSDavid du Colombier 			green |= green<<8;
12169a747e4fSDavid du Colombier 			green |= green<<16;
12179a747e4fSDavid du Colombier 			blue |= blue<<8;
12189a747e4fSDavid du Colombier 			blue |= blue<<16;
12199a747e4fSDavid du Colombier 			setcolor(i, red, green, blue);
12209a747e4fSDavid du Colombier 		}
12219a747e4fSDavid du Colombier 		break;
12229a747e4fSDavid du Colombier 
12239a747e4fSDavid du Colombier 	case Qdata:
12249a747e4fSDavid du Colombier 		drawmesg(cl, a, n);
12259a747e4fSDavid du Colombier 		drawwakeall();
12269a747e4fSDavid du Colombier 		break;
12279a747e4fSDavid du Colombier 
12289a747e4fSDavid du Colombier 	default:
12299a747e4fSDavid du Colombier 		error(Ebadusefd);
12309a747e4fSDavid du Colombier 	}
12319a747e4fSDavid du Colombier 	qunlock(&sdraw);
12329a747e4fSDavid du Colombier 	poperror();
12339a747e4fSDavid du Colombier 	return n;
12349a747e4fSDavid du Colombier }
12359a747e4fSDavid du Colombier 
12369a747e4fSDavid du Colombier uchar*
drawcoord(uchar * p,uchar * maxp,int oldx,int * newx)12379a747e4fSDavid du Colombier drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
12389a747e4fSDavid du Colombier {
12399a747e4fSDavid du Colombier 	int b, x;
12409a747e4fSDavid du Colombier 
12419a747e4fSDavid du Colombier 	if(p >= maxp)
12429a747e4fSDavid du Colombier 		error(Eshortdraw);
12439a747e4fSDavid du Colombier 	b = *p++;
12449a747e4fSDavid du Colombier 	x = b & 0x7F;
12459a747e4fSDavid du Colombier 	if(b & 0x80){
12469a747e4fSDavid du Colombier 		if(p+1 >= maxp)
12479a747e4fSDavid du Colombier 			error(Eshortdraw);
12489a747e4fSDavid du Colombier 		x |= *p++ << 7;
12499a747e4fSDavid du Colombier 		x |= *p++ << 15;
12509a747e4fSDavid du Colombier 		if(x & (1<<22))
12519a747e4fSDavid du Colombier 			x |= ~0<<23;
12529a747e4fSDavid du Colombier 	}else{
12539a747e4fSDavid du Colombier 		if(b & 0x40)
12549a747e4fSDavid du Colombier 			x |= ~0<<7;
12559a747e4fSDavid du Colombier 		x += oldx;
12569a747e4fSDavid du Colombier 	}
12579a747e4fSDavid du Colombier 	*newx = x;
12589a747e4fSDavid du Colombier 	return p;
12599a747e4fSDavid du Colombier }
12609a747e4fSDavid du Colombier 
12619a747e4fSDavid du Colombier static void
printmesg(char * fmt,uchar * a,int plsprnt)12629a747e4fSDavid du Colombier printmesg(char *fmt, uchar *a, int plsprnt)
12639a747e4fSDavid du Colombier {
12649a747e4fSDavid du Colombier 	char buf[256];
12659a747e4fSDavid du Colombier 	char *p, *q;
12669a747e4fSDavid du Colombier 	int s;
12679a747e4fSDavid du Colombier 
12689a747e4fSDavid du Colombier 	if(1|| plsprnt==0){
12699a747e4fSDavid du Colombier 		SET(s,q,p);
12709a747e4fSDavid du Colombier 		USED(fmt, a, buf, p, q, s);
12719a747e4fSDavid du Colombier 		return;
12729a747e4fSDavid du Colombier 	}
12739a747e4fSDavid du Colombier 	q = buf;
12749a747e4fSDavid du Colombier 	*q++ = *a++;
12759a747e4fSDavid du Colombier 	for(p=fmt; *p; p++){
12769a747e4fSDavid du Colombier 		switch(*p){
12779a747e4fSDavid du Colombier 		case 'l':
12789a747e4fSDavid du Colombier 			q += sprint(q, " %ld", (long)BGLONG(a));
12799a747e4fSDavid du Colombier 			a += 4;
12809a747e4fSDavid du Colombier 			break;
12819a747e4fSDavid du Colombier 		case 'L':
12829a747e4fSDavid du Colombier 			q += sprint(q, " %.8lux", (ulong)BGLONG(a));
12839a747e4fSDavid du Colombier 			a += 4;
12849a747e4fSDavid du Colombier 			break;
12859a747e4fSDavid du Colombier 		case 'R':
12869a747e4fSDavid du Colombier 			q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
12879a747e4fSDavid du Colombier 			a += 16;
12889a747e4fSDavid du Colombier 			break;
12899a747e4fSDavid du Colombier 		case 'P':
12909a747e4fSDavid du Colombier 			q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
12919a747e4fSDavid du Colombier 			a += 8;
12929a747e4fSDavid du Colombier 			break;
12939a747e4fSDavid du Colombier 		case 'b':
12949a747e4fSDavid du Colombier 			q += sprint(q, " %d", *a++);
12959a747e4fSDavid du Colombier 			break;
12969a747e4fSDavid du Colombier 		case 's':
12979a747e4fSDavid du Colombier 			q += sprint(q, " %d", BGSHORT(a));
12989a747e4fSDavid du Colombier 			a += 2;
12999a747e4fSDavid du Colombier 			break;
13009a747e4fSDavid du Colombier 		case 'S':
13019a747e4fSDavid du Colombier 			q += sprint(q, " %.4ux", BGSHORT(a));
13029a747e4fSDavid du Colombier 			a += 2;
13039a747e4fSDavid du Colombier 			break;
13049a747e4fSDavid du Colombier 		}
13059a747e4fSDavid du Colombier 	}
13069a747e4fSDavid du Colombier 	*q++ = '\n';
13079a747e4fSDavid du Colombier 	*q = 0;
13089a747e4fSDavid du Colombier 	iprint("%.*s", (int)(q-buf), buf);
13099a747e4fSDavid du Colombier }
13109a747e4fSDavid du Colombier 
13119a747e4fSDavid du Colombier void
drawmesg(Client * client,void * av,int n)13129a747e4fSDavid du Colombier drawmesg(Client *client, void *av, int n)
13139a747e4fSDavid du Colombier {
13146a9fc400SDavid du Colombier 	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
13159a747e4fSDavid du Colombier 	uchar *u, *a, refresh;
13169a747e4fSDavid du Colombier 	char *fmt;
13179a747e4fSDavid du Colombier 	ulong value, chan;
13189a747e4fSDavid du Colombier 	Rectangle r, clipr;
13199a747e4fSDavid du Colombier 	Point p, q, *pp, sp;
13209a747e4fSDavid du Colombier 	Memimage *i, *dst, *src, *mask;
13219a747e4fSDavid du Colombier 	Memimage *l, **lp;
13229a747e4fSDavid du Colombier 	Memscreen *scrn;
13239a747e4fSDavid du Colombier 	DImage *font, *ll, *di, *ddst, *dsrc;
13249a747e4fSDavid du Colombier 	DName *dn;
13259a747e4fSDavid du Colombier 	DScreen *dscrn;
13269a747e4fSDavid du Colombier 	FChar *fc;
13279a747e4fSDavid du Colombier 	Refx *refx;
13289a747e4fSDavid du Colombier 	CScreen *cs;
13299a747e4fSDavid du Colombier 	Refreshfn reffn;
13309a747e4fSDavid du Colombier 
13319a747e4fSDavid du Colombier 	a = av;
13329a747e4fSDavid du Colombier 	m = 0;
13339a747e4fSDavid du Colombier 	fmt = nil;
13349a747e4fSDavid du Colombier 	if(waserror()){
13359a747e4fSDavid du Colombier 		if(fmt) printmesg(fmt, a, 1);
13369a747e4fSDavid du Colombier 	/*	iprint("error: %s\n", up->error);	*/
13379a747e4fSDavid du Colombier 		nexterror();
13389a747e4fSDavid du Colombier 	}
13399a747e4fSDavid du Colombier 	while((n-=m) > 0){
13409a747e4fSDavid du Colombier 		USED(fmt);
13419a747e4fSDavid du Colombier 		a += m;
13429a747e4fSDavid du Colombier 		switch(*a){
13439a747e4fSDavid du Colombier 		default:
13449a747e4fSDavid du Colombier 			error("bad draw command");
13459a747e4fSDavid du Colombier 		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
13469a747e4fSDavid du Colombier 		case 'b':
13479a747e4fSDavid du Colombier 			printmesg(fmt="LLbLbRRL", a, 0);
13489a747e4fSDavid du Colombier 			m = 1+4+4+1+4+1+4*4+4*4+4;
13499a747e4fSDavid du Colombier 			if(n < m)
13509a747e4fSDavid du Colombier 				error(Eshortdraw);
13519a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
13529a747e4fSDavid du Colombier 			scrnid = BGSHORT(a+5);
13539a747e4fSDavid du Colombier 			refresh = a[9];
13549a747e4fSDavid du Colombier 			chan = BGLONG(a+10);
13559a747e4fSDavid du Colombier 			repl = a[14];
13569a747e4fSDavid du Colombier 			drawrectangle(&r, a+15);
13579a747e4fSDavid du Colombier 			drawrectangle(&clipr, a+31);
13589a747e4fSDavid du Colombier 			value = BGLONG(a+47);
13599a747e4fSDavid du Colombier 			if(drawlookup(client, dstid, 0))
13609a747e4fSDavid du Colombier 				error(Eimageexists);
13619a747e4fSDavid du Colombier 			if(scrnid){
13629a747e4fSDavid du Colombier 				dscrn = drawlookupscreen(client, scrnid, &cs);
13639a747e4fSDavid du Colombier 				scrn = dscrn->screen;
13649a747e4fSDavid du Colombier 				if(repl || chan!=scrn->image->chan)
13659a747e4fSDavid du Colombier 					error("image parameters incompatible with screen");
13669a747e4fSDavid du Colombier 				reffn = nil;
13679a747e4fSDavid du Colombier 				switch(refresh){
13689a747e4fSDavid du Colombier 				case Refbackup:
13699a747e4fSDavid du Colombier 					break;
13709a747e4fSDavid du Colombier 				case Refnone:
13719a747e4fSDavid du Colombier 					reffn = memlnorefresh;
13729a747e4fSDavid du Colombier 					break;
13739a747e4fSDavid du Colombier 				case Refmesg:
13749a747e4fSDavid du Colombier 					reffn = drawrefresh;
13759a747e4fSDavid du Colombier 					break;
13769a747e4fSDavid du Colombier 				default:
13779a747e4fSDavid du Colombier 					error("unknown refresh method");
13789a747e4fSDavid du Colombier 				}
13799a747e4fSDavid du Colombier 				l = memlalloc(scrn, r, reffn, 0, value);
13809a747e4fSDavid du Colombier 				if(l == 0)
13819a747e4fSDavid du Colombier 					error(Edrawmem);
13829a747e4fSDavid du Colombier 				addflush(l->layer->screenr);
13839a747e4fSDavid du Colombier 				l->clipr = clipr;
13849a747e4fSDavid du Colombier 				rectclip(&l->clipr, r);
13859a747e4fSDavid du Colombier 				if(drawinstall(client, dstid, l, dscrn) == 0){
13869a747e4fSDavid du Colombier 					memldelete(l);
13879a747e4fSDavid du Colombier 					error(Edrawmem);
13889a747e4fSDavid du Colombier 				}
13899a747e4fSDavid du Colombier 				dscrn->ref++;
13909a747e4fSDavid du Colombier 				if(reffn){
13919a747e4fSDavid du Colombier 					refx = nil;
13929a747e4fSDavid du Colombier 					if(reffn == drawrefresh){
13939a747e4fSDavid du Colombier 						refx = malloc(sizeof(Refx));
13949a747e4fSDavid du Colombier 						if(refx == 0){
13959a747e4fSDavid du Colombier 							drawuninstall(client, dstid);
13969a747e4fSDavid du Colombier 							error(Edrawmem);
13979a747e4fSDavid du Colombier 						}
13989a747e4fSDavid du Colombier 						refx->client = client;
13999a747e4fSDavid du Colombier 						refx->dimage = drawlookup(client, dstid, 1);
14009a747e4fSDavid du Colombier 					}
14019a747e4fSDavid du Colombier 					memlsetrefresh(l, reffn, refx);
14029a747e4fSDavid du Colombier 				}
14039a747e4fSDavid du Colombier 				continue;
14049a747e4fSDavid du Colombier 			}
14059a747e4fSDavid du Colombier 			i = allocmemimage(r, chan);
14069a747e4fSDavid du Colombier 			if(i == 0)
14079a747e4fSDavid du Colombier 				error(Edrawmem);
14089a747e4fSDavid du Colombier 			if(repl)
14099a747e4fSDavid du Colombier 				i->flags |= Frepl;
14109a747e4fSDavid du Colombier 			i->clipr = clipr;
14119a747e4fSDavid du Colombier 			if(!repl)
14129a747e4fSDavid du Colombier 				rectclip(&i->clipr, r);
14139a747e4fSDavid du Colombier 			if(drawinstall(client, dstid, i, 0) == 0){
14149a747e4fSDavid du Colombier 				freememimage(i);
14159a747e4fSDavid du Colombier 				error(Edrawmem);
14169a747e4fSDavid du Colombier 			}
14179a747e4fSDavid du Colombier 			memfillcolor(i, value);
14189a747e4fSDavid du Colombier 			continue;
14199a747e4fSDavid du Colombier 
14209a747e4fSDavid du Colombier 		/* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
14219a747e4fSDavid du Colombier 		case 'A':
14229a747e4fSDavid du Colombier 			printmesg(fmt="LLLb", a, 1);
14239a747e4fSDavid du Colombier 			m = 1+4+4+4+1;
14249a747e4fSDavid du Colombier 			if(n < m)
14259a747e4fSDavid du Colombier 				error(Eshortdraw);
14269a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
14279a747e4fSDavid du Colombier 			if(dstid == 0)
14289a747e4fSDavid du Colombier 				error(Ebadarg);
14299a747e4fSDavid du Colombier 			if(drawlookupdscreen(dstid))
14309a747e4fSDavid du Colombier 				error(Escreenexists);
14319a747e4fSDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+5), 1);
14329a747e4fSDavid du Colombier 			dsrc = drawlookup(client, BGLONG(a+9), 1);
14339a747e4fSDavid du Colombier 			if(ddst==0 || dsrc==0)
14349a747e4fSDavid du Colombier 				error(Enodrawimage);
14359a747e4fSDavid du Colombier 			if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
14369a747e4fSDavid du Colombier 				error(Edrawmem);
14379a747e4fSDavid du Colombier 			continue;
14389a747e4fSDavid du Colombier 
14399a747e4fSDavid du Colombier 		/* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
14409a747e4fSDavid du Colombier 		case 'c':
14419a747e4fSDavid du Colombier 			printmesg(fmt="LbR", a, 0);
14429a747e4fSDavid du Colombier 			m = 1+4+1+4*4;
14439a747e4fSDavid du Colombier 			if(n < m)
14449a747e4fSDavid du Colombier 				error(Eshortdraw);
14459a747e4fSDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+1), 1);
14469a747e4fSDavid du Colombier 			if(ddst == nil)
14479a747e4fSDavid du Colombier 				error(Enodrawimage);
14489a747e4fSDavid du Colombier 			if(ddst->name)
14499a747e4fSDavid du Colombier 				error("can't change repl/clipr of shared image");
14509a747e4fSDavid du Colombier 			dst = ddst->image;
14519a747e4fSDavid du Colombier 			if(a[5])
14529a747e4fSDavid du Colombier 				dst->flags |= Frepl;
14539a747e4fSDavid du Colombier 			drawrectangle(&dst->clipr, a+6);
14549a747e4fSDavid du Colombier 			continue;
14559a747e4fSDavid du Colombier 
14569a747e4fSDavid du Colombier 		/* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
14579a747e4fSDavid du Colombier 		case 'd':
14589a747e4fSDavid du Colombier 			printmesg(fmt="LLLRPP", a, 0);
14599a747e4fSDavid du Colombier 			m = 1+4+4+4+4*4+2*4+2*4;
14609a747e4fSDavid du Colombier 			if(n < m)
14619a747e4fSDavid du Colombier 				error(Eshortdraw);
14629a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
14639a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
14649a747e4fSDavid du Colombier 			src = drawimage(client, a+5);
14659a747e4fSDavid du Colombier 			mask = drawimage(client, a+9);
14669a747e4fSDavid du Colombier 			drawrectangle(&r, a+13);
14679a747e4fSDavid du Colombier 			drawpoint(&p, a+29);
14689a747e4fSDavid du Colombier 			drawpoint(&q, a+37);
14696a9fc400SDavid du Colombier 			op = drawclientop(client);
14706a9fc400SDavid du Colombier 			memdraw(dst, r, src, p, mask, q, op);
14719a747e4fSDavid du Colombier 			dstflush(dstid, dst, r);
14729a747e4fSDavid du Colombier 			continue;
14739a747e4fSDavid du Colombier 
14749a747e4fSDavid du Colombier 		/* toggle debugging: 'D' val[1] */
14759a747e4fSDavid du Colombier 		case 'D':
14769a747e4fSDavid du Colombier 			printmesg(fmt="b", a, 0);
14779a747e4fSDavid du Colombier 			m = 1+1;
14789a747e4fSDavid du Colombier 			if(n < m)
14799a747e4fSDavid du Colombier 				error(Eshortdraw);
14809a747e4fSDavid du Colombier 			drawdebug = a[1];
14819a747e4fSDavid du Colombier 			continue;
14829a747e4fSDavid du Colombier 
14839a747e4fSDavid du Colombier 		/* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
14849a747e4fSDavid du Colombier 		case 'e':
14859a747e4fSDavid du Colombier 		case 'E':
14869a747e4fSDavid du Colombier 			printmesg(fmt="LLPlllPll", a, 0);
14879a747e4fSDavid du Colombier 			m = 1+4+4+2*4+4+4+4+2*4+2*4;
14889a747e4fSDavid du Colombier 			if(n < m)
14899a747e4fSDavid du Colombier 				error(Eshortdraw);
14909a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
14919a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
14929a747e4fSDavid du Colombier 			src = drawimage(client, a+5);
14939a747e4fSDavid du Colombier 			drawpoint(&p, a+9);
14949a747e4fSDavid du Colombier 			e0 = BGLONG(a+17);
14959a747e4fSDavid du Colombier 			e1 = BGLONG(a+21);
14969a747e4fSDavid du Colombier 			if(e0<0 || e1<0)
14979a747e4fSDavid du Colombier 				error("invalid ellipse semidiameter");
14989a747e4fSDavid du Colombier 			j = BGLONG(a+25);
14999a747e4fSDavid du Colombier 			if(j < 0)
15009a747e4fSDavid du Colombier 				error("negative ellipse thickness");
15019a747e4fSDavid du Colombier 			drawpoint(&sp, a+29);
15029a747e4fSDavid du Colombier 			c = j;
15039a747e4fSDavid du Colombier 			if(*a == 'E')
15049a747e4fSDavid du Colombier 				c = -1;
15059a747e4fSDavid du Colombier 			ox = BGLONG(a+37);
15069a747e4fSDavid du Colombier 			oy = BGLONG(a+41);
15076a9fc400SDavid du Colombier 			op = drawclientop(client);
15089a747e4fSDavid du Colombier 			/* high bit indicates arc angles are present */
15099a747e4fSDavid du Colombier 			if(ox & (1<<31)){
15109a747e4fSDavid du Colombier 				if((ox & (1<<30)) == 0)
15119a747e4fSDavid du Colombier 					ox &= ~(1<<31);
15126a9fc400SDavid du Colombier 				memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
15139a747e4fSDavid du Colombier 			}else
15146a9fc400SDavid du Colombier 				memellipse(dst, p, e0, e1, c, src, sp, op);
15159a747e4fSDavid du Colombier 			dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
15169a747e4fSDavid du Colombier 			continue;
15179a747e4fSDavid du Colombier 
15189a747e4fSDavid du Colombier 		/* free: 'f' id[4] */
15199a747e4fSDavid du Colombier 		case 'f':
15209a747e4fSDavid du Colombier 			printmesg(fmt="L", a, 1);
15219a747e4fSDavid du Colombier 			m = 1+4;
15229a747e4fSDavid du Colombier 			if(n < m)
15239a747e4fSDavid du Colombier 				error(Eshortdraw);
15249a747e4fSDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1), 0);
15259a747e4fSDavid du Colombier 			if(ll && ll->dscreen && ll->dscreen->owner != client)
15269a747e4fSDavid du Colombier 				ll->dscreen->owner->refreshme = 1;
15279a747e4fSDavid du Colombier 			drawuninstall(client, BGLONG(a+1));
15289a747e4fSDavid du Colombier 			continue;
15299a747e4fSDavid du Colombier 
15309a747e4fSDavid du Colombier 		/* free screen: 'F' id[4] */
15319a747e4fSDavid du Colombier 		case 'F':
15329a747e4fSDavid du Colombier 			printmesg(fmt="L", a, 1);
15339a747e4fSDavid du Colombier 			m = 1+4;
15349a747e4fSDavid du Colombier 			if(n < m)
15359a747e4fSDavid du Colombier 				error(Eshortdraw);
15369a747e4fSDavid du Colombier 			drawlookupscreen(client, BGLONG(a+1), &cs);
15379a747e4fSDavid du Colombier 			drawuninstallscreen(client, cs);
15389a747e4fSDavid du Colombier 			continue;
15399a747e4fSDavid du Colombier 
15409a747e4fSDavid du Colombier 		/* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
15419a747e4fSDavid du Colombier 		case 'i':
15429a747e4fSDavid du Colombier 			printmesg(fmt="Llb", a, 1);
15439a747e4fSDavid du Colombier 			m = 1+4+4+1;
15449a747e4fSDavid du Colombier 			if(n < m)
15459a747e4fSDavid du Colombier 				error(Eshortdraw);
15469a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
15479a747e4fSDavid du Colombier 			if(dstid == 0)
15489a747e4fSDavid du Colombier 				error("can't use display as font");
15499a747e4fSDavid du Colombier 			font = drawlookup(client, dstid, 1);
15509a747e4fSDavid du Colombier 			if(font == 0)
15519a747e4fSDavid du Colombier 				error(Enodrawimage);
15529a747e4fSDavid du Colombier 			if(font->image->layer)
15539a747e4fSDavid du Colombier 				error("can't use window as font");
15549a747e4fSDavid du Colombier 			free(font->fchar);	/* should we complain if non-zero? */
15559a747e4fSDavid du Colombier 			ni = BGLONG(a+5);
15569a747e4fSDavid du Colombier 			font->fchar = malloc(ni*sizeof(FChar));
15579a747e4fSDavid du Colombier 			if(font->fchar == 0)
15589a747e4fSDavid du Colombier 				error("no memory for font");
15599a747e4fSDavid du Colombier 			memset(font->fchar, 0, ni*sizeof(FChar));
15609a747e4fSDavid du Colombier 			font->nfchar = ni;
15619a747e4fSDavid du Colombier 			font->ascent = a[9];
15629a747e4fSDavid du Colombier 			continue;
15639a747e4fSDavid du Colombier 
15649a747e4fSDavid du Colombier 		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
15659a747e4fSDavid du Colombier 		case 'l':
15669a747e4fSDavid du Colombier 			printmesg(fmt="LLSRPbb", a, 0);
15679a747e4fSDavid du Colombier 			m = 1+4+4+2+4*4+2*4+1+1;
15689a747e4fSDavid du Colombier 			if(n < m)
15699a747e4fSDavid du Colombier 				error(Eshortdraw);
15709a747e4fSDavid du Colombier 			font = drawlookup(client, BGLONG(a+1), 1);
15719a747e4fSDavid du Colombier 			if(font == 0)
15729a747e4fSDavid du Colombier 				error(Enodrawimage);
15739a747e4fSDavid du Colombier 			if(font->nfchar == 0)
15749a747e4fSDavid du Colombier 				error(Enotfont);
15759a747e4fSDavid du Colombier 			src = drawimage(client, a+5);
15769a747e4fSDavid du Colombier 			ci = BGSHORT(a+9);
15779a747e4fSDavid du Colombier 			if(ci >= font->nfchar)
15789a747e4fSDavid du Colombier 				error(Eindex);
15799a747e4fSDavid du Colombier 			drawrectangle(&r, a+11);
15809a747e4fSDavid du Colombier 			drawpoint(&p, a+27);
15816a9fc400SDavid du Colombier 			memdraw(font->image, r, src, p, memopaque, p, S);
15829a747e4fSDavid du Colombier 			fc = &font->fchar[ci];
15839a747e4fSDavid du Colombier 			fc->minx = r.min.x;
15849a747e4fSDavid du Colombier 			fc->maxx = r.max.x;
15859a747e4fSDavid du Colombier 			fc->miny = r.min.y;
15869a747e4fSDavid du Colombier 			fc->maxy = r.max.y;
15879a747e4fSDavid du Colombier 			fc->left = a[35];
15889a747e4fSDavid du Colombier 			fc->width = a[36];
15899a747e4fSDavid du Colombier 			continue;
15909a747e4fSDavid du Colombier 
15919a747e4fSDavid du Colombier 		/* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
15929a747e4fSDavid du Colombier 		case 'L':
15939a747e4fSDavid du Colombier 			printmesg(fmt="LPPlllLP", a, 0);
15949a747e4fSDavid du Colombier 			m = 1+4+2*4+2*4+4+4+4+4+2*4;
15959a747e4fSDavid du Colombier 			if(n < m)
15969a747e4fSDavid du Colombier 				error(Eshortdraw);
15979a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
15989a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
15999a747e4fSDavid du Colombier 			drawpoint(&p, a+5);
16009a747e4fSDavid du Colombier 			drawpoint(&q, a+13);
16019a747e4fSDavid du Colombier 			e0 = BGLONG(a+21);
16029a747e4fSDavid du Colombier 			e1 = BGLONG(a+25);
16039a747e4fSDavid du Colombier 			j = BGLONG(a+29);
16049a747e4fSDavid du Colombier 			if(j < 0)
16059a747e4fSDavid du Colombier 				error("negative line width");
16069a747e4fSDavid du Colombier 			src = drawimage(client, a+33);
16079a747e4fSDavid du Colombier 			drawpoint(&sp, a+37);
16086a9fc400SDavid du Colombier 			op = drawclientop(client);
16096a9fc400SDavid du Colombier 			memline(dst, p, q, e0, e1, j, src, sp, op);
16109a747e4fSDavid du Colombier 			/* avoid memlinebbox if possible */
16119a747e4fSDavid du Colombier 			if(dstid==0 || dst->layer!=nil){
16129a747e4fSDavid du Colombier 				/* BUG: this is terribly inefficient: update maximal containing rect*/
16139a747e4fSDavid du Colombier 				r = memlinebbox(p, q, e0, e1, j);
16149a747e4fSDavid du Colombier 				dstflush(dstid, dst, insetrect(r, -(1+1+j)));
16159a747e4fSDavid du Colombier 			}
16169a747e4fSDavid du Colombier 			continue;
16179a747e4fSDavid du Colombier 
16189a747e4fSDavid du Colombier 		/* create image mask: 'm' newid[4] id[4] */
16199a747e4fSDavid du Colombier /*
16209a747e4fSDavid du Colombier  *
16219a747e4fSDavid du Colombier 		case 'm':
16229a747e4fSDavid du Colombier 			printmesg("LL", a, 0);
16239a747e4fSDavid du Colombier 			m = 4+4;
16249a747e4fSDavid du Colombier 			if(n < m)
16259a747e4fSDavid du Colombier 				error(Eshortdraw);
16269a747e4fSDavid du Colombier 			break;
16279a747e4fSDavid du Colombier  *
16289a747e4fSDavid du Colombier  */
16299a747e4fSDavid du Colombier 
16309a747e4fSDavid du Colombier 		/* attach to a named image: 'n' dstid[4] j[1] name[j] */
16319a747e4fSDavid du Colombier 		case 'n':
16329a747e4fSDavid du Colombier 			printmesg(fmt="Lz", a, 0);
16339a747e4fSDavid du Colombier 			m = 1+4+1;
16349a747e4fSDavid du Colombier 			if(n < m)
16359a747e4fSDavid du Colombier 				error(Eshortdraw);
16369a747e4fSDavid du Colombier 			j = a[5];
16379a747e4fSDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
16389a747e4fSDavid du Colombier 				error(Eshortdraw);
16399a747e4fSDavid du Colombier 			m += j;
16409a747e4fSDavid du Colombier 			if(n < m)
16419a747e4fSDavid du Colombier 				error(Eshortdraw);
16429a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
16439a747e4fSDavid du Colombier 			if(drawlookup(client, dstid, 0))
16449a747e4fSDavid du Colombier 				error(Eimageexists);
16459a747e4fSDavid du Colombier 			dn = drawlookupname(j, (char*)a+6);
16469a747e4fSDavid du Colombier 			if(dn == nil)
16479a747e4fSDavid du Colombier 				error(Enoname);
16489a747e4fSDavid du Colombier 			if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
16499a747e4fSDavid du Colombier 				error(Edrawmem);
16509a747e4fSDavid du Colombier 			di = drawlookup(client, dstid, 0);
16519a747e4fSDavid du Colombier 			if(di == 0)
16529a747e4fSDavid du Colombier 				error("draw: can't happen");
16539a747e4fSDavid du Colombier 			di->vers = dn->vers;
16549a747e4fSDavid du Colombier 			di->name = smalloc(j+1);
16559a747e4fSDavid du Colombier 			di->fromname = dn->dimage;
16569a747e4fSDavid du Colombier 			di->fromname->ref++;
16579a747e4fSDavid du Colombier 			memmove(di->name, a+6, j);
16589a747e4fSDavid du Colombier 			di->name[j] = 0;
16599a747e4fSDavid du Colombier 			client->infoid = dstid;
16609a747e4fSDavid du Colombier 			continue;
16619a747e4fSDavid du Colombier 
16629a747e4fSDavid du Colombier 		/* name an image: 'N' dstid[4] in[1] j[1] name[j] */
16639a747e4fSDavid du Colombier 		case 'N':
16649a747e4fSDavid du Colombier 			printmesg(fmt="Lbz", a, 0);
16659a747e4fSDavid du Colombier 			m = 1+4+1+1;
16669a747e4fSDavid du Colombier 			if(n < m)
16679a747e4fSDavid du Colombier 				error(Eshortdraw);
16689a747e4fSDavid du Colombier 			c = a[5];
16699a747e4fSDavid du Colombier 			j = a[6];
16709a747e4fSDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
16719a747e4fSDavid du Colombier 				error(Eshortdraw);
16729a747e4fSDavid du Colombier 			m += j;
16739a747e4fSDavid du Colombier 			if(n < m)
16749a747e4fSDavid du Colombier 				error(Eshortdraw);
16759a747e4fSDavid du Colombier 			di = drawlookup(client, BGLONG(a+1), 0);
16769a747e4fSDavid du Colombier 			if(di == 0)
16779a747e4fSDavid du Colombier 				error(Enodrawimage);
16789a747e4fSDavid du Colombier 			if(di->name)
16799a747e4fSDavid du Colombier 				error(Enamed);
16809a747e4fSDavid du Colombier 			if(c)
16819a747e4fSDavid du Colombier 				drawaddname(client, di, j, (char*)a+7);
16829a747e4fSDavid du Colombier 			else{
16839a747e4fSDavid du Colombier 				dn = drawlookupname(j, (char*)a+7);
16849a747e4fSDavid du Colombier 				if(dn == nil)
16859a747e4fSDavid du Colombier 					error(Enoname);
16869a747e4fSDavid du Colombier 				if(dn->dimage != di)
16879a747e4fSDavid du Colombier 					error(Ewrongname);
16889a747e4fSDavid du Colombier 				drawdelname(dn);
16899a747e4fSDavid du Colombier 			}
16909a747e4fSDavid du Colombier 			continue;
16919a747e4fSDavid du Colombier 
16929a747e4fSDavid du Colombier 		/* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
16939a747e4fSDavid du Colombier 		case 'o':
16949a747e4fSDavid du Colombier 			printmesg(fmt="LPP", a, 0);
16959a747e4fSDavid du Colombier 			m = 1+4+2*4+2*4;
16969a747e4fSDavid du Colombier 			if(n < m)
16979a747e4fSDavid du Colombier 				error(Eshortdraw);
16989a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
16999a747e4fSDavid du Colombier 			if(dst->layer){
17009a747e4fSDavid du Colombier 				drawpoint(&p, a+5);
17019a747e4fSDavid du Colombier 				drawpoint(&q, a+13);
17029a747e4fSDavid du Colombier 				r = dst->layer->screenr;
17039a747e4fSDavid du Colombier 				ni = memlorigin(dst, p, q);
17049a747e4fSDavid du Colombier 				if(ni < 0)
17059a747e4fSDavid du Colombier 					error("image origin failed");
17069a747e4fSDavid du Colombier 				if(ni > 0){
17079a747e4fSDavid du Colombier 					addflush(r);
17089a747e4fSDavid du Colombier 					addflush(dst->layer->screenr);
17099a747e4fSDavid du Colombier 					ll = drawlookup(client, BGLONG(a+1), 1);
17109a747e4fSDavid du Colombier 					drawrefreshscreen(ll, client);
17119a747e4fSDavid du Colombier 				}
17129a747e4fSDavid du Colombier 			}
17139a747e4fSDavid du Colombier 			continue;
17149a747e4fSDavid du Colombier 
17156a9fc400SDavid du Colombier 		/* set compositing operator for next draw operation: 'O' op */
17166a9fc400SDavid du Colombier 		case 'O':
17176a9fc400SDavid du Colombier 			printmesg(fmt="b", a, 0);
17186a9fc400SDavid du Colombier 			m = 1+1;
17196a9fc400SDavid du Colombier 			if(n < m)
17206a9fc400SDavid du Colombier 				error(Eshortdraw);
17216a9fc400SDavid du Colombier 			client->op = a[1];
17226a9fc400SDavid du Colombier 			continue;
17236a9fc400SDavid du Colombier 
17249a747e4fSDavid du Colombier 		/* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
17259a747e4fSDavid du Colombier 		/* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
17269a747e4fSDavid du Colombier 		case 'p':
17279a747e4fSDavid du Colombier 		case 'P':
17289a747e4fSDavid du Colombier 			printmesg(fmt="LslllLPP", a, 0);
17299a747e4fSDavid du Colombier 			m = 1+4+2+4+4+4+4+2*4;
17309a747e4fSDavid du Colombier 			if(n < m)
17319a747e4fSDavid du Colombier 				error(Eshortdraw);
17329a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
17339a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
17349a747e4fSDavid du Colombier 			ni = BGSHORT(a+5);
17359a747e4fSDavid du Colombier 			if(ni < 0)
17369a747e4fSDavid du Colombier 				error("negative count in polygon");
17379a747e4fSDavid du Colombier 			e0 = BGLONG(a+7);
17389a747e4fSDavid du Colombier 			e1 = BGLONG(a+11);
17399a747e4fSDavid du Colombier 			j = 0;
17409a747e4fSDavid du Colombier 			if(*a == 'p'){
17419a747e4fSDavid du Colombier 				j = BGLONG(a+15);
17429a747e4fSDavid du Colombier 				if(j < 0)
17439a747e4fSDavid du Colombier 					error("negative polygon line width");
17449a747e4fSDavid du Colombier 			}
17459a747e4fSDavid du Colombier 			src = drawimage(client, a+19);
17469a747e4fSDavid du Colombier 			drawpoint(&sp, a+23);
17479a747e4fSDavid du Colombier 			drawpoint(&p, a+31);
17489a747e4fSDavid du Colombier 			ni++;
17499a747e4fSDavid du Colombier 			pp = malloc(ni*sizeof(Point));
17509a747e4fSDavid du Colombier 			if(pp == nil)
17519a747e4fSDavid du Colombier 				error(Enomem);
17529a747e4fSDavid du Colombier 			doflush = 0;
17539a747e4fSDavid du Colombier 			if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
17549a747e4fSDavid du Colombier 				doflush = 1;	/* simplify test in loop */
17559a747e4fSDavid du Colombier 			ox = oy = 0;
17566a9fc400SDavid du Colombier 			esize = 0;
17579a747e4fSDavid du Colombier 			u = a+m;
17589a747e4fSDavid du Colombier 			for(y=0; y<ni; y++){
17596a9fc400SDavid du Colombier 				q = p;
17606a9fc400SDavid du Colombier 				oesize = esize;
17619a747e4fSDavid du Colombier 				u = drawcoord(u, a+n, ox, &p.x);
17629a747e4fSDavid du Colombier 				u = drawcoord(u, a+n, oy, &p.y);
17639a747e4fSDavid du Colombier 				ox = p.x;
17649a747e4fSDavid du Colombier 				oy = p.y;
17659a747e4fSDavid du Colombier 				if(doflush){
17669a747e4fSDavid du Colombier 					esize = j;
17679a747e4fSDavid du Colombier 					if(*a == 'p'){
17689a747e4fSDavid du Colombier 						if(y == 0){
17699a747e4fSDavid du Colombier 							c = memlineendsize(e0);
17709a747e4fSDavid du Colombier 							if(c > esize)
17719a747e4fSDavid du Colombier 								esize = c;
17729a747e4fSDavid du Colombier 						}
17739a747e4fSDavid du Colombier 						if(y == ni-1){
17749a747e4fSDavid du Colombier 							c = memlineendsize(e1);
17759a747e4fSDavid du Colombier 							if(c > esize)
17769a747e4fSDavid du Colombier 								esize = c;
17779a747e4fSDavid du Colombier 						}
17789a747e4fSDavid du Colombier 					}
17799a747e4fSDavid du Colombier 					if(*a=='P' && e0!=1 && e0 !=~0)
17809a747e4fSDavid du Colombier 						r = dst->clipr;
17816a9fc400SDavid du Colombier 					else if(y > 0){
17826a9fc400SDavid du Colombier 						r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
17836a9fc400SDavid du Colombier 						combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
17846a9fc400SDavid du Colombier 					}
17856a9fc400SDavid du Colombier 					if(rectclip(&r, dst->clipr))		/* should perhaps be an arg to dstflush */
17869a747e4fSDavid du Colombier 						dstflush(dstid, dst, r);
17879a747e4fSDavid du Colombier 				}
17889a747e4fSDavid du Colombier 				pp[y] = p;
17899a747e4fSDavid du Colombier 			}
17906a9fc400SDavid du Colombier 			if(y == 1)
17916a9fc400SDavid du Colombier 				dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
17926a9fc400SDavid du Colombier 			op = drawclientop(client);
17939a747e4fSDavid du Colombier 			if(*a == 'p')
17946a9fc400SDavid du Colombier 				mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
17959a747e4fSDavid du Colombier 			else
17966a9fc400SDavid du Colombier 				memfillpoly(dst, pp, ni, e0, src, sp, op);
17979a747e4fSDavid du Colombier 			free(pp);
17989a747e4fSDavid du Colombier 			m = u-a;
17999a747e4fSDavid du Colombier 			continue;
18009a747e4fSDavid du Colombier 
18019a747e4fSDavid du Colombier 		/* read: 'r' id[4] R[4*4] */
18029a747e4fSDavid du Colombier 		case 'r':
18039a747e4fSDavid du Colombier 			printmesg(fmt="LR", a, 0);
18049a747e4fSDavid du Colombier 			m = 1+4+4*4;
18059a747e4fSDavid du Colombier 			if(n < m)
18069a747e4fSDavid du Colombier 				error(Eshortdraw);
18079a747e4fSDavid du Colombier 			i = drawimage(client, a+1);
18089a747e4fSDavid du Colombier 			if(0 && i->layer)
18099a747e4fSDavid du Colombier 				error("readimage from window unimplemented");
18109a747e4fSDavid du Colombier 			drawrectangle(&r, a+5);
18119a747e4fSDavid du Colombier 			if(!rectinrect(r, i->r))
18129a747e4fSDavid du Colombier 				error(Ereadoutside);
18139a747e4fSDavid du Colombier 			c = bytesperline(r, i->depth);
18149a747e4fSDavid du Colombier 			c *= Dy(r);
18159a747e4fSDavid du Colombier 			free(client->readdata);
18169a747e4fSDavid du Colombier 			client->readdata = mallocz(c, 0);
18179a747e4fSDavid du Colombier 			if(client->readdata == nil)
18189a747e4fSDavid du Colombier 				error("readimage malloc failed");
18199a747e4fSDavid du Colombier 			client->nreaddata = unloadmemimage(i, r, client->readdata, c);
18209a747e4fSDavid du Colombier 			if(client->nreaddata < 0){
18219a747e4fSDavid du Colombier 				free(client->readdata);
18229a747e4fSDavid du Colombier 				client->readdata = nil;
18239a747e4fSDavid du Colombier 				error("bad readimage call");
18249a747e4fSDavid du Colombier 			}
18259a747e4fSDavid du Colombier 			continue;
18269a747e4fSDavid du Colombier 
18279a747e4fSDavid du Colombier 		/* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
18289a747e4fSDavid du Colombier 		/* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
18299a747e4fSDavid du Colombier 		case 's':
18309a747e4fSDavid du Colombier 		case 'x':
18319a747e4fSDavid du Colombier 			printmesg(fmt="LLLPRPs", a, 0);
18329a747e4fSDavid du Colombier 			m = 1+4+4+4+2*4+4*4+2*4+2;
18339a747e4fSDavid du Colombier 			if(*a == 'x')
18349a747e4fSDavid du Colombier 				m += 4+2*4;
18359a747e4fSDavid du Colombier 			if(n < m)
18369a747e4fSDavid du Colombier 				error(Eshortdraw);
18379a747e4fSDavid du Colombier 
18389a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
18399a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
18409a747e4fSDavid du Colombier 			src = drawimage(client, a+5);
18419a747e4fSDavid du Colombier 			font = drawlookup(client, BGLONG(a+9), 1);
18429a747e4fSDavid du Colombier 			if(font == 0)
18439a747e4fSDavid du Colombier 				error(Enodrawimage);
18449a747e4fSDavid du Colombier 			if(font->nfchar == 0)
18459a747e4fSDavid du Colombier 				error(Enotfont);
18469a747e4fSDavid du Colombier 			drawpoint(&p, a+13);
18479a747e4fSDavid du Colombier 			drawrectangle(&r, a+21);
18489a747e4fSDavid du Colombier 			drawpoint(&sp, a+37);
18499a747e4fSDavid du Colombier 			ni = BGSHORT(a+45);
18509a747e4fSDavid du Colombier 			u = a+m;
18519a747e4fSDavid du Colombier 			m += ni*2;
18529a747e4fSDavid du Colombier 			if(n < m)
18539a747e4fSDavid du Colombier 				error(Eshortdraw);
18549a747e4fSDavid du Colombier 			clipr = dst->clipr;
18559a747e4fSDavid du Colombier 			dst->clipr = r;
18566a9fc400SDavid du Colombier 			op = drawclientop(client);
18579a747e4fSDavid du Colombier 			if(*a == 'x'){
18589a747e4fSDavid du Colombier 				/* paint background */
18599a747e4fSDavid du Colombier 				l = drawimage(client, a+47);
18609a747e4fSDavid du Colombier 				drawpoint(&q, a+51);
18619a747e4fSDavid du Colombier 				r.min.x = p.x;
18629a747e4fSDavid du Colombier 				r.min.y = p.y-font->ascent;
18639a747e4fSDavid du Colombier 				r.max.x = p.x;
18649a747e4fSDavid du Colombier 				r.max.y = r.min.y+Dy(font->image->r);
18659a747e4fSDavid du Colombier 				j = ni;
18669a747e4fSDavid du Colombier 				while(--j >= 0){
18679a747e4fSDavid du Colombier 					ci = BGSHORT(u);
18689a747e4fSDavid du Colombier 					if(ci<0 || ci>=font->nfchar){
18699a747e4fSDavid du Colombier 						dst->clipr = clipr;
18709a747e4fSDavid du Colombier 						error(Eindex);
18719a747e4fSDavid du Colombier 					}
18729a747e4fSDavid du Colombier 					r.max.x += font->fchar[ci].width;
18739a747e4fSDavid du Colombier 					u += 2;
18749a747e4fSDavid du Colombier 				}
18756a9fc400SDavid du Colombier 				memdraw(dst, r, l, q, memopaque, ZP, op);
18769a747e4fSDavid du Colombier 				u -= 2*ni;
18779a747e4fSDavid du Colombier 			}
18789a747e4fSDavid du Colombier 			q = p;
18799a747e4fSDavid du Colombier 			while(--ni >= 0){
18809a747e4fSDavid du Colombier 				ci = BGSHORT(u);
18819a747e4fSDavid du Colombier 				if(ci<0 || ci>=font->nfchar){
18829a747e4fSDavid du Colombier 					dst->clipr = clipr;
18839a747e4fSDavid du Colombier 					error(Eindex);
18849a747e4fSDavid du Colombier 				}
18856a9fc400SDavid du Colombier 				q = drawchar(dst, q, src, &sp, font, ci, op);
18869a747e4fSDavid du Colombier 				u += 2;
18879a747e4fSDavid du Colombier 			}
18889a747e4fSDavid du Colombier 			dst->clipr = clipr;
18899a747e4fSDavid du Colombier 			p.y -= font->ascent;
18909a747e4fSDavid du Colombier 			dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
18919a747e4fSDavid du Colombier 			continue;
18929a747e4fSDavid du Colombier 
18939a747e4fSDavid du Colombier 		/* use public screen: 'S' id[4] chan[4] */
18949a747e4fSDavid du Colombier 		case 'S':
18959a747e4fSDavid du Colombier 			printmesg(fmt="Ll", a, 0);
18969a747e4fSDavid du Colombier 			m = 1+4+4;
18979a747e4fSDavid du Colombier 			if(n < m)
18989a747e4fSDavid du Colombier 				error(Eshortdraw);
18999a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
19009a747e4fSDavid du Colombier 			if(dstid == 0)
19019a747e4fSDavid du Colombier 				error(Ebadarg);
19029a747e4fSDavid du Colombier 			dscrn = drawlookupdscreen(dstid);
19039a747e4fSDavid du Colombier 			if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
19049a747e4fSDavid du Colombier 				error(Enodrawscreen);
19059a747e4fSDavid du Colombier 			if(dscrn->screen->image->chan != BGLONG(a+5))
19069a747e4fSDavid du Colombier 				error("inconsistent chan");
19079a747e4fSDavid du Colombier 			if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
19089a747e4fSDavid du Colombier 				error(Edrawmem);
19099a747e4fSDavid du Colombier 			continue;
19109a747e4fSDavid du Colombier 
19119a747e4fSDavid du Colombier 		/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
19129a747e4fSDavid du Colombier 		case 't':
19139a747e4fSDavid du Colombier 			printmesg(fmt="bsL", a, 0);
19149a747e4fSDavid du Colombier 			m = 1+1+2;
19159a747e4fSDavid du Colombier 			if(n < m)
19169a747e4fSDavid du Colombier 				error(Eshortdraw);
19179a747e4fSDavid du Colombier 			nw = BGSHORT(a+2);
19189a747e4fSDavid du Colombier 			if(nw < 0)
19199a747e4fSDavid du Colombier 				error(Ebadarg);
19209a747e4fSDavid du Colombier 			if(nw == 0)
19219a747e4fSDavid du Colombier 				continue;
19229a747e4fSDavid du Colombier 			m += nw*4;
19239a747e4fSDavid du Colombier 			if(n < m)
19249a747e4fSDavid du Colombier 				error(Eshortdraw);
19259a747e4fSDavid du Colombier 			lp = malloc(nw*sizeof(Memimage*));
19269a747e4fSDavid du Colombier 			if(lp == 0)
19279a747e4fSDavid du Colombier 				error(Enomem);
19289a747e4fSDavid du Colombier 			if(waserror()){
19299a747e4fSDavid du Colombier 				free(lp);
19309a747e4fSDavid du Colombier 				nexterror();
19319a747e4fSDavid du Colombier 			}
19329a747e4fSDavid du Colombier 			for(j=0; j<nw; j++)
19339a747e4fSDavid du Colombier 				lp[j] = drawimage(client, a+1+1+2+j*4);
19349a747e4fSDavid du Colombier 			if(lp[0]->layer == 0)
19359a747e4fSDavid du Colombier 				error("images are not windows");
19369a747e4fSDavid du Colombier 			for(j=1; j<nw; j++)
19379a747e4fSDavid du Colombier 				if(lp[j]->layer->screen != lp[0]->layer->screen)
19389a747e4fSDavid du Colombier 					error("images not on same screen");
19399a747e4fSDavid du Colombier 			if(a[1])
19409a747e4fSDavid du Colombier 				memltofrontn(lp, nw);
19419a747e4fSDavid du Colombier 			else
19429a747e4fSDavid du Colombier 				memltorearn(lp, nw);
19439a747e4fSDavid du Colombier 			if(lp[0]->layer->screen->image->data == screenimage->data)
19449a747e4fSDavid du Colombier 				for(j=0; j<nw; j++)
19459a747e4fSDavid du Colombier 					addflush(lp[j]->layer->screenr);
19469a747e4fSDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1+1+2), 1);
19479a747e4fSDavid du Colombier 			drawrefreshscreen(ll, client);
19489a747e4fSDavid du Colombier 			poperror();
19499a747e4fSDavid du Colombier 			free(lp);
19509a747e4fSDavid du Colombier 			continue;
19519a747e4fSDavid du Colombier 
19529a747e4fSDavid du Colombier 		/* visible: 'v' */
19539a747e4fSDavid du Colombier 		case 'v':
19549a747e4fSDavid du Colombier 			printmesg(fmt="", a, 0);
19559a747e4fSDavid du Colombier 			m = 1;
19569a747e4fSDavid du Colombier 			drawflush();
19579a747e4fSDavid du Colombier 			continue;
19589a747e4fSDavid du Colombier 
19599a747e4fSDavid du Colombier 		/* write: 'y' id[4] R[4*4] data[x*1] */
19609a747e4fSDavid du Colombier 		/* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
19619a747e4fSDavid du Colombier 		case 'y':
19629a747e4fSDavid du Colombier 		case 'Y':
19639a747e4fSDavid du Colombier 			printmesg(fmt="LR", a, 0);
19649a747e4fSDavid du Colombier 		//	iprint("load %c\n", *a);
19659a747e4fSDavid du Colombier 			m = 1+4+4*4;
19669a747e4fSDavid du Colombier 			if(n < m)
19679a747e4fSDavid du Colombier 				error(Eshortdraw);
19689a747e4fSDavid du Colombier 			dstid = BGLONG(a+1);
19699a747e4fSDavid du Colombier 			dst = drawimage(client, a+1);
19709a747e4fSDavid du Colombier 			drawrectangle(&r, a+5);
19719a747e4fSDavid du Colombier 			if(!rectinrect(r, dst->r))
19729a747e4fSDavid du Colombier 				error(Ewriteoutside);
19739a747e4fSDavid du Colombier 			y = memload(dst, r, a+m, n-m, *a=='Y');
19749a747e4fSDavid du Colombier 			if(y < 0)
19759a747e4fSDavid du Colombier 				error("bad writeimage call");
19769a747e4fSDavid du Colombier 			dstflush(dstid, dst, r);
19779a747e4fSDavid du Colombier 			m += y;
19789a747e4fSDavid du Colombier 			continue;
19799a747e4fSDavid du Colombier 		}
19809a747e4fSDavid du Colombier 	}
19819a747e4fSDavid du Colombier 	poperror();
19829a747e4fSDavid du Colombier }
19839a747e4fSDavid du Colombier 
19849a747e4fSDavid du Colombier Dev drawdevtab = {
19859a747e4fSDavid du Colombier 	'i',
19869a747e4fSDavid du Colombier 	"draw",
19879a747e4fSDavid du Colombier 
19889a747e4fSDavid du Colombier 	devreset,
19899a747e4fSDavid du Colombier 	devinit,
19909a747e4fSDavid du Colombier 	drawattach,
19919a747e4fSDavid du Colombier 	drawwalk,
19929a747e4fSDavid du Colombier 	drawstat,
19939a747e4fSDavid du Colombier 	drawopen,
19949a747e4fSDavid du Colombier 	devcreate,
19959a747e4fSDavid du Colombier 	drawclose,
19969a747e4fSDavid du Colombier 	drawread,
19979a747e4fSDavid du Colombier 	devbread,
19989a747e4fSDavid du Colombier 	drawwrite,
19999a747e4fSDavid du Colombier 	devbwrite,
20009a747e4fSDavid du Colombier 	devremove,
20019a747e4fSDavid du Colombier 	devwstat,
20029a747e4fSDavid du Colombier };
20039a747e4fSDavid du Colombier 
20049a747e4fSDavid du Colombier /*
20059a747e4fSDavid du Colombier  * On 8 bit displays, load the default color map
20069a747e4fSDavid du Colombier  */
20079a747e4fSDavid du Colombier void
drawcmap(void)20089a747e4fSDavid du Colombier drawcmap(void)
20099a747e4fSDavid du Colombier {
20109a747e4fSDavid du Colombier 	int r, g, b, cr, cg, cb, v;
20119a747e4fSDavid du Colombier 	int num, den;
20129a747e4fSDavid du Colombier 	int i, j;
20139a747e4fSDavid du Colombier 
20149a747e4fSDavid du Colombier 	drawactive(1);	/* to restore map from backup */
20159a747e4fSDavid du Colombier 	for(r=0,i=0; r!=4; r++)
20169a747e4fSDavid du Colombier 	    for(v=0; v!=4; v++,i+=16){
20179a747e4fSDavid du Colombier 		for(g=0,j=v-r; g!=4; g++)
20189a747e4fSDavid du Colombier 		    for(b=0;b!=4;b++,j++){
20199a747e4fSDavid du Colombier 			den = r;
20209a747e4fSDavid du Colombier 			if(g > den)
20219a747e4fSDavid du Colombier 				den = g;
20229a747e4fSDavid du Colombier 			if(b > den)
20239a747e4fSDavid du Colombier 				den = b;
20249a747e4fSDavid du Colombier 			if(den == 0)	/* divide check -- pick grey shades */
20259a747e4fSDavid du Colombier 				cr = cg = cb = v*17;
20269a747e4fSDavid du Colombier 			else{
20279a747e4fSDavid du Colombier 				num = 17*(4*den+v);
20289a747e4fSDavid du Colombier 				cr = r*num/den;
20299a747e4fSDavid du Colombier 				cg = g*num/den;
20309a747e4fSDavid du Colombier 				cb = b*num/den;
20319a747e4fSDavid du Colombier 			}
20329a747e4fSDavid du Colombier 			setcolor(i+(j&15),
20339a747e4fSDavid du Colombier 				cr*0x01010101, cg*0x01010101, cb*0x01010101);
20349a747e4fSDavid du Colombier 		    }
20359a747e4fSDavid du Colombier 	}
20369a747e4fSDavid du Colombier }
20379a747e4fSDavid du Colombier 
20389a747e4fSDavid du Colombier void
drawblankscreen(int blank)20399a747e4fSDavid du Colombier drawblankscreen(int blank)
20409a747e4fSDavid du Colombier {
20419a747e4fSDavid du Colombier 	int i, nc;
20429a747e4fSDavid du Colombier 	ulong *p;
20439a747e4fSDavid du Colombier 
20449a747e4fSDavid du Colombier 	if(blank == sdraw.blanked)
20459a747e4fSDavid du Colombier 		return;
20469a747e4fSDavid du Colombier 	if(!canqlock(&sdraw))
20479a747e4fSDavid du Colombier 		return;
20489a747e4fSDavid du Colombier 	if(!initscreenimage()){
20499a747e4fSDavid du Colombier 		qunlock(&sdraw);
20509a747e4fSDavid du Colombier 		return;
20519a747e4fSDavid du Colombier 	}
20529a747e4fSDavid du Colombier 	p = sdraw.savemap;
20539a747e4fSDavid du Colombier 	nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
20549a747e4fSDavid du Colombier 
20559a747e4fSDavid du Colombier 	/*
20569a747e4fSDavid du Colombier 	 * blankscreen uses the hardware to blank the screen
20579a747e4fSDavid du Colombier 	 * when possible.  to help in cases when it is not possible,
20589a747e4fSDavid du Colombier 	 * we set the color map to be all black.
20599a747e4fSDavid du Colombier 	 */
20609a747e4fSDavid du Colombier 	if(blank == 0){	/* turn screen on */
20619a747e4fSDavid du Colombier 		for(i=0; i<nc; i++, p+=3)
20629a747e4fSDavid du Colombier 			setcolor(i, p[0], p[1], p[2]);
20639a747e4fSDavid du Colombier 		blankscreen(0);
20649a747e4fSDavid du Colombier 	}else{	/* turn screen off */
20659a747e4fSDavid du Colombier 		blankscreen(1);
20669a747e4fSDavid du Colombier 		for(i=0; i<nc; i++, p+=3){
20679a747e4fSDavid du Colombier 			getcolor(i, &p[0], &p[1], &p[2]);
20689a747e4fSDavid du Colombier 			setcolor(i, 0, 0, 0);
20699a747e4fSDavid du Colombier 		}
20709a747e4fSDavid du Colombier 	}
20719a747e4fSDavid du Colombier 	sdraw.blanked = blank;
20729a747e4fSDavid du Colombier 	qunlock(&sdraw);
20739a747e4fSDavid du Colombier }
20749a747e4fSDavid du Colombier 
20759a747e4fSDavid du Colombier /*
20769a747e4fSDavid du Colombier  * record activity on screen, changing blanking as appropriate
20779a747e4fSDavid du Colombier  */
20789a747e4fSDavid du Colombier void
drawactive(int active)20799a747e4fSDavid du Colombier drawactive(int active)
20809a747e4fSDavid du Colombier {
20819a747e4fSDavid du Colombier 	if(active){
20829a747e4fSDavid du Colombier 		drawblankscreen(0);
20839a747e4fSDavid du Colombier 		sdraw.blanktime = 0;
208422a127bbSDavid du Colombier 	}else
20859a747e4fSDavid du Colombier 		sdraw.blanktime++;
20869a747e4fSDavid du Colombier }
2087