xref: /plan9/sys/src/9/port/devdraw.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
17dd7cddfSDavid du Colombier #include	"u.h"
27dd7cddfSDavid du Colombier #include	"../port/lib.h"
37dd7cddfSDavid du Colombier #include	"mem.h"
47dd7cddfSDavid du Colombier #include	"dat.h"
57dd7cddfSDavid du Colombier #include	"fns.h"
67dd7cddfSDavid du Colombier #include	"../port/error.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #define	Image	IMAGE
97dd7cddfSDavid du Colombier #include	<draw.h>
107dd7cddfSDavid du Colombier #include	<memdraw.h>
117dd7cddfSDavid du Colombier #include	<memlayer.h>
127dd7cddfSDavid du Colombier #include	<cursor.h>
137dd7cddfSDavid du Colombier #include	"screen.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier enum
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	Qtopdir		= 0,
187dd7cddfSDavid du Colombier 	Qnew,
194de34a7eSDavid du Colombier 	Qwinname,
207dd7cddfSDavid du Colombier 	Q3rd,
217dd7cddfSDavid du Colombier 	Q2nd,
227dd7cddfSDavid du Colombier 	Qcolormap,
237dd7cddfSDavid du Colombier 	Qctl,
247dd7cddfSDavid du Colombier 	Qdata,
257dd7cddfSDavid du Colombier 	Qrefresh,
267dd7cddfSDavid du Colombier };
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier /*
297dd7cddfSDavid du Colombier  * Qid path is:
307dd7cddfSDavid du Colombier  *	 4 bits of file type (qids above)
317dd7cddfSDavid du Colombier  *	24 bits of mux slot number +1; 0 means not attached to client
327dd7cddfSDavid du Colombier  */
337dd7cddfSDavid du Colombier #define	QSHIFT	4	/* location in qid of client # */
347dd7cddfSDavid du Colombier 
359a747e4fSDavid du Colombier #define	QID(q)		((((ulong)(q).path)&0x0000000F)>>0)
369a747e4fSDavid du Colombier #define	CLIENTPATH(q)	((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
377dd7cddfSDavid du Colombier #define	CLIENT(q)	CLIENTPATH((q).path)
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier #define	NHASH		(1<<5)
407dd7cddfSDavid du Colombier #define	HASHMASK	(NHASH-1)
419a747e4fSDavid du Colombier #define	IOUNIT		(64*1024)
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier typedef struct Client Client;
447dd7cddfSDavid du Colombier typedef struct Draw Draw;
457dd7cddfSDavid du Colombier typedef struct DImage DImage;
467dd7cddfSDavid du Colombier typedef struct DScreen DScreen;
477dd7cddfSDavid du Colombier typedef struct CScreen CScreen;
487dd7cddfSDavid du Colombier typedef struct FChar FChar;
497dd7cddfSDavid du Colombier typedef struct Refresh Refresh;
507dd7cddfSDavid du Colombier typedef struct Refx Refx;
517dd7cddfSDavid du Colombier typedef struct DName DName;
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier ulong blanktime = 30;	/* in minutes; a half hour */
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier struct Draw
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier 	int		clientid;
587dd7cddfSDavid du Colombier 	int		nclient;
597dd7cddfSDavid du Colombier 	Client**	client;
607dd7cddfSDavid du Colombier 	int		nname;
617dd7cddfSDavid du Colombier 	DName*		name;
627dd7cddfSDavid du Colombier 	int		vers;
637dd7cddfSDavid du Colombier 	int		softscreen;
647dd7cddfSDavid du Colombier 	int		blanked;	/* screen turned off */
657dd7cddfSDavid du Colombier 	ulong		blanktime;	/* time of last operation */
667dd7cddfSDavid du Colombier 	ulong		savemap[3*256];
677dd7cddfSDavid du Colombier };
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier struct Client
707dd7cddfSDavid du Colombier {
717dd7cddfSDavid du Colombier 	Ref		r;
727dd7cddfSDavid du Colombier 	DImage*		dimage[NHASH];
737dd7cddfSDavid du Colombier 	CScreen*	cscreen;
747dd7cddfSDavid du Colombier 	Refresh*	refresh;
757dd7cddfSDavid du Colombier 	Rendez		refrend;
767dd7cddfSDavid du Colombier 	uchar*		readdata;
777dd7cddfSDavid du Colombier 	int		nreaddata;
787dd7cddfSDavid du Colombier 	int		busy;
797dd7cddfSDavid du Colombier 	int		clientid;
807dd7cddfSDavid du Colombier 	int		slot;
817dd7cddfSDavid du Colombier 	int		refreshme;
827dd7cddfSDavid du Colombier 	int		infoid;
836a9fc400SDavid du Colombier 	int		op;
847dd7cddfSDavid du Colombier };
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier struct Refresh
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier 	DImage*		dimage;
897dd7cddfSDavid du Colombier 	Rectangle	r;
907dd7cddfSDavid du Colombier 	Refresh*	next;
917dd7cddfSDavid du Colombier };
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier struct Refx
947dd7cddfSDavid du Colombier {
957dd7cddfSDavid du Colombier 	Client*		client;
967dd7cddfSDavid du Colombier 	DImage*		dimage;
977dd7cddfSDavid du Colombier };
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier struct DName
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier 	char		*name;
1027dd7cddfSDavid du Colombier 	Client		*client;
1037dd7cddfSDavid du Colombier 	DImage*		dimage;
1047dd7cddfSDavid du Colombier 	int		vers;
1057dd7cddfSDavid du Colombier };
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier struct FChar
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	int		minx;	/* left edge of bits */
1107dd7cddfSDavid du Colombier 	int		maxx;	/* right edge of bits */
1117dd7cddfSDavid du Colombier 	uchar		miny;	/* first non-zero scan-line */
1127dd7cddfSDavid du Colombier 	uchar		maxy;	/* last non-zero scan-line + 1 */
1137dd7cddfSDavid du Colombier 	schar		left;	/* offset of baseline */
1147dd7cddfSDavid du Colombier 	uchar		width;	/* width of baseline */
1157dd7cddfSDavid du Colombier };
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier /*
1187dd7cddfSDavid du Colombier  * Reference counts in DImages:
1197dd7cddfSDavid du Colombier  *	one per open by original client
1207dd7cddfSDavid du Colombier  *	one per screen image or fill
1217dd7cddfSDavid du Colombier  * 	one per image derived from this one by name
1227dd7cddfSDavid du Colombier  */
1237dd7cddfSDavid du Colombier struct DImage
1247dd7cddfSDavid du Colombier {
1257dd7cddfSDavid du Colombier 	int		id;
1267dd7cddfSDavid du Colombier 	int		ref;
1277dd7cddfSDavid du Colombier 	char		*name;
1287dd7cddfSDavid du Colombier 	int		vers;
1297dd7cddfSDavid du Colombier 	Memimage*	image;
1307dd7cddfSDavid du Colombier 	int		ascent;
1317dd7cddfSDavid du Colombier 	int		nfchar;
1327dd7cddfSDavid du Colombier 	FChar*		fchar;
1337dd7cddfSDavid du Colombier 	DScreen*	dscreen;	/* 0 if not a window */
1347dd7cddfSDavid du Colombier 	DImage*		fromname;	/* image this one is derived from, by name */
1357dd7cddfSDavid du Colombier 	DImage*		next;
1367dd7cddfSDavid du Colombier };
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier struct CScreen
1397dd7cddfSDavid du Colombier {
1407dd7cddfSDavid du Colombier 	DScreen*	dscreen;
1417dd7cddfSDavid du Colombier 	CScreen*	next;
1427dd7cddfSDavid du Colombier };
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier struct DScreen
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier 	int		id;
1477dd7cddfSDavid du Colombier 	int		public;
1487dd7cddfSDavid du Colombier 	int		ref;
1497dd7cddfSDavid du Colombier 	DImage		*dimage;
1507dd7cddfSDavid du Colombier 	DImage		*dfill;
1517dd7cddfSDavid du Colombier 	Memscreen*	screen;
1527dd7cddfSDavid du Colombier 	Client*		owner;
1537dd7cddfSDavid du Colombier 	DScreen*	next;
1547dd7cddfSDavid du Colombier };
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier static	Draw		sdraw;
1574de34a7eSDavid du Colombier 	QLock	drawlock;
1584de34a7eSDavid du Colombier 
1597dd7cddfSDavid du Colombier static	Memimage	*screenimage;
1604de34a7eSDavid du Colombier static	DImage*	screendimage;
1614de34a7eSDavid du Colombier static	char	screenname[40];
1624de34a7eSDavid du Colombier static	int	screennameid;
1634de34a7eSDavid du Colombier 
1647dd7cddfSDavid du Colombier static	Rectangle	flushrect;
1657dd7cddfSDavid du Colombier static	int		waste;
1667dd7cddfSDavid du Colombier static	DScreen*	dscreen;
1677dd7cddfSDavid du Colombier extern	void		flushmemscreen(Rectangle);
1687dd7cddfSDavid du Colombier 	void		drawmesg(Client*, void*, int);
1697dd7cddfSDavid du Colombier 	void		drawuninstall(Client*, int);
1707dd7cddfSDavid du Colombier 	void		drawfreedimage(DImage*);
1717dd7cddfSDavid du Colombier 	Client*		drawclientofpath(ulong);
1724de34a7eSDavid du Colombier 	DImage*	allocdimage(Memimage*);
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier static	char Enodrawimage[] =	"unknown id for draw image";
1757dd7cddfSDavid du Colombier static	char Enodrawscreen[] =	"unknown id for draw screen";
1767dd7cddfSDavid du Colombier static	char Eshortdraw[] =	"short draw message";
1777dd7cddfSDavid du Colombier static	char Eshortread[] =	"draw read too short";
1787dd7cddfSDavid du Colombier static	char Eimageexists[] =	"image id in use";
1797dd7cddfSDavid du Colombier static	char Escreenexists[] =	"screen id in use";
1807dd7cddfSDavid du Colombier static	char Edrawmem[] =	"image memory allocation failed";
1817dd7cddfSDavid du Colombier static	char Ereadoutside[] =	"readimage outside image";
1827dd7cddfSDavid du Colombier static	char Ewriteoutside[] =	"writeimage outside image";
1837dd7cddfSDavid du Colombier static	char Enotfont[] =	"image not a font";
1847dd7cddfSDavid du Colombier static	char Eindex[] =		"character index out of range";
1857dd7cddfSDavid du Colombier static	char Enoclient[] =	"no such draw client";
1867dd7cddfSDavid du Colombier static	char Edepth[] =		"image has bad depth";
1877dd7cddfSDavid du Colombier static	char Enameused[] =	"image name in use";
1887dd7cddfSDavid du Colombier static	char Enoname[] =	"no image with that name";
1897dd7cddfSDavid du Colombier static	char Eoldname[] =	"named image no longer valid";
1907dd7cddfSDavid du Colombier static	char Enamed[] = 	"image already has name";
1917dd7cddfSDavid du Colombier static	char Ewrongname[] = 	"wrong name for image";
1927dd7cddfSDavid du Colombier 
1934de34a7eSDavid du Colombier static void
dlock(void)1944de34a7eSDavid du Colombier dlock(void)
1954de34a7eSDavid du Colombier {
1964de34a7eSDavid du Colombier 	qlock(&drawlock);
1974de34a7eSDavid du Colombier }
1984de34a7eSDavid du Colombier 
1994de34a7eSDavid du Colombier static int
candlock(void)2004de34a7eSDavid du Colombier candlock(void)
2014de34a7eSDavid du Colombier {
2024de34a7eSDavid du Colombier 	return canqlock(&drawlock);
2034de34a7eSDavid du Colombier }
2044de34a7eSDavid du Colombier 
2054de34a7eSDavid du Colombier static void
dunlock(void)2064de34a7eSDavid du Colombier dunlock(void)
2074de34a7eSDavid du Colombier {
2084de34a7eSDavid du Colombier 	qunlock(&drawlock);
2094de34a7eSDavid du Colombier }
2104de34a7eSDavid du Colombier 
2117dd7cddfSDavid du Colombier static int
drawgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)2129a747e4fSDavid du Colombier drawgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
2137dd7cddfSDavid du Colombier {
2147dd7cddfSDavid du Colombier 	int t;
2157dd7cddfSDavid du Colombier 	Qid q;
2167dd7cddfSDavid du Colombier 	ulong path;
2177dd7cddfSDavid du Colombier 	Client *cl;
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	q.vers = 0;
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier 	if(s == DEVDOTDOT){
2227dd7cddfSDavid du Colombier 		switch(QID(c->qid)){
2237dd7cddfSDavid du Colombier 		case Qtopdir:
2247dd7cddfSDavid du Colombier 		case Q2nd:
2259a747e4fSDavid du Colombier 			mkqid(&q, Qtopdir, 0, QTDIR);
2269a747e4fSDavid du Colombier 			devdir(c, q, "#i", 0, eve, 0500, dp);
2277dd7cddfSDavid du Colombier 			break;
2287dd7cddfSDavid du Colombier 		case Q3rd:
2297dd7cddfSDavid du Colombier 			cl = drawclientofpath(c->qid.path);
2307dd7cddfSDavid du Colombier 			if(cl == nil)
2314e3613abSDavid du Colombier 				strncpy(up->genbuf, "??", sizeof up->genbuf);
2327dd7cddfSDavid du Colombier 			else
2334e3613abSDavid du Colombier 				snprint(up->genbuf, sizeof up->genbuf,
2344e3613abSDavid du Colombier 					"%d", cl->clientid);
2359a747e4fSDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
2369a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0500, dp);
2377dd7cddfSDavid du Colombier 			break;
2387dd7cddfSDavid du Colombier 		default:
2399a747e4fSDavid du Colombier 			panic("drawwalk %llux", c->qid.path);
2407dd7cddfSDavid du Colombier 		}
2417dd7cddfSDavid du Colombier 		return 1;
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	/*
2457dd7cddfSDavid du Colombier 	 * Top level directory contains the name of the device.
2467dd7cddfSDavid du Colombier 	 */
2479a747e4fSDavid du Colombier 	t = QID(c->qid);
2489a747e4fSDavid du Colombier 	if(t == Qtopdir){
2497dd7cddfSDavid du Colombier 		switch(s){
2507dd7cddfSDavid du Colombier 		case 0:
2519a747e4fSDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
2527dd7cddfSDavid du Colombier 			devdir(c, q, "draw", 0, eve, 0555, dp);
2537dd7cddfSDavid du Colombier 			break;
2544de34a7eSDavid du Colombier 		case 1:
255*6bbfed0dSDavid du Colombier 			mkqid(&q, Qwinname, 0, QTFILE);
2564de34a7eSDavid du Colombier 			devdir(c, q, "winname", 0, eve, 0444, dp);
2574de34a7eSDavid du Colombier 			break;
2587dd7cddfSDavid du Colombier 		default:
2597dd7cddfSDavid du Colombier 			return -1;
2607dd7cddfSDavid du Colombier 		}
2617dd7cddfSDavid du Colombier 		return 1;
2627dd7cddfSDavid du Colombier 	}
2637dd7cddfSDavid du Colombier 
264*6bbfed0dSDavid du Colombier 	if(t == Qwinname){
265*6bbfed0dSDavid du Colombier 		mkqid(&q, Qwinname, 0, QTFILE);
266*6bbfed0dSDavid du Colombier 		devdir(c, q, "winname", 0, eve, 0444, dp);
267*6bbfed0dSDavid du Colombier 		return 1;
268*6bbfed0dSDavid du Colombier 	}
269*6bbfed0dSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	/*
2717dd7cddfSDavid du Colombier 	 * Second level contains "new" plus all the clients.
2727dd7cddfSDavid du Colombier 	 */
2737dd7cddfSDavid du Colombier 	if(t == Q2nd || t == Qnew){
2747dd7cddfSDavid du Colombier 		if(s == 0){
2759a747e4fSDavid du Colombier 			mkqid(&q, Qnew, 0, QTFILE);
2769a747e4fSDavid du Colombier 			devdir(c, q, "new", 0, eve, 0666, dp);
2777dd7cddfSDavid du Colombier 		}
2787dd7cddfSDavid du Colombier 		else if(s <= sdraw.nclient){
2797dd7cddfSDavid du Colombier 			cl = sdraw.client[s-1];
2807dd7cddfSDavid du Colombier 			if(cl == 0)
2817dd7cddfSDavid du Colombier 				return 0;
2824e3613abSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "%d",
2834e3613abSDavid du Colombier 				cl->clientid);
2849a747e4fSDavid du Colombier 			mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
2859a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
2867dd7cddfSDavid du Colombier 			return 1;
2877dd7cddfSDavid du Colombier 		}
2887dd7cddfSDavid du Colombier 		else
2897dd7cddfSDavid du Colombier 			return -1;
2907dd7cddfSDavid du Colombier 		return 1;
2917dd7cddfSDavid du Colombier 	}
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	/*
2947dd7cddfSDavid du Colombier 	 * Third level.
2957dd7cddfSDavid du Colombier 	 */
2969a747e4fSDavid du Colombier 	path = c->qid.path&~((1<<QSHIFT)-1);	/* slot component */
2977dd7cddfSDavid du Colombier 	q.vers = c->qid.vers;
2989a747e4fSDavid du Colombier 	q.type = QTFILE;
2997dd7cddfSDavid du Colombier 	switch(s){
3007dd7cddfSDavid du Colombier 	case 0:
3019a747e4fSDavid du Colombier 		q.path = path|Qcolormap;
3027dd7cddfSDavid du Colombier 		devdir(c, q, "colormap", 0, eve, 0600, dp);
3037dd7cddfSDavid du Colombier 		break;
3047dd7cddfSDavid du Colombier 	case 1:
3059a747e4fSDavid du Colombier 		q.path = path|Qctl;
3067dd7cddfSDavid du Colombier 		devdir(c, q, "ctl", 0, eve, 0600, dp);
3077dd7cddfSDavid du Colombier 		break;
3087dd7cddfSDavid du Colombier 	case 2:
3099a747e4fSDavid du Colombier 		q.path = path|Qdata;
3107dd7cddfSDavid du Colombier 		devdir(c, q, "data", 0, eve, 0600, dp);
3117dd7cddfSDavid du Colombier 		break;
3127dd7cddfSDavid du Colombier 	case 3:
3139a747e4fSDavid du Colombier 		q.path = path|Qrefresh;
3147dd7cddfSDavid du Colombier 		devdir(c, q, "refresh", 0, eve, 0400, dp);
3157dd7cddfSDavid du Colombier 		break;
3167dd7cddfSDavid du Colombier 	default:
3177dd7cddfSDavid du Colombier 		return -1;
3187dd7cddfSDavid du Colombier 	}
3197dd7cddfSDavid du Colombier 	return 1;
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier static
3237dd7cddfSDavid du Colombier int
drawrefactive(void * a)3247dd7cddfSDavid du Colombier drawrefactive(void *a)
3257dd7cddfSDavid du Colombier {
3267dd7cddfSDavid du Colombier 	Client *c;
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 	c = a;
3297dd7cddfSDavid du Colombier 	return c->refreshme || c->refresh!=0;
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier static
3337dd7cddfSDavid du Colombier void
drawrefreshscreen(DImage * l,Client * client)3347dd7cddfSDavid du Colombier drawrefreshscreen(DImage *l, Client *client)
3357dd7cddfSDavid du Colombier {
3367dd7cddfSDavid du Colombier 	while(l != nil && l->dscreen == nil)
3377dd7cddfSDavid du Colombier 		l = l->fromname;
3387dd7cddfSDavid du Colombier 	if(l != nil && l->dscreen->owner != client)
3397dd7cddfSDavid du Colombier 		l->dscreen->owner->refreshme = 1;
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier static
3437dd7cddfSDavid du Colombier void
drawrefresh(Memimage *,Rectangle r,void * v)3449a747e4fSDavid du Colombier drawrefresh(Memimage*, Rectangle r, void *v)
3457dd7cddfSDavid du Colombier {
3467dd7cddfSDavid du Colombier 	Refx *x;
3477dd7cddfSDavid du Colombier 	DImage *d;
3487dd7cddfSDavid du Colombier 	Client *c;
3497dd7cddfSDavid du Colombier 	Refresh *ref;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 	if(v == 0)
3527dd7cddfSDavid du Colombier 		return;
3537dd7cddfSDavid du Colombier 	x = v;
3547dd7cddfSDavid du Colombier 	c = x->client;
3557dd7cddfSDavid du Colombier 	d = x->dimage;
3567dd7cddfSDavid du Colombier 	for(ref=c->refresh; ref; ref=ref->next)
3577dd7cddfSDavid du Colombier 		if(ref->dimage == d){
3587dd7cddfSDavid du Colombier 			combinerect(&ref->r, r);
3597dd7cddfSDavid du Colombier 			return;
3607dd7cddfSDavid du Colombier 		}
3617dd7cddfSDavid du Colombier 	ref = malloc(sizeof(Refresh));
3627dd7cddfSDavid du Colombier 	if(ref){
3637dd7cddfSDavid du Colombier 		ref->dimage = d;
3647dd7cddfSDavid du Colombier 		ref->r = r;
3657dd7cddfSDavid du Colombier 		ref->next = c->refresh;
3667dd7cddfSDavid du Colombier 		c->refresh = ref;
3677dd7cddfSDavid du Colombier 	}
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier static void
addflush(Rectangle r)3717dd7cddfSDavid du Colombier addflush(Rectangle r)
3727dd7cddfSDavid du Colombier {
3737dd7cddfSDavid du Colombier 	int abb, ar, anbb;
3747dd7cddfSDavid du Colombier 	Rectangle nbb;
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier 	if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
3777dd7cddfSDavid du Colombier 		return;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	if(flushrect.min.x >= flushrect.max.x){
3807dd7cddfSDavid du Colombier 		flushrect = r;
3817dd7cddfSDavid du Colombier 		waste = 0;
3827dd7cddfSDavid du Colombier 		return;
3837dd7cddfSDavid du Colombier 	}
3847dd7cddfSDavid du Colombier 	nbb = flushrect;
3857dd7cddfSDavid du Colombier 	combinerect(&nbb, r);
3867dd7cddfSDavid du Colombier 	ar = Dx(r)*Dy(r);
3877dd7cddfSDavid du Colombier 	abb = Dx(flushrect)*Dy(flushrect);
3887dd7cddfSDavid du Colombier 	anbb = Dx(nbb)*Dy(nbb);
3897dd7cddfSDavid du Colombier 	/*
3907dd7cddfSDavid du Colombier 	 * Area of new waste is area of new bb minus area of old bb,
3917dd7cddfSDavid du Colombier 	 * less the area of the new segment, which we assume is not waste.
3927dd7cddfSDavid du Colombier 	 * This could be negative, but that's OK.
3937dd7cddfSDavid du Colombier 	 */
3947dd7cddfSDavid du Colombier 	waste += anbb-abb - ar;
3957dd7cddfSDavid du Colombier 	if(waste < 0)
3967dd7cddfSDavid du Colombier 		waste = 0;
3977dd7cddfSDavid du Colombier 	/*
3987dd7cddfSDavid du Colombier 	 * absorb if:
3997dd7cddfSDavid du Colombier 	 *	total area is small
4007dd7cddfSDavid du Colombier 	 *	waste is less than half total area
4017dd7cddfSDavid du Colombier 	 * 	rectangles touch
4027dd7cddfSDavid du Colombier 	 */
4037dd7cddfSDavid du Colombier 	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
4047dd7cddfSDavid du Colombier 		flushrect = nbb;
4057dd7cddfSDavid du Colombier 		return;
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier 	/* emit current state */
4089a747e4fSDavid du Colombier 	if(flushrect.min.x < flushrect.max.x)
4097dd7cddfSDavid du Colombier 		flushmemscreen(flushrect);
4107dd7cddfSDavid du Colombier 	flushrect = r;
4117dd7cddfSDavid du Colombier 	waste = 0;
4127dd7cddfSDavid du Colombier }
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier static
4157dd7cddfSDavid du Colombier void
dstflush(int dstid,Memimage * dst,Rectangle r)4167dd7cddfSDavid du Colombier dstflush(int dstid, Memimage *dst, Rectangle r)
4177dd7cddfSDavid du Colombier {
4187dd7cddfSDavid du Colombier 	Memlayer *l;
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 	if(dstid == 0){
4217dd7cddfSDavid du Colombier 		combinerect(&flushrect, r);
4227dd7cddfSDavid du Colombier 		return;
4237dd7cddfSDavid du Colombier 	}
4246a9fc400SDavid du Colombier 	/* how can this happen? -rsc, dec 12 2002 */
4256a9fc400SDavid du Colombier 	if(dst == 0){
4266a9fc400SDavid du Colombier 		print("nil dstflush\n");
4276a9fc400SDavid du Colombier 		return;
4286a9fc400SDavid du Colombier 	}
4297dd7cddfSDavid du Colombier 	l = dst->layer;
4307dd7cddfSDavid du Colombier 	if(l == nil)
4317dd7cddfSDavid du Colombier 		return;
4327dd7cddfSDavid du Colombier 	do{
4337dd7cddfSDavid du Colombier 		if(l->screen->image->data != screenimage->data)
4347dd7cddfSDavid du Colombier 			return;
4357dd7cddfSDavid du Colombier 		r = rectaddpt(r, l->delta);
4367dd7cddfSDavid du Colombier 		l = l->screen->image->layer;
4377dd7cddfSDavid du Colombier 	}while(l);
4387dd7cddfSDavid du Colombier 	addflush(r);
4397dd7cddfSDavid du Colombier }
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier void
drawflush(void)4427dd7cddfSDavid du Colombier drawflush(void)
4437dd7cddfSDavid du Colombier {
4449a747e4fSDavid du Colombier 	if(flushrect.min.x < flushrect.max.x)
4457dd7cddfSDavid du Colombier 		flushmemscreen(flushrect);
4467dd7cddfSDavid du Colombier 	flushrect = Rect(10000, 10000, -10000, -10000);
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier static
4507dd7cddfSDavid du Colombier int
drawcmp(char * a,char * b,int n)4517dd7cddfSDavid du Colombier drawcmp(char *a, char *b, int n)
4527dd7cddfSDavid du Colombier {
4537dd7cddfSDavid du Colombier 	if(strlen(a) != n)
4547dd7cddfSDavid du Colombier 		return 1;
4557dd7cddfSDavid du Colombier 	return memcmp(a, b, n);
4567dd7cddfSDavid du Colombier }
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier DName*
drawlookupname(int n,char * str)4597dd7cddfSDavid du Colombier drawlookupname(int n, char *str)
4607dd7cddfSDavid du Colombier {
4617dd7cddfSDavid du Colombier 	DName *name, *ename;
4627dd7cddfSDavid du Colombier 
4637dd7cddfSDavid du Colombier 	name = sdraw.name;
4647dd7cddfSDavid du Colombier 	ename = &name[sdraw.nname];
4657dd7cddfSDavid du Colombier 	for(; name<ename; name++)
4667dd7cddfSDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
4677dd7cddfSDavid du Colombier 			return name;
4687dd7cddfSDavid du Colombier 	return 0;
4697dd7cddfSDavid du Colombier }
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier int
drawgoodname(DImage * d)4727dd7cddfSDavid du Colombier drawgoodname(DImage *d)
4737dd7cddfSDavid du Colombier {
4747dd7cddfSDavid du Colombier 	DName *n;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 	/* if window, validate the screen's own images */
4777dd7cddfSDavid du Colombier 	if(d->dscreen)
4787dd7cddfSDavid du Colombier 		if(drawgoodname(d->dscreen->dimage) == 0
4797dd7cddfSDavid du Colombier 		|| drawgoodname(d->dscreen->dfill) == 0)
4807dd7cddfSDavid du Colombier 			return 0;
4817dd7cddfSDavid du Colombier 	if(d->name == nil)
4827dd7cddfSDavid du Colombier 		return 1;
4837dd7cddfSDavid du Colombier 	n = drawlookupname(strlen(d->name), d->name);
4847dd7cddfSDavid du Colombier 	if(n==nil || n->vers!=d->vers)
4857dd7cddfSDavid du Colombier 		return 0;
4867dd7cddfSDavid du Colombier 	return 1;
4877dd7cddfSDavid du Colombier }
4887dd7cddfSDavid du Colombier 
4897dd7cddfSDavid du Colombier DImage*
drawlookup(Client * client,int id,int checkname)4907dd7cddfSDavid du Colombier drawlookup(Client *client, int id, int checkname)
4917dd7cddfSDavid du Colombier {
4927dd7cddfSDavid du Colombier 	DImage *d;
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier 	d = client->dimage[id&HASHMASK];
4957dd7cddfSDavid du Colombier 	while(d){
4967dd7cddfSDavid du Colombier 		if(d->id == id){
4977dd7cddfSDavid du Colombier 			if(checkname && !drawgoodname(d))
4987dd7cddfSDavid du Colombier 				error(Eoldname);
4997dd7cddfSDavid du Colombier 			return d;
5007dd7cddfSDavid du Colombier 		}
5017dd7cddfSDavid du Colombier 		d = d->next;
5027dd7cddfSDavid du Colombier 	}
5037dd7cddfSDavid du Colombier 	return 0;
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier DScreen*
drawlookupdscreen(int id)5077dd7cddfSDavid du Colombier drawlookupdscreen(int id)
5087dd7cddfSDavid du Colombier {
5097dd7cddfSDavid du Colombier 	DScreen *s;
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier 	s = dscreen;
5127dd7cddfSDavid du Colombier 	while(s){
5137dd7cddfSDavid du Colombier 		if(s->id == id)
5147dd7cddfSDavid du Colombier 			return s;
5157dd7cddfSDavid du Colombier 		s = s->next;
5167dd7cddfSDavid du Colombier 	}
5177dd7cddfSDavid du Colombier 	return 0;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier 
5207dd7cddfSDavid du Colombier DScreen*
drawlookupscreen(Client * client,int id,CScreen ** cs)5217dd7cddfSDavid du Colombier drawlookupscreen(Client *client, int id, CScreen **cs)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier 	CScreen *s;
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier 	s = client->cscreen;
5267dd7cddfSDavid du Colombier 	while(s){
5277dd7cddfSDavid du Colombier 		if(s->dscreen->id == id){
5287dd7cddfSDavid du Colombier 			*cs = s;
5297dd7cddfSDavid du Colombier 			return s->dscreen;
5307dd7cddfSDavid du Colombier 		}
5317dd7cddfSDavid du Colombier 		s = s->next;
5327dd7cddfSDavid du Colombier 	}
5337dd7cddfSDavid du Colombier 	error(Enodrawscreen);
5347dd7cddfSDavid du Colombier 	return 0;
5357dd7cddfSDavid du Colombier }
5367dd7cddfSDavid du Colombier 
5374de34a7eSDavid du Colombier DImage*
allocdimage(Memimage * i)5384de34a7eSDavid du Colombier allocdimage(Memimage *i)
5397dd7cddfSDavid du Colombier {
5407dd7cddfSDavid du Colombier 	DImage *d;
5417dd7cddfSDavid du Colombier 
5427dd7cddfSDavid du Colombier 	d = malloc(sizeof(DImage));
5437dd7cddfSDavid du Colombier 	if(d == 0)
5447dd7cddfSDavid du Colombier 		return 0;
5457dd7cddfSDavid du Colombier 	d->ref = 1;
5467dd7cddfSDavid du Colombier 	d->name = 0;
5477dd7cddfSDavid du Colombier 	d->vers = 0;
5487dd7cddfSDavid du Colombier 	d->image = i;
5497dd7cddfSDavid du Colombier 	d->nfchar = 0;
5507dd7cddfSDavid du Colombier 	d->fchar = 0;
5517dd7cddfSDavid du Colombier 	d->fromname = 0;
5524de34a7eSDavid du Colombier 	return d;
5534de34a7eSDavid du Colombier }
5544de34a7eSDavid du Colombier 
5554de34a7eSDavid du Colombier Memimage*
drawinstall(Client * client,int id,Memimage * i,DScreen * dscreen)5564de34a7eSDavid du Colombier drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
5574de34a7eSDavid du Colombier {
5584de34a7eSDavid du Colombier 	DImage *d;
5594de34a7eSDavid du Colombier 
5604de34a7eSDavid du Colombier 	d = allocdimage(i);
5614de34a7eSDavid du Colombier 	if(d == 0)
5624de34a7eSDavid du Colombier 		return 0;
5634de34a7eSDavid du Colombier 	d->id = id;
5647dd7cddfSDavid du Colombier 	d->dscreen = dscreen;
5657dd7cddfSDavid du Colombier 	d->next = client->dimage[id&HASHMASK];
5667dd7cddfSDavid du Colombier 	client->dimage[id&HASHMASK] = d;
5677dd7cddfSDavid du Colombier 	return i;
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier Memscreen*
drawinstallscreen(Client * client,DScreen * d,int id,DImage * dimage,DImage * dfill,int public)5717dd7cddfSDavid du Colombier drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
5727dd7cddfSDavid du Colombier {
5737dd7cddfSDavid du Colombier 	Memscreen *s;
5747dd7cddfSDavid du Colombier 	CScreen *c;
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier 	c = malloc(sizeof(CScreen));
5777dd7cddfSDavid du Colombier 	if(dimage && dimage->image && dimage->image->chan == 0)
5787dd7cddfSDavid du Colombier 		panic("bad image %p in drawinstallscreen", dimage->image);
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier 	if(c == 0)
5817dd7cddfSDavid du Colombier 		return 0;
5827dd7cddfSDavid du Colombier 	if(d == 0){
5837dd7cddfSDavid du Colombier 		d = malloc(sizeof(DScreen));
5847dd7cddfSDavid du Colombier 		if(d == 0){
5857dd7cddfSDavid du Colombier 			free(c);
5867dd7cddfSDavid du Colombier 			return 0;
5877dd7cddfSDavid du Colombier 		}
5887dd7cddfSDavid du Colombier 		s = malloc(sizeof(Memscreen));
5897dd7cddfSDavid du Colombier 		if(s == 0){
5907dd7cddfSDavid du Colombier 			free(c);
5917dd7cddfSDavid du Colombier 			free(d);
5927dd7cddfSDavid du Colombier 			return 0;
5937dd7cddfSDavid du Colombier 		}
5947dd7cddfSDavid du Colombier 		s->frontmost = 0;
5957dd7cddfSDavid du Colombier 		s->rearmost = 0;
5967dd7cddfSDavid du Colombier 		d->dimage = dimage;
5977dd7cddfSDavid du Colombier 		if(dimage){
5987dd7cddfSDavid du Colombier 			s->image = dimage->image;
5997dd7cddfSDavid du Colombier 			dimage->ref++;
6007dd7cddfSDavid du Colombier 		}
6017dd7cddfSDavid du Colombier 		d->dfill = dfill;
6027dd7cddfSDavid du Colombier 		if(dfill){
6037dd7cddfSDavid du Colombier 			s->fill = dfill->image;
6047dd7cddfSDavid du Colombier 			dfill->ref++;
6057dd7cddfSDavid du Colombier 		}
6067dd7cddfSDavid du Colombier 		d->ref = 0;
6077dd7cddfSDavid du Colombier 		d->id = id;
6087dd7cddfSDavid du Colombier 		d->screen = s;
6097dd7cddfSDavid du Colombier 		d->public = public;
6107dd7cddfSDavid du Colombier 		d->next = dscreen;
6117dd7cddfSDavid du Colombier 		d->owner = client;
6127dd7cddfSDavid du Colombier 		dscreen = d;
6137dd7cddfSDavid du Colombier 	}
6147dd7cddfSDavid du Colombier 	c->dscreen = d;
6157dd7cddfSDavid du Colombier 	d->ref++;
6167dd7cddfSDavid du Colombier 	c->next = client->cscreen;
6177dd7cddfSDavid du Colombier 	client->cscreen = c;
6187dd7cddfSDavid du Colombier 	return d->screen;
6197dd7cddfSDavid du Colombier }
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier void
drawdelname(DName * name)6227dd7cddfSDavid du Colombier drawdelname(DName *name)
6237dd7cddfSDavid du Colombier {
6247dd7cddfSDavid du Colombier 	int i;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	i = name-sdraw.name;
6277dd7cddfSDavid du Colombier 	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
6287dd7cddfSDavid du Colombier 	sdraw.nname--;
6297dd7cddfSDavid du Colombier }
6307dd7cddfSDavid du Colombier 
6317dd7cddfSDavid du Colombier void
drawfreedscreen(DScreen * this)6327dd7cddfSDavid du Colombier drawfreedscreen(DScreen *this)
6337dd7cddfSDavid du Colombier {
6347dd7cddfSDavid du Colombier 	DScreen *ds, *next;
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier 	this->ref--;
6377dd7cddfSDavid du Colombier 	if(this->ref < 0)
6387dd7cddfSDavid du Colombier 		print("negative ref in drawfreedscreen\n");
6397dd7cddfSDavid du Colombier 	if(this->ref > 0)
6407dd7cddfSDavid du Colombier 		return;
6417dd7cddfSDavid du Colombier 	ds = dscreen;
6427dd7cddfSDavid du Colombier 	if(ds == this){
6437dd7cddfSDavid du Colombier 		dscreen = this->next;
6447dd7cddfSDavid du Colombier 		goto Found;
6457dd7cddfSDavid du Colombier 	}
6467dd7cddfSDavid du Colombier 	while(next = ds->next){	/* assign = */
6477dd7cddfSDavid du Colombier 		if(next == this){
6487dd7cddfSDavid du Colombier 			ds->next = this->next;
6497dd7cddfSDavid du Colombier 			goto Found;
6507dd7cddfSDavid du Colombier 		}
6517dd7cddfSDavid du Colombier 		ds = next;
6527dd7cddfSDavid du Colombier 	}
6537dd7cddfSDavid du Colombier 	error(Enodrawimage);
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier     Found:
6567dd7cddfSDavid du Colombier 	if(this->dimage)
6577dd7cddfSDavid du Colombier 		drawfreedimage(this->dimage);
6587dd7cddfSDavid du Colombier 	if(this->dfill)
6597dd7cddfSDavid du Colombier 		drawfreedimage(this->dfill);
6607dd7cddfSDavid du Colombier 	free(this->screen);
6617dd7cddfSDavid du Colombier 	free(this);
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier 
6647dd7cddfSDavid du Colombier void
drawfreedimage(DImage * dimage)6657dd7cddfSDavid du Colombier drawfreedimage(DImage *dimage)
6667dd7cddfSDavid du Colombier {
6677dd7cddfSDavid du Colombier 	int i;
6687dd7cddfSDavid du Colombier 	Memimage *l;
6697dd7cddfSDavid du Colombier 	DScreen *ds;
6707dd7cddfSDavid du Colombier 
6717dd7cddfSDavid du Colombier 	dimage->ref--;
6727dd7cddfSDavid du Colombier 	if(dimage->ref < 0)
6737dd7cddfSDavid du Colombier 		print("negative ref in drawfreedimage\n");
6747dd7cddfSDavid du Colombier 	if(dimage->ref > 0)
6757dd7cddfSDavid du Colombier 		return;
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier 	/* any names? */
6787dd7cddfSDavid du Colombier 	for(i=0; i<sdraw.nname; )
6797dd7cddfSDavid du Colombier 		if(sdraw.name[i].dimage == dimage)
6807dd7cddfSDavid du Colombier 			drawdelname(sdraw.name+i);
6817dd7cddfSDavid du Colombier 		else
6827dd7cddfSDavid du Colombier 			i++;
6837dd7cddfSDavid du Colombier 	if(dimage->fromname){	/* acquired by name; owned by someone else*/
6847dd7cddfSDavid du Colombier 		drawfreedimage(dimage->fromname);
6857dd7cddfSDavid du Colombier 		goto Return;
6867dd7cddfSDavid du Colombier 	}
6874de34a7eSDavid du Colombier //	if(dimage->image == screenimage)	/* don't free the display */
6884de34a7eSDavid du Colombier //		goto Return;
6897dd7cddfSDavid du Colombier 	ds = dimage->dscreen;
6907dd7cddfSDavid du Colombier 	if(ds){
6917dd7cddfSDavid du Colombier 		l = dimage->image;
6927dd7cddfSDavid du Colombier 		if(l->data == screenimage->data)
6937dd7cddfSDavid du Colombier 			addflush(l->layer->screenr);
6947dd7cddfSDavid du Colombier 		if(l->layer->refreshfn == drawrefresh)	/* else true owner will clean up */
6957dd7cddfSDavid du Colombier 			free(l->layer->refreshptr);
6967dd7cddfSDavid du Colombier 		l->layer->refreshptr = nil;
6977dd7cddfSDavid du Colombier 		if(drawgoodname(dimage))
6987dd7cddfSDavid du Colombier 			memldelete(l);
6997dd7cddfSDavid du Colombier 		else
7007dd7cddfSDavid du Colombier 			memlfree(l);
7017dd7cddfSDavid du Colombier 		drawfreedscreen(ds);
7027dd7cddfSDavid du Colombier 	}else
7037dd7cddfSDavid du Colombier 		freememimage(dimage->image);
7047dd7cddfSDavid du Colombier     Return:
7057dd7cddfSDavid du Colombier 	free(dimage->fchar);
7067dd7cddfSDavid du Colombier 	free(dimage);
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier 
7097dd7cddfSDavid du Colombier void
drawuninstallscreen(Client * client,CScreen * this)7107dd7cddfSDavid du Colombier drawuninstallscreen(Client *client, CScreen *this)
7117dd7cddfSDavid du Colombier {
7127dd7cddfSDavid du Colombier 	CScreen *cs, *next;
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier 	cs = client->cscreen;
7157dd7cddfSDavid du Colombier 	if(cs == this){
7167dd7cddfSDavid du Colombier 		client->cscreen = this->next;
7177dd7cddfSDavid du Colombier 		drawfreedscreen(this->dscreen);
7187dd7cddfSDavid du Colombier 		free(this);
7197dd7cddfSDavid du Colombier 		return;
7207dd7cddfSDavid du Colombier 	}
7217dd7cddfSDavid du Colombier 	while(next = cs->next){	/* assign = */
7227dd7cddfSDavid du Colombier 		if(next == this){
7237dd7cddfSDavid du Colombier 			cs->next = this->next;
7247dd7cddfSDavid du Colombier 			drawfreedscreen(this->dscreen);
7257dd7cddfSDavid du Colombier 			free(this);
7267dd7cddfSDavid du Colombier 			return;
7277dd7cddfSDavid du Colombier 		}
7287dd7cddfSDavid du Colombier 		cs = next;
7297dd7cddfSDavid du Colombier 	}
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier 
7327dd7cddfSDavid du Colombier void
drawuninstall(Client * client,int id)7337dd7cddfSDavid du Colombier drawuninstall(Client *client, int id)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier 	DImage *d, *next;
7367dd7cddfSDavid du Colombier 
7377dd7cddfSDavid du Colombier 	d = client->dimage[id&HASHMASK];
7387dd7cddfSDavid du Colombier 	if(d == 0)
7397dd7cddfSDavid du Colombier 		error(Enodrawimage);
7407dd7cddfSDavid du Colombier 	if(d->id == id){
7417dd7cddfSDavid du Colombier 		client->dimage[id&HASHMASK] = d->next;
7427dd7cddfSDavid du Colombier 		drawfreedimage(d);
7437dd7cddfSDavid du Colombier 		return;
7447dd7cddfSDavid du Colombier 	}
7457dd7cddfSDavid du Colombier 	while(next = d->next){	/* assign = */
7467dd7cddfSDavid du Colombier 		if(next->id == id){
7477dd7cddfSDavid du Colombier 			d->next = next->next;
7487dd7cddfSDavid du Colombier 			drawfreedimage(next);
7497dd7cddfSDavid du Colombier 			return;
7507dd7cddfSDavid du Colombier 		}
7517dd7cddfSDavid du Colombier 		d = next;
7527dd7cddfSDavid du Colombier 	}
7537dd7cddfSDavid du Colombier 	error(Enodrawimage);
7547dd7cddfSDavid du Colombier }
7557dd7cddfSDavid du Colombier 
7567dd7cddfSDavid du Colombier void
drawaddname(Client * client,DImage * di,int n,char * str)7577dd7cddfSDavid du Colombier drawaddname(Client *client, DImage *di, int n, char *str)
7587dd7cddfSDavid du Colombier {
7597dd7cddfSDavid du Colombier 	DName *name, *ename, *new, *t;
7607dd7cddfSDavid du Colombier 
7617dd7cddfSDavid du Colombier 	name = sdraw.name;
7627dd7cddfSDavid du Colombier 	ename = &name[sdraw.nname];
7637dd7cddfSDavid du Colombier 	for(; name<ename; name++)
7647dd7cddfSDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
7657dd7cddfSDavid du Colombier 			error(Enameused);
7667dd7cddfSDavid du Colombier 	t = smalloc((sdraw.nname+1)*sizeof(DName));
7677dd7cddfSDavid du Colombier 	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
7687dd7cddfSDavid du Colombier 	free(sdraw.name);
7697dd7cddfSDavid du Colombier 	sdraw.name = t;
7707dd7cddfSDavid du Colombier 	new = &sdraw.name[sdraw.nname++];
7717dd7cddfSDavid du Colombier 	new->name = smalloc(n+1);
7727dd7cddfSDavid du Colombier 	memmove(new->name, str, n);
7737dd7cddfSDavid du Colombier 	new->name[n] = 0;
7747dd7cddfSDavid du Colombier 	new->dimage = di;
7757dd7cddfSDavid du Colombier 	new->client = client;
7767dd7cddfSDavid du Colombier 	new->vers = ++sdraw.vers;
7777dd7cddfSDavid du Colombier }
7787dd7cddfSDavid du Colombier 
7797dd7cddfSDavid du Colombier Client*
drawnewclient(void)7807dd7cddfSDavid du Colombier drawnewclient(void)
7817dd7cddfSDavid du Colombier {
7827dd7cddfSDavid du Colombier 	Client *cl, **cp;
7837dd7cddfSDavid du Colombier 	int i;
7847dd7cddfSDavid du Colombier 
7857dd7cddfSDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
7867dd7cddfSDavid du Colombier 		cl = sdraw.client[i];
7877dd7cddfSDavid du Colombier 		if(cl == 0)
7887dd7cddfSDavid du Colombier 			break;
7897dd7cddfSDavid du Colombier 	}
7907dd7cddfSDavid du Colombier 	if(i == sdraw.nclient){
7917dd7cddfSDavid du Colombier 		cp = malloc((sdraw.nclient+1)*sizeof(Client*));
7927dd7cddfSDavid du Colombier 		if(cp == 0)
7937dd7cddfSDavid du Colombier 			return 0;
7947dd7cddfSDavid du Colombier 		memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
7957dd7cddfSDavid du Colombier 		free(sdraw.client);
7967dd7cddfSDavid du Colombier 		sdraw.client = cp;
7977dd7cddfSDavid du Colombier 		sdraw.nclient++;
7987dd7cddfSDavid du Colombier 		cp[i] = 0;
7997dd7cddfSDavid du Colombier 	}
8007dd7cddfSDavid du Colombier 	cl = malloc(sizeof(Client));
8017dd7cddfSDavid du Colombier 	if(cl == 0)
8027dd7cddfSDavid du Colombier 		return 0;
8037dd7cddfSDavid du Colombier 	memset(cl, 0, sizeof(Client));
8047dd7cddfSDavid du Colombier 	cl->slot = i;
8057dd7cddfSDavid du Colombier 	cl->clientid = ++sdraw.clientid;
8066a9fc400SDavid du Colombier 	cl->op = SoverD;
8077dd7cddfSDavid du Colombier 	sdraw.client[i] = cl;
8087dd7cddfSDavid du Colombier 	return cl;
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier 
8116a9fc400SDavid du Colombier static int
drawclientop(Client * cl)8126a9fc400SDavid du Colombier drawclientop(Client *cl)
8136a9fc400SDavid du Colombier {
8146a9fc400SDavid du Colombier 	int op;
8156a9fc400SDavid du Colombier 
8166a9fc400SDavid du Colombier 	op = cl->op;
8176a9fc400SDavid du Colombier 	cl->op = SoverD;
8186a9fc400SDavid du Colombier 	return op;
8196a9fc400SDavid du Colombier }
8206a9fc400SDavid du Colombier 
8217dd7cddfSDavid du Colombier int
drawhasclients(void)8227dd7cddfSDavid du Colombier drawhasclients(void)
8237dd7cddfSDavid du Colombier {
824223a736eSDavid du Colombier 	/*
825223a736eSDavid du Colombier 	 * if draw has ever been used, we can't resize the frame buffer,
826223a736eSDavid du Colombier 	 * even if all clients have exited (nclients is cumulative); it's too
827223a736eSDavid du Colombier 	 * hard to make work.
828223a736eSDavid du Colombier 	 */
8297dd7cddfSDavid du Colombier 	return sdraw.nclient != 0;
8307dd7cddfSDavid du Colombier }
8317dd7cddfSDavid du Colombier 
8327dd7cddfSDavid du Colombier Client*
drawclientofpath(ulong path)8337dd7cddfSDavid du Colombier drawclientofpath(ulong path)
8347dd7cddfSDavid du Colombier {
8357dd7cddfSDavid du Colombier 	Client *cl;
8367dd7cddfSDavid du Colombier 	int slot;
8377dd7cddfSDavid du Colombier 
8387dd7cddfSDavid du Colombier 	slot = CLIENTPATH(path);
8397dd7cddfSDavid du Colombier 	if(slot == 0)
8407dd7cddfSDavid du Colombier 		return nil;
8417dd7cddfSDavid du Colombier 	cl = sdraw.client[slot-1];
8427dd7cddfSDavid du Colombier 	if(cl==0 || cl->clientid==0)
8437dd7cddfSDavid du Colombier 		return nil;
8447dd7cddfSDavid du Colombier 	return cl;
8457dd7cddfSDavid du Colombier }
8467dd7cddfSDavid du Colombier 
8477dd7cddfSDavid du Colombier 
8487dd7cddfSDavid du Colombier Client*
drawclient(Chan * c)8497dd7cddfSDavid du Colombier drawclient(Chan *c)
8507dd7cddfSDavid du Colombier {
8517dd7cddfSDavid du Colombier 	Client *client;
8527dd7cddfSDavid du Colombier 
8537dd7cddfSDavid du Colombier 	client = drawclientofpath(c->qid.path);
8547dd7cddfSDavid du Colombier 	if(client == nil)
8557dd7cddfSDavid du Colombier 		error(Enoclient);
8567dd7cddfSDavid du Colombier 	return client;
8577dd7cddfSDavid du Colombier }
8587dd7cddfSDavid du Colombier 
8597dd7cddfSDavid du Colombier Memimage*
drawimage(Client * client,uchar * a)8607dd7cddfSDavid du Colombier drawimage(Client *client, uchar *a)
8617dd7cddfSDavid du Colombier {
8627dd7cddfSDavid du Colombier 	DImage *d;
8637dd7cddfSDavid du Colombier 
8647dd7cddfSDavid du Colombier 	d = drawlookup(client, BGLONG(a), 1);
8657dd7cddfSDavid du Colombier 	if(d == nil)
8667dd7cddfSDavid du Colombier 		error(Enodrawimage);
8677dd7cddfSDavid du Colombier 	return d->image;
8687dd7cddfSDavid du Colombier }
8697dd7cddfSDavid du Colombier 
8707dd7cddfSDavid du Colombier void
drawrectangle(Rectangle * r,uchar * a)8717dd7cddfSDavid du Colombier drawrectangle(Rectangle *r, uchar *a)
8727dd7cddfSDavid du Colombier {
8737dd7cddfSDavid du Colombier 	r->min.x = BGLONG(a+0*4);
8747dd7cddfSDavid du Colombier 	r->min.y = BGLONG(a+1*4);
8757dd7cddfSDavid du Colombier 	r->max.x = BGLONG(a+2*4);
8767dd7cddfSDavid du Colombier 	r->max.y = BGLONG(a+3*4);
8777dd7cddfSDavid du Colombier }
8787dd7cddfSDavid du Colombier 
8797dd7cddfSDavid du Colombier void
drawpoint(Point * p,uchar * a)8807dd7cddfSDavid du Colombier drawpoint(Point *p, uchar *a)
8817dd7cddfSDavid du Colombier {
8827dd7cddfSDavid du Colombier 	p->x = BGLONG(a+0*4);
8837dd7cddfSDavid du Colombier 	p->y = BGLONG(a+1*4);
8847dd7cddfSDavid du Colombier }
8857dd7cddfSDavid du Colombier 
8867dd7cddfSDavid du Colombier Point
drawchar(Memimage * dst,Memimage * rdst,Point p,Memimage * src,Point * sp,DImage * font,int index,int op)8871ee3cffaSDavid du Colombier drawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
8887dd7cddfSDavid du Colombier {
8897dd7cddfSDavid du Colombier 	FChar *fc;
8907dd7cddfSDavid du Colombier 	Rectangle r;
8917dd7cddfSDavid du Colombier 	Point sp1;
8921ee3cffaSDavid du Colombier 	static Memimage *tmp;
8937dd7cddfSDavid du Colombier 
8947dd7cddfSDavid du Colombier 	fc = &font->fchar[index];
8957dd7cddfSDavid du Colombier 	r.min.x = p.x+fc->left;
8967dd7cddfSDavid du Colombier 	r.min.y = p.y-(font->ascent-fc->miny);
8977dd7cddfSDavid du Colombier 	r.max.x = r.min.x+(fc->maxx-fc->minx);
8987dd7cddfSDavid du Colombier 	r.max.y = r.min.y+(fc->maxy-fc->miny);
8997dd7cddfSDavid du Colombier 	sp1.x = sp->x+fc->left;
9007dd7cddfSDavid du Colombier 	sp1.y = sp->y+fc->miny;
9011ee3cffaSDavid du Colombier 
9021ee3cffaSDavid du Colombier 	/*
9031ee3cffaSDavid du Colombier 	 * If we're drawing greyscale fonts onto a VGA screen,
9041ee3cffaSDavid du Colombier 	 * it's very costly to read the screen memory to do the
9051ee3cffaSDavid du Colombier 	 * alpha blending inside memdraw.  If this is really a stringbg,
9061ee3cffaSDavid du Colombier 	 * then rdst is the bg image (in main memory) which we can
9071ee3cffaSDavid du Colombier 	 * refer to for the underlying dst pixels instead of reading dst
9081ee3cffaSDavid du Colombier 	 * directly.
9091ee3cffaSDavid du Colombier 	 */
9101ee3cffaSDavid du Colombier 	if(ishwimage(dst) && !ishwimage(rdst) && font->image->depth > 1){
9111ee3cffaSDavid du Colombier 		if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){
9121ee3cffaSDavid du Colombier 			if(tmp)
9131ee3cffaSDavid du Colombier 				freememimage(tmp);
9141ee3cffaSDavid du Colombier 			tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);
9151ee3cffaSDavid du Colombier 			if(tmp == nil)
9161ee3cffaSDavid du Colombier 				goto fallback;
9171ee3cffaSDavid du Colombier 		}
9181ee3cffaSDavid du Colombier 		memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);
9191ee3cffaSDavid du Colombier 		memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);
9201ee3cffaSDavid du Colombier 		memdraw(dst, r, tmp, ZP, memopaque, ZP, S);
9211ee3cffaSDavid du Colombier 	}else{
9221ee3cffaSDavid du Colombier 	fallback:
9236a9fc400SDavid du Colombier 		memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
9241ee3cffaSDavid du Colombier 	}
9251ee3cffaSDavid du Colombier 
9267dd7cddfSDavid du Colombier 	p.x += fc->width;
9277dd7cddfSDavid du Colombier 	sp->x += fc->width;
9287dd7cddfSDavid du Colombier 	return p;
9297dd7cddfSDavid du Colombier }
9307dd7cddfSDavid du Colombier 
9314de34a7eSDavid du Colombier static DImage*
makescreenimage(void)9324de34a7eSDavid du Colombier makescreenimage(void)
9337dd7cddfSDavid du Colombier {
9347dd7cddfSDavid du Colombier 	int width, depth;
9357dd7cddfSDavid du Colombier 	ulong chan;
9364de34a7eSDavid du Colombier 	DImage *di;
9374de34a7eSDavid du Colombier 	Memdata *md;
9384de34a7eSDavid du Colombier 	Memimage *i;
9397dd7cddfSDavid du Colombier 	Rectangle r;
9407dd7cddfSDavid du Colombier 
9414de34a7eSDavid du Colombier 	md = malloc(sizeof *md);
9424de34a7eSDavid du Colombier 	if(md == nil)
9434de34a7eSDavid du Colombier 		return nil;
9444de34a7eSDavid du Colombier 	md->allocd = 1;
9454de34a7eSDavid du Colombier 	md->base = nil;
9464de34a7eSDavid du Colombier 	md->bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen);
9474de34a7eSDavid du Colombier 	if(md->bdata == nil){
9484de34a7eSDavid du Colombier 		free(md);
9494de34a7eSDavid du Colombier 		return nil;
9504de34a7eSDavid du Colombier 	}
9514de34a7eSDavid du Colombier 	md->ref = 1;
9524de34a7eSDavid du Colombier 	i = allocmemimaged(r, chan, md);
9534de34a7eSDavid du Colombier 	if(i == nil){
9544de34a7eSDavid du Colombier 		free(md);
9554de34a7eSDavid du Colombier 		return nil;
9564de34a7eSDavid du Colombier 	}
9574de34a7eSDavid du Colombier 	i->width = width;
9584de34a7eSDavid du Colombier 	i->clipr = r;
9594de34a7eSDavid du Colombier 
9604de34a7eSDavid du Colombier 	di = allocdimage(i);
9614de34a7eSDavid du Colombier 	if(di == nil){
9624de34a7eSDavid du Colombier 		freememimage(i);	/* frees md */
9634de34a7eSDavid du Colombier 		return nil;
9644de34a7eSDavid du Colombier 	}
9654de34a7eSDavid du Colombier 	if(!waserror()){
9664de34a7eSDavid du Colombier 		snprint(screenname, sizeof screenname, "noborder.screen.%d", ++screennameid);
9674de34a7eSDavid du Colombier 		drawaddname(nil, di, strlen(screenname), screenname);
9684de34a7eSDavid du Colombier 		poperror();
9694de34a7eSDavid du Colombier 	}
9704de34a7eSDavid du Colombier 	return di;
9714de34a7eSDavid du Colombier }
9724de34a7eSDavid du Colombier 
9734de34a7eSDavid du Colombier static int
initscreenimage(void)9744de34a7eSDavid du Colombier initscreenimage(void)
9754de34a7eSDavid du Colombier {
9767dd7cddfSDavid du Colombier 	if(screenimage != nil)
9777dd7cddfSDavid du Colombier 		return 1;
9787dd7cddfSDavid du Colombier 
9794de34a7eSDavid du Colombier 	screendimage = makescreenimage();
9804de34a7eSDavid du Colombier 	if(screendimage == nil)
9817dd7cddfSDavid du Colombier 		return 0;
9824de34a7eSDavid du Colombier 	screenimage = screendimage->image;
9834de34a7eSDavid du Colombier // iprint("initscreenimage %p %p\n", screendimage, screenimage);
9844de34a7eSDavid du Colombier 	mouseresize();
9857dd7cddfSDavid du Colombier 	return 1;
9867dd7cddfSDavid du Colombier }
9877dd7cddfSDavid du Colombier 
9887dd7cddfSDavid du Colombier void
deletescreenimage(void)9897dd7cddfSDavid du Colombier deletescreenimage(void)
9907dd7cddfSDavid du Colombier {
9914de34a7eSDavid du Colombier 	dlock();
9924de34a7eSDavid du Colombier 	if(screenimage){
9934de34a7eSDavid du Colombier 		/* will be freed via screendimage; disable */
9944de34a7eSDavid du Colombier 		screenimage->clipr = ZR;
9957dd7cddfSDavid du Colombier 		screenimage = nil;
9964de34a7eSDavid du Colombier 	}
9974de34a7eSDavid du Colombier 	if(screendimage){
9984de34a7eSDavid du Colombier 		drawfreedimage(screendimage);
9994de34a7eSDavid du Colombier 		screendimage = nil;
10004de34a7eSDavid du Colombier 	}
10014de34a7eSDavid du Colombier 	dunlock();
10024de34a7eSDavid du Colombier }
10034de34a7eSDavid du Colombier 
10044de34a7eSDavid du Colombier void
resetscreenimage(void)10054de34a7eSDavid du Colombier resetscreenimage(void)
10064de34a7eSDavid du Colombier {
10074de34a7eSDavid du Colombier 	dlock();
10084de34a7eSDavid du Colombier 	initscreenimage();
10094de34a7eSDavid du Colombier 	dunlock();
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier 
10126a9fc400SDavid du Colombier static Chan*
drawattach(char * spec)10137dd7cddfSDavid du Colombier drawattach(char *spec)
10147dd7cddfSDavid du Colombier {
10154de34a7eSDavid du Colombier 	dlock();
10167dd7cddfSDavid du Colombier 	if(!initscreenimage()){
10174de34a7eSDavid du Colombier 		dunlock();
10187dd7cddfSDavid du Colombier 		error("no frame buffer");
10197dd7cddfSDavid du Colombier 	}
10204de34a7eSDavid du Colombier 	dunlock();
10217dd7cddfSDavid du Colombier 	return devattach('i', spec);
10227dd7cddfSDavid du Colombier }
10237dd7cddfSDavid du Colombier 
10246a9fc400SDavid du Colombier static Walkqid*
drawwalk(Chan * c,Chan * nc,char ** name,int nname)10259a747e4fSDavid du Colombier drawwalk(Chan *c, Chan *nc, char **name, int nname)
10267dd7cddfSDavid du Colombier {
10274de34a7eSDavid du Colombier 	if(screenimage == nil)
10287dd7cddfSDavid du Colombier 		error("no frame buffer");
10299a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, drawgen);
10307dd7cddfSDavid du Colombier }
10317dd7cddfSDavid du Colombier 
10329a747e4fSDavid du Colombier static int
drawstat(Chan * c,uchar * db,int n)10339a747e4fSDavid du Colombier drawstat(Chan *c, uchar *db, int n)
10347dd7cddfSDavid du Colombier {
10359a747e4fSDavid du Colombier 	return devstat(c, db, n, 0, 0, drawgen);
10367dd7cddfSDavid du Colombier }
10377dd7cddfSDavid du Colombier 
10387dd7cddfSDavid du Colombier static Chan*
drawopen(Chan * c,int omode)10397dd7cddfSDavid du Colombier drawopen(Chan *c, int omode)
10407dd7cddfSDavid du Colombier {
10417dd7cddfSDavid du Colombier 	Client *cl;
10424de34a7eSDavid du Colombier 	DName *dn;
10434de34a7eSDavid du Colombier 	DImage *di;
10447dd7cddfSDavid du Colombier 
10459a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR){
10469a747e4fSDavid du Colombier 		c = devopen(c, omode, 0, 0, drawgen);
10479a747e4fSDavid du Colombier 		c->iounit = IOUNIT;
10489a747e4fSDavid du Colombier 	}
10497dd7cddfSDavid du Colombier 
10504de34a7eSDavid du Colombier 	dlock();
10517dd7cddfSDavid du Colombier 	if(waserror()){
10524de34a7eSDavid du Colombier 		dunlock();
10537dd7cddfSDavid du Colombier 		nexterror();
10547dd7cddfSDavid du Colombier 	}
10557dd7cddfSDavid du Colombier 
10567dd7cddfSDavid du Colombier 	if(QID(c->qid) == Qnew){
10577dd7cddfSDavid du Colombier 		cl = drawnewclient();
10587dd7cddfSDavid du Colombier 		if(cl == 0)
10597dd7cddfSDavid du Colombier 			error(Enodev);
10607dd7cddfSDavid du Colombier 		c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
10617dd7cddfSDavid du Colombier 	}
10627dd7cddfSDavid du Colombier 
10637dd7cddfSDavid du Colombier 	switch(QID(c->qid)){
10644de34a7eSDavid du Colombier 	case Qwinname:
10654de34a7eSDavid du Colombier 		break;
10664de34a7eSDavid du Colombier 
10677dd7cddfSDavid du Colombier 	case Qnew:
10687dd7cddfSDavid du Colombier 		break;
10697dd7cddfSDavid du Colombier 
10707dd7cddfSDavid du Colombier 	case Qctl:
10717dd7cddfSDavid du Colombier 		cl = drawclient(c);
10727dd7cddfSDavid du Colombier 		if(cl->busy)
10737dd7cddfSDavid du Colombier 			error(Einuse);
10747dd7cddfSDavid du Colombier 		cl->busy = 1;
10757dd7cddfSDavid du Colombier 		flushrect = Rect(10000, 10000, -10000, -10000);
10764de34a7eSDavid du Colombier 		dn = drawlookupname(strlen(screenname), screenname);
10774de34a7eSDavid du Colombier 		if(dn == 0)
10784de34a7eSDavid du Colombier 			error("draw: cannot happen 2");
10794de34a7eSDavid du Colombier 		if(drawinstall(cl, 0, dn->dimage->image, 0) == 0)
10804de34a7eSDavid du Colombier 			error(Edrawmem);
10814de34a7eSDavid du Colombier 		di = drawlookup(cl, 0, 0);
10824de34a7eSDavid du Colombier 		if(di == 0)
10834de34a7eSDavid du Colombier 			error("draw: cannot happen 1");
10844de34a7eSDavid du Colombier 		di->vers = dn->vers;
10854de34a7eSDavid du Colombier 		di->name = smalloc(strlen(screenname)+1);
10864de34a7eSDavid du Colombier 		strcpy(di->name, screenname);
10874de34a7eSDavid du Colombier 		di->fromname = dn->dimage;
10884de34a7eSDavid du Colombier 		di->fromname->ref++;
10897dd7cddfSDavid du Colombier 		incref(&cl->r);
10907dd7cddfSDavid du Colombier 		break;
10914de34a7eSDavid du Colombier 
10927dd7cddfSDavid du Colombier 	case Qcolormap:
10937dd7cddfSDavid du Colombier 	case Qdata:
10947dd7cddfSDavid du Colombier 	case Qrefresh:
10957dd7cddfSDavid du Colombier 		cl = drawclient(c);
10967dd7cddfSDavid du Colombier 		incref(&cl->r);
10977dd7cddfSDavid du Colombier 		break;
10987dd7cddfSDavid du Colombier 	}
10994de34a7eSDavid du Colombier 	dunlock();
11007dd7cddfSDavid du Colombier 	poperror();
11017dd7cddfSDavid du Colombier 	c->mode = openmode(omode);
11027dd7cddfSDavid du Colombier 	c->flag |= COPEN;
11037dd7cddfSDavid du Colombier 	c->offset = 0;
11049a747e4fSDavid du Colombier 	c->iounit = IOUNIT;
11057dd7cddfSDavid du Colombier 	return c;
11067dd7cddfSDavid du Colombier }
11077dd7cddfSDavid du Colombier 
11087dd7cddfSDavid du Colombier static void
drawclose(Chan * c)11097dd7cddfSDavid du Colombier drawclose(Chan *c)
11107dd7cddfSDavid du Colombier {
11117dd7cddfSDavid du Colombier 	int i;
11127dd7cddfSDavid du Colombier 	DImage *d, **dp;
11137dd7cddfSDavid du Colombier 	Client *cl;
11147dd7cddfSDavid du Colombier 	Refresh *r;
11157dd7cddfSDavid du Colombier 
11169a747e4fSDavid du Colombier 	if(QID(c->qid) < Qcolormap)	/* Qtopdir, Qnew, Q3rd, Q2nd have no client */
11177dd7cddfSDavid du Colombier 		return;
11184de34a7eSDavid du Colombier 	dlock();
11197dd7cddfSDavid du Colombier 	if(waserror()){
11204de34a7eSDavid du Colombier 		dunlock();
11217dd7cddfSDavid du Colombier 		nexterror();
11227dd7cddfSDavid du Colombier 	}
11237dd7cddfSDavid du Colombier 
11247dd7cddfSDavid du Colombier 	cl = drawclient(c);
11257dd7cddfSDavid du Colombier 	if(QID(c->qid) == Qctl)
11267dd7cddfSDavid du Colombier 		cl->busy = 0;
11277dd7cddfSDavid du Colombier 	if((c->flag&COPEN) && (decref(&cl->r)==0)){
11287dd7cddfSDavid du Colombier 		while(r = cl->refresh){	/* assign = */
11297dd7cddfSDavid du Colombier 			cl->refresh = r->next;
11307dd7cddfSDavid du Colombier 			free(r);
11317dd7cddfSDavid du Colombier 		}
11327dd7cddfSDavid du Colombier 		/* free names */
11337dd7cddfSDavid du Colombier 		for(i=0; i<sdraw.nname; )
11347dd7cddfSDavid du Colombier 			if(sdraw.name[i].client == cl)
11357dd7cddfSDavid du Colombier 				drawdelname(sdraw.name+i);
11367dd7cddfSDavid du Colombier 			else
11377dd7cddfSDavid du Colombier 				i++;
11387dd7cddfSDavid du Colombier 		while(cl->cscreen)
11397dd7cddfSDavid du Colombier 			drawuninstallscreen(cl, cl->cscreen);
11407dd7cddfSDavid du Colombier 		/* all screens are freed, so now we can free images */
11417dd7cddfSDavid du Colombier 		dp = cl->dimage;
11427dd7cddfSDavid du Colombier 		for(i=0; i<NHASH; i++){
11437dd7cddfSDavid du Colombier 			while((d = *dp) != nil){
11447dd7cddfSDavid du Colombier 				*dp = d->next;
11457dd7cddfSDavid du Colombier 				drawfreedimage(d);
11467dd7cddfSDavid du Colombier 			}
11477dd7cddfSDavid du Colombier 			dp++;
11487dd7cddfSDavid du Colombier 		}
11497dd7cddfSDavid du Colombier 		sdraw.client[cl->slot] = 0;
11507dd7cddfSDavid du Colombier 		drawflush();	/* to erase visible, now dead windows */
11517dd7cddfSDavid du Colombier 		free(cl);
11527dd7cddfSDavid du Colombier 	}
11534de34a7eSDavid du Colombier 	dunlock();
11547dd7cddfSDavid du Colombier 	poperror();
11557dd7cddfSDavid du Colombier }
11567dd7cddfSDavid du Colombier 
11577dd7cddfSDavid du Colombier long
drawread(Chan * c,void * a,long n,vlong off)11587dd7cddfSDavid du Colombier drawread(Chan *c, void *a, long n, vlong off)
11597dd7cddfSDavid du Colombier {
11607dd7cddfSDavid du Colombier 	int index, m;
11617dd7cddfSDavid du Colombier 	ulong red, green, blue;
11627dd7cddfSDavid du Colombier 	Client *cl;
11637dd7cddfSDavid du Colombier 	uchar *p;
11647dd7cddfSDavid du Colombier 	Refresh *r;
11657dd7cddfSDavid du Colombier 	DImage *di;
11667dd7cddfSDavid du Colombier 	Memimage *i;
11677dd7cddfSDavid du Colombier 	ulong offset = off;
11687dd7cddfSDavid du Colombier 	char buf[16];
11697dd7cddfSDavid du Colombier 
11709a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
11717dd7cddfSDavid du Colombier 		return devdirread(c, a, n, 0, 0, drawgen);
11724de34a7eSDavid du Colombier 	if(QID(c->qid) == Qwinname)
11734de34a7eSDavid du Colombier 		return readstr(off, a, n, screenname);
11744de34a7eSDavid du Colombier 
11757dd7cddfSDavid du Colombier 	cl = drawclient(c);
11764de34a7eSDavid du Colombier 	dlock();
11777dd7cddfSDavid du Colombier 	if(waserror()){
11784de34a7eSDavid du Colombier 		dunlock();
11797dd7cddfSDavid du Colombier 		nexterror();
11807dd7cddfSDavid du Colombier 	}
11817dd7cddfSDavid du Colombier 	switch(QID(c->qid)){
11827dd7cddfSDavid du Colombier 	case Qctl:
11837dd7cddfSDavid du Colombier 		if(n < 12*12)
11847dd7cddfSDavid du Colombier 			error(Eshortread);
11857dd7cddfSDavid du Colombier 		if(cl->infoid < 0)
11867dd7cddfSDavid du Colombier 			error(Enodrawimage);
11877dd7cddfSDavid du Colombier 		if(cl->infoid == 0){
11887dd7cddfSDavid du Colombier 			i = screenimage;
11897dd7cddfSDavid du Colombier 			if(i == nil)
11907dd7cddfSDavid du Colombier 				error(Enodrawimage);
11917dd7cddfSDavid du Colombier 		}else{
11927dd7cddfSDavid du Colombier 			di = drawlookup(cl, cl->infoid, 1);
11937dd7cddfSDavid du Colombier 			if(di == nil)
11947dd7cddfSDavid du Colombier 				error(Enodrawimage);
11957dd7cddfSDavid du Colombier 			i = di->image;
11967dd7cddfSDavid du Colombier 		}
11974e3613abSDavid du Colombier 		n = snprint(a, n,
11984e3613abSDavid du Colombier 			"%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
11994e3613abSDavid du Colombier 			cl->clientid, cl->infoid, chantostr(buf, i->chan),
12004e3613abSDavid du Colombier 			(i->flags&Frepl)==Frepl,
12017dd7cddfSDavid du Colombier 			i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
12024e3613abSDavid du Colombier 			i->clipr.min.x, i->clipr.min.y, i->clipr.max.x,
12034e3613abSDavid du Colombier 			i->clipr.max.y);
12047dd7cddfSDavid du Colombier 		cl->infoid = -1;
12057dd7cddfSDavid du Colombier 		break;
12067dd7cddfSDavid du Colombier 
12077dd7cddfSDavid du Colombier 	case Qcolormap:
12087dd7cddfSDavid du Colombier 		drawactive(1);	/* to restore map from backup */
12097dd7cddfSDavid du Colombier 		p = malloc(4*12*256+1);
12107dd7cddfSDavid du Colombier 		if(p == 0)
12117dd7cddfSDavid du Colombier 			error(Enomem);
12127dd7cddfSDavid du Colombier 		m = 0;
12137dd7cddfSDavid du Colombier 		for(index = 0; index < 256; index++){
12147dd7cddfSDavid du Colombier 			getcolor(index, &red, &green, &blue);
12154e3613abSDavid du Colombier 			m += snprint((char*)p+m, 4*12*256+1 - m,
12164e3613abSDavid du Colombier 				"%11d %11lud %11lud %11lud\n", index,
12174e3613abSDavid du Colombier 				red>>24, green>>24, blue>>24);
12187dd7cddfSDavid du Colombier 		}
12197dd7cddfSDavid du Colombier 		n = readstr(offset, a, n, (char*)p);
12207dd7cddfSDavid du Colombier 		free(p);
12217dd7cddfSDavid du Colombier 		break;
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier 	case Qdata:
12247dd7cddfSDavid du Colombier 		if(cl->readdata == nil)
12257dd7cddfSDavid du Colombier 			error("no draw data");
12267dd7cddfSDavid du Colombier 		if(n < cl->nreaddata)
12277dd7cddfSDavid du Colombier 			error(Eshortread);
12287dd7cddfSDavid du Colombier 		n = cl->nreaddata;
12297dd7cddfSDavid du Colombier 		memmove(a, cl->readdata, cl->nreaddata);
12307dd7cddfSDavid du Colombier 		free(cl->readdata);
12317dd7cddfSDavid du Colombier 		cl->readdata = nil;
12327dd7cddfSDavid du Colombier 		break;
12337dd7cddfSDavid du Colombier 
12347dd7cddfSDavid du Colombier 	case Qrefresh:
12357dd7cddfSDavid du Colombier 		if(n < 5*4)
12367dd7cddfSDavid du Colombier 			error(Ebadarg);
12377dd7cddfSDavid du Colombier 		for(;;){
12387dd7cddfSDavid du Colombier 			if(cl->refreshme || cl->refresh)
12397dd7cddfSDavid du Colombier 				break;
12404de34a7eSDavid du Colombier 			dunlock();
12417dd7cddfSDavid du Colombier 			if(waserror()){
12424de34a7eSDavid du Colombier 				dlock();	/* restore lock for waserror() above */
12437dd7cddfSDavid du Colombier 				nexterror();
12447dd7cddfSDavid du Colombier 			}
12457dd7cddfSDavid du Colombier 			sleep(&cl->refrend, drawrefactive, cl);
12467dd7cddfSDavid du Colombier 			poperror();
12474de34a7eSDavid du Colombier 			dlock();
12487dd7cddfSDavid du Colombier 		}
12497dd7cddfSDavid du Colombier 		p = a;
12507dd7cddfSDavid du Colombier 		while(cl->refresh && n>=5*4){
12517dd7cddfSDavid du Colombier 			r = cl->refresh;
12527dd7cddfSDavid du Colombier 			BPLONG(p+0*4, r->dimage->id);
12537dd7cddfSDavid du Colombier 			BPLONG(p+1*4, r->r.min.x);
12547dd7cddfSDavid du Colombier 			BPLONG(p+2*4, r->r.min.y);
12557dd7cddfSDavid du Colombier 			BPLONG(p+3*4, r->r.max.x);
12567dd7cddfSDavid du Colombier 			BPLONG(p+4*4, r->r.max.y);
12577dd7cddfSDavid du Colombier 			cl->refresh = r->next;
12587dd7cddfSDavid du Colombier 			free(r);
12597dd7cddfSDavid du Colombier 			p += 5*4;
12607dd7cddfSDavid du Colombier 			n -= 5*4;
12617dd7cddfSDavid du Colombier 		}
12627dd7cddfSDavid du Colombier 		cl->refreshme = 0;
12637dd7cddfSDavid du Colombier 		n = p-(uchar*)a;
12644de34a7eSDavid du Colombier 		break;
12657dd7cddfSDavid du Colombier 	}
12664de34a7eSDavid du Colombier 	dunlock();
12677dd7cddfSDavid du Colombier 	poperror();
12687dd7cddfSDavid du Colombier 	return n;
12697dd7cddfSDavid du Colombier }
12707dd7cddfSDavid du Colombier 
12717dd7cddfSDavid du Colombier void
drawwakeall(void)12727dd7cddfSDavid du Colombier drawwakeall(void)
12737dd7cddfSDavid du Colombier {
12747dd7cddfSDavid du Colombier 	Client *cl;
12757dd7cddfSDavid du Colombier 	int i;
12767dd7cddfSDavid du Colombier 
12777dd7cddfSDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
12787dd7cddfSDavid du Colombier 		cl = sdraw.client[i];
12797dd7cddfSDavid du Colombier 		if(cl && (cl->refreshme || cl->refresh))
12807dd7cddfSDavid du Colombier 			wakeup(&cl->refrend);
12817dd7cddfSDavid du Colombier 	}
12827dd7cddfSDavid du Colombier }
12837dd7cddfSDavid du Colombier 
12847dd7cddfSDavid du Colombier static long
drawwrite(Chan * c,void * a,long n,vlong)12859a747e4fSDavid du Colombier drawwrite(Chan *c, void *a, long n, vlong)
12867dd7cddfSDavid du Colombier {
12877dd7cddfSDavid du Colombier 	char buf[128], *fields[4], *q;
12887dd7cddfSDavid du Colombier 	Client *cl;
12897dd7cddfSDavid du Colombier 	int i, m, red, green, blue, x;
12907dd7cddfSDavid du Colombier 
12919a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
12927dd7cddfSDavid du Colombier 		error(Eisdir);
12937dd7cddfSDavid du Colombier 	cl = drawclient(c);
12944de34a7eSDavid du Colombier 	dlock();
12957dd7cddfSDavid du Colombier 	if(waserror()){
12967dd7cddfSDavid du Colombier 		drawwakeall();
12974de34a7eSDavid du Colombier 		dunlock();
12987dd7cddfSDavid du Colombier 		nexterror();
12997dd7cddfSDavid du Colombier 	}
13007dd7cddfSDavid du Colombier 	switch(QID(c->qid)){
13017dd7cddfSDavid du Colombier 	case Qctl:
13027dd7cddfSDavid du Colombier 		if(n != 4)
13037dd7cddfSDavid du Colombier 			error("unknown draw control request");
13047dd7cddfSDavid du Colombier 		cl->infoid = BGLONG((uchar*)a);
13057dd7cddfSDavid du Colombier 		break;
13067dd7cddfSDavid du Colombier 
13077dd7cddfSDavid du Colombier 	case Qcolormap:
13087dd7cddfSDavid du Colombier 		drawactive(1);	/* to restore map from backup */
13097dd7cddfSDavid du Colombier 		m = n;
13107dd7cddfSDavid du Colombier 		n = 0;
13117dd7cddfSDavid du Colombier 		while(m > 0){
13127dd7cddfSDavid du Colombier 			x = m;
13137dd7cddfSDavid du Colombier 			if(x > sizeof(buf)-1)
13147dd7cddfSDavid du Colombier 				x = sizeof(buf)-1;
13157dd7cddfSDavid du Colombier 			q = memccpy(buf, a, '\n', x);
13167dd7cddfSDavid du Colombier 			if(q == 0)
13177dd7cddfSDavid du Colombier 				break;
13187dd7cddfSDavid du Colombier 			i = q-buf;
13197dd7cddfSDavid du Colombier 			n += i;
13207dd7cddfSDavid du Colombier 			a = (char*)a + i;
13217dd7cddfSDavid du Colombier 			m -= i;
13227dd7cddfSDavid du Colombier 			*q = 0;
13239a747e4fSDavid du Colombier 			if(tokenize(buf, fields, nelem(fields)) != 4)
13247dd7cddfSDavid du Colombier 				error(Ebadarg);
13257dd7cddfSDavid du Colombier 			i = strtoul(fields[0], 0, 0);
13267dd7cddfSDavid du Colombier 			red = strtoul(fields[1], 0, 0);
13277dd7cddfSDavid du Colombier 			green = strtoul(fields[2], 0, 0);
13287dd7cddfSDavid du Colombier 			blue = strtoul(fields[3], &q, 0);
13297dd7cddfSDavid du Colombier 			if(fields[3] == q)
13307dd7cddfSDavid du Colombier 				error(Ebadarg);
13317dd7cddfSDavid du Colombier 			if(red>255 || green>255 || blue>255 || i<0 || i>255)
13327dd7cddfSDavid du Colombier 				error(Ebadarg);
13337dd7cddfSDavid du Colombier 			red |= red<<8;
13347dd7cddfSDavid du Colombier 			red |= red<<16;
13357dd7cddfSDavid du Colombier 			green |= green<<8;
13367dd7cddfSDavid du Colombier 			green |= green<<16;
13377dd7cddfSDavid du Colombier 			blue |= blue<<8;
13387dd7cddfSDavid du Colombier 			blue |= blue<<16;
13397dd7cddfSDavid du Colombier 			setcolor(i, red, green, blue);
13407dd7cddfSDavid du Colombier 		}
13417dd7cddfSDavid du Colombier 		break;
13427dd7cddfSDavid du Colombier 
13437dd7cddfSDavid du Colombier 	case Qdata:
13447dd7cddfSDavid du Colombier 		drawmesg(cl, a, n);
13457dd7cddfSDavid du Colombier 		drawwakeall();
13467dd7cddfSDavid du Colombier 		break;
13477dd7cddfSDavid du Colombier 
13487dd7cddfSDavid du Colombier 	default:
13497dd7cddfSDavid du Colombier 		error(Ebadusefd);
13507dd7cddfSDavid du Colombier 	}
13514de34a7eSDavid du Colombier 	dunlock();
13527dd7cddfSDavid du Colombier 	poperror();
13537dd7cddfSDavid du Colombier 	return n;
13547dd7cddfSDavid du Colombier }
13557dd7cddfSDavid du Colombier 
13567dd7cddfSDavid du Colombier uchar*
drawcoord(uchar * p,uchar * maxp,int oldx,int * newx)13577dd7cddfSDavid du Colombier drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
13587dd7cddfSDavid du Colombier {
13597dd7cddfSDavid du Colombier 	int b, x;
13607dd7cddfSDavid du Colombier 
13617dd7cddfSDavid du Colombier 	if(p >= maxp)
13627dd7cddfSDavid du Colombier 		error(Eshortdraw);
13637dd7cddfSDavid du Colombier 	b = *p++;
13647dd7cddfSDavid du Colombier 	x = b & 0x7F;
13657dd7cddfSDavid du Colombier 	if(b & 0x80){
13667dd7cddfSDavid du Colombier 		if(p+1 >= maxp)
13677dd7cddfSDavid du Colombier 			error(Eshortdraw);
13687dd7cddfSDavid du Colombier 		x |= *p++ << 7;
13697dd7cddfSDavid du Colombier 		x |= *p++ << 15;
13707dd7cddfSDavid du Colombier 		if(x & (1<<22))
13717dd7cddfSDavid du Colombier 			x |= ~0<<23;
13727dd7cddfSDavid du Colombier 	}else{
13737dd7cddfSDavid du Colombier 		if(b & 0x40)
13747dd7cddfSDavid du Colombier 			x |= ~0<<7;
13757dd7cddfSDavid du Colombier 		x += oldx;
13767dd7cddfSDavid du Colombier 	}
13777dd7cddfSDavid du Colombier 	*newx = x;
13787dd7cddfSDavid du Colombier 	return p;
13797dd7cddfSDavid du Colombier }
13807dd7cddfSDavid du Colombier 
13817dd7cddfSDavid du Colombier static void
printmesg(char * fmt,uchar * a,int plsprnt)13827dd7cddfSDavid du Colombier printmesg(char *fmt, uchar *a, int plsprnt)
13837dd7cddfSDavid du Colombier {
13847dd7cddfSDavid du Colombier 	char buf[256];
13857dd7cddfSDavid du Colombier 	char *p, *q;
13864e3613abSDavid du Colombier 	int s, left;
13877dd7cddfSDavid du Colombier 
13887dd7cddfSDavid du Colombier 	if(1|| plsprnt==0){
13897dd7cddfSDavid du Colombier 		SET(s,q,p);
13907dd7cddfSDavid du Colombier 		USED(fmt, a, buf, p, q, s);
13917dd7cddfSDavid du Colombier 		return;
13927dd7cddfSDavid du Colombier 	}
13937dd7cddfSDavid du Colombier 	q = buf;
13947dd7cddfSDavid du Colombier 	*q++ = *a++;
13957dd7cddfSDavid du Colombier 	for(p=fmt; *p; p++){
13964e3613abSDavid du Colombier 		left = sizeof buf - 2 - (q - buf);	/* 2 for \n\0 */
13977dd7cddfSDavid du Colombier 		switch(*p){
13987dd7cddfSDavid du Colombier 		case 'l':
13994e3613abSDavid du Colombier 			q += snprint(q, left, " %ld", (long)BGLONG(a));
14007dd7cddfSDavid du Colombier 			a += 4;
14017dd7cddfSDavid du Colombier 			break;
14027dd7cddfSDavid du Colombier 		case 'L':
14034e3613abSDavid du Colombier 			q += snprint(q, left, " %.8lux", (ulong)BGLONG(a));
14047dd7cddfSDavid du Colombier 			a += 4;
14057dd7cddfSDavid du Colombier 			break;
14067dd7cddfSDavid du Colombier 		case 'R':
14074e3613abSDavid du Colombier 			q += snprint(q, left, " [%d %d %d %d]", BGLONG(a),
14084e3613abSDavid du Colombier 				BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
14097dd7cddfSDavid du Colombier 			a += 16;
14107dd7cddfSDavid du Colombier 			break;
14117dd7cddfSDavid du Colombier 		case 'P':
14124e3613abSDavid du Colombier 			q += snprint(q, left, " [%d %d]", BGLONG(a), BGLONG(a+4));
14137dd7cddfSDavid du Colombier 			a += 8;
14147dd7cddfSDavid du Colombier 			break;
14157dd7cddfSDavid du Colombier 		case 'b':
14164e3613abSDavid du Colombier 			q += snprint(q, left, " %d", *a++);
14177dd7cddfSDavid du Colombier 			break;
14187dd7cddfSDavid du Colombier 		case 's':
14194e3613abSDavid du Colombier 			q += snprint(q, left, " %d", BGSHORT(a));
14207dd7cddfSDavid du Colombier 			a += 2;
14217dd7cddfSDavid du Colombier 			break;
14227dd7cddfSDavid du Colombier 		case 'S':
14234e3613abSDavid du Colombier 			q += snprint(q, left, " %.4ux", BGSHORT(a));
14247dd7cddfSDavid du Colombier 			a += 2;
14257dd7cddfSDavid du Colombier 			break;
14267dd7cddfSDavid du Colombier 		}
14277dd7cddfSDavid du Colombier 	}
14287dd7cddfSDavid du Colombier 	*q++ = '\n';
14297dd7cddfSDavid du Colombier 	*q = 0;
14307dd7cddfSDavid du Colombier 	iprint("%.*s", (int)(q-buf), buf);
14317dd7cddfSDavid du Colombier }
14327dd7cddfSDavid du Colombier 
14337dd7cddfSDavid du Colombier void
drawmesg(Client * client,void * av,int n)14347dd7cddfSDavid du Colombier drawmesg(Client *client, void *av, int n)
14357dd7cddfSDavid du Colombier {
14366a9fc400SDavid du Colombier 	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
14377dd7cddfSDavid du Colombier 	uchar *u, *a, refresh;
14387dd7cddfSDavid du Colombier 	char *fmt;
14397dd7cddfSDavid du Colombier 	ulong value, chan;
14407dd7cddfSDavid du Colombier 	Rectangle r, clipr;
14417dd7cddfSDavid du Colombier 	Point p, q, *pp, sp;
14421ee3cffaSDavid du Colombier 	Memimage *i, *bg, *dst, *src, *mask;
14437dd7cddfSDavid du Colombier 	Memimage *l, **lp;
14447dd7cddfSDavid du Colombier 	Memscreen *scrn;
14457dd7cddfSDavid du Colombier 	DImage *font, *ll, *di, *ddst, *dsrc;
14467dd7cddfSDavid du Colombier 	DName *dn;
14477dd7cddfSDavid du Colombier 	DScreen *dscrn;
14487dd7cddfSDavid du Colombier 	FChar *fc;
14497dd7cddfSDavid du Colombier 	Refx *refx;
14507dd7cddfSDavid du Colombier 	CScreen *cs;
14517dd7cddfSDavid du Colombier 	Refreshfn reffn;
14527dd7cddfSDavid du Colombier 
14537dd7cddfSDavid du Colombier 	a = av;
14547dd7cddfSDavid du Colombier 	m = 0;
14557dd7cddfSDavid du Colombier 	fmt = nil;
14567dd7cddfSDavid du Colombier 	if(waserror()){
14577dd7cddfSDavid du Colombier 		if(fmt) printmesg(fmt, a, 1);
14589a747e4fSDavid du Colombier 	/*	iprint("error: %s\n", up->errstr);	*/
14597dd7cddfSDavid du Colombier 		nexterror();
14607dd7cddfSDavid du Colombier 	}
14617dd7cddfSDavid du Colombier 	while((n-=m) > 0){
14627dd7cddfSDavid du Colombier 		USED(fmt);
14637dd7cddfSDavid du Colombier 		a += m;
14647dd7cddfSDavid du Colombier 		switch(*a){
14657dd7cddfSDavid du Colombier 		default:
14667dd7cddfSDavid du Colombier 			error("bad draw command");
14677dd7cddfSDavid du Colombier 		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
14687dd7cddfSDavid du Colombier 		case 'b':
14697dd7cddfSDavid du Colombier 			printmesg(fmt="LLbLbRRL", a, 0);
14707dd7cddfSDavid du Colombier 			m = 1+4+4+1+4+1+4*4+4*4+4;
14717dd7cddfSDavid du Colombier 			if(n < m)
14727dd7cddfSDavid du Colombier 				error(Eshortdraw);
14737dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
14747dd7cddfSDavid du Colombier 			scrnid = BGSHORT(a+5);
14757dd7cddfSDavid du Colombier 			refresh = a[9];
14767dd7cddfSDavid du Colombier 			chan = BGLONG(a+10);
14777dd7cddfSDavid du Colombier 			repl = a[14];
14787dd7cddfSDavid du Colombier 			drawrectangle(&r, a+15);
14797dd7cddfSDavid du Colombier 			drawrectangle(&clipr, a+31);
14807dd7cddfSDavid du Colombier 			value = BGLONG(a+47);
14817dd7cddfSDavid du Colombier 			if(drawlookup(client, dstid, 0))
14827dd7cddfSDavid du Colombier 				error(Eimageexists);
14837dd7cddfSDavid du Colombier 			if(scrnid){
14847dd7cddfSDavid du Colombier 				dscrn = drawlookupscreen(client, scrnid, &cs);
14857dd7cddfSDavid du Colombier 				scrn = dscrn->screen;
14867dd7cddfSDavid du Colombier 				if(repl || chan!=scrn->image->chan)
14877dd7cddfSDavid du Colombier 					error("image parameters incompatible with screen");
14887dd7cddfSDavid du Colombier 				reffn = nil;
14897dd7cddfSDavid du Colombier 				switch(refresh){
14907dd7cddfSDavid du Colombier 				case Refbackup:
14917dd7cddfSDavid du Colombier 					break;
14927dd7cddfSDavid du Colombier 				case Refnone:
14937dd7cddfSDavid du Colombier 					reffn = memlnorefresh;
14947dd7cddfSDavid du Colombier 					break;
14957dd7cddfSDavid du Colombier 				case Refmesg:
14967dd7cddfSDavid du Colombier 					reffn = drawrefresh;
14977dd7cddfSDavid du Colombier 					break;
14987dd7cddfSDavid du Colombier 				default:
14997dd7cddfSDavid du Colombier 					error("unknown refresh method");
15007dd7cddfSDavid du Colombier 				}
15017dd7cddfSDavid du Colombier 				l = memlalloc(scrn, r, reffn, 0, value);
15027dd7cddfSDavid du Colombier 				if(l == 0)
15037dd7cddfSDavid du Colombier 					error(Edrawmem);
15047dd7cddfSDavid du Colombier 				addflush(l->layer->screenr);
15057dd7cddfSDavid du Colombier 				l->clipr = clipr;
15067dd7cddfSDavid du Colombier 				rectclip(&l->clipr, r);
15077dd7cddfSDavid du Colombier 				if(drawinstall(client, dstid, l, dscrn) == 0){
15087dd7cddfSDavid du Colombier 					memldelete(l);
15097dd7cddfSDavid du Colombier 					error(Edrawmem);
15107dd7cddfSDavid du Colombier 				}
15117dd7cddfSDavid du Colombier 				dscrn->ref++;
15127dd7cddfSDavid du Colombier 				if(reffn){
15137dd7cddfSDavid du Colombier 					refx = nil;
15147dd7cddfSDavid du Colombier 					if(reffn == drawrefresh){
15157dd7cddfSDavid du Colombier 						refx = malloc(sizeof(Refx));
15167dd7cddfSDavid du Colombier 						if(refx == 0){
15177dd7cddfSDavid du Colombier 							drawuninstall(client, dstid);
15187dd7cddfSDavid du Colombier 							error(Edrawmem);
15197dd7cddfSDavid du Colombier 						}
15207dd7cddfSDavid du Colombier 						refx->client = client;
15217dd7cddfSDavid du Colombier 						refx->dimage = drawlookup(client, dstid, 1);
15227dd7cddfSDavid du Colombier 					}
15237dd7cddfSDavid du Colombier 					memlsetrefresh(l, reffn, refx);
15247dd7cddfSDavid du Colombier 				}
15257dd7cddfSDavid du Colombier 				continue;
15267dd7cddfSDavid du Colombier 			}
15277dd7cddfSDavid du Colombier 			i = allocmemimage(r, chan);
152880ee5cbfSDavid du Colombier 			if(i == 0)
15297dd7cddfSDavid du Colombier 				error(Edrawmem);
15307dd7cddfSDavid du Colombier 			if(repl)
15317dd7cddfSDavid du Colombier 				i->flags |= Frepl;
15327dd7cddfSDavid du Colombier 			i->clipr = clipr;
15337dd7cddfSDavid du Colombier 			if(!repl)
15347dd7cddfSDavid du Colombier 				rectclip(&i->clipr, r);
15357dd7cddfSDavid du Colombier 			if(drawinstall(client, dstid, i, 0) == 0){
15367dd7cddfSDavid du Colombier 				freememimage(i);
15377dd7cddfSDavid du Colombier 				error(Edrawmem);
15387dd7cddfSDavid du Colombier 			}
15397dd7cddfSDavid du Colombier 			memfillcolor(i, value);
15407dd7cddfSDavid du Colombier 			continue;
15417dd7cddfSDavid du Colombier 
15427dd7cddfSDavid du Colombier 		/* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
15437dd7cddfSDavid du Colombier 		case 'A':
15447dd7cddfSDavid du Colombier 			printmesg(fmt="LLLb", a, 1);
15457dd7cddfSDavid du Colombier 			m = 1+4+4+4+1;
15467dd7cddfSDavid du Colombier 			if(n < m)
15477dd7cddfSDavid du Colombier 				error(Eshortdraw);
15487dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
15497dd7cddfSDavid du Colombier 			if(dstid == 0)
15507dd7cddfSDavid du Colombier 				error(Ebadarg);
15517dd7cddfSDavid du Colombier 			if(drawlookupdscreen(dstid))
15527dd7cddfSDavid du Colombier 				error(Escreenexists);
15537dd7cddfSDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+5), 1);
15547dd7cddfSDavid du Colombier 			dsrc = drawlookup(client, BGLONG(a+9), 1);
15557dd7cddfSDavid du Colombier 			if(ddst==0 || dsrc==0)
15567dd7cddfSDavid du Colombier 				error(Enodrawimage);
15577dd7cddfSDavid du Colombier 			if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
15587dd7cddfSDavid du Colombier 				error(Edrawmem);
15597dd7cddfSDavid du Colombier 			continue;
15607dd7cddfSDavid du Colombier 
15617dd7cddfSDavid du Colombier 		/* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
15627dd7cddfSDavid du Colombier 		case 'c':
15637dd7cddfSDavid du Colombier 			printmesg(fmt="LbR", a, 0);
15647dd7cddfSDavid du Colombier 			m = 1+4+1+4*4;
15657dd7cddfSDavid du Colombier 			if(n < m)
15667dd7cddfSDavid du Colombier 				error(Eshortdraw);
15677dd7cddfSDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+1), 1);
15687dd7cddfSDavid du Colombier 			if(ddst == nil)
15697dd7cddfSDavid du Colombier 				error(Enodrawimage);
15707dd7cddfSDavid du Colombier 			if(ddst->name)
15718cd4f5a6SDavid du Colombier 				error("cannot change repl/clipr of shared image");
15727dd7cddfSDavid du Colombier 			dst = ddst->image;
15737dd7cddfSDavid du Colombier 			if(a[5])
15747dd7cddfSDavid du Colombier 				dst->flags |= Frepl;
15757dd7cddfSDavid du Colombier 			drawrectangle(&dst->clipr, a+6);
15767dd7cddfSDavid du Colombier 			continue;
15777dd7cddfSDavid du Colombier 
15787dd7cddfSDavid du Colombier 		/* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
15797dd7cddfSDavid du Colombier 		case 'd':
15807dd7cddfSDavid du Colombier 			printmesg(fmt="LLLRPP", a, 0);
15817dd7cddfSDavid du Colombier 			m = 1+4+4+4+4*4+2*4+2*4;
15827dd7cddfSDavid du Colombier 			if(n < m)
15837dd7cddfSDavid du Colombier 				error(Eshortdraw);
15847dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
15857dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
15867dd7cddfSDavid du Colombier 			src = drawimage(client, a+5);
15877dd7cddfSDavid du Colombier 			mask = drawimage(client, a+9);
15887dd7cddfSDavid du Colombier 			drawrectangle(&r, a+13);
15897dd7cddfSDavid du Colombier 			drawpoint(&p, a+29);
15907dd7cddfSDavid du Colombier 			drawpoint(&q, a+37);
15916a9fc400SDavid du Colombier 			op = drawclientop(client);
15926a9fc400SDavid du Colombier 			memdraw(dst, r, src, p, mask, q, op);
15937dd7cddfSDavid du Colombier 			dstflush(dstid, dst, r);
15947dd7cddfSDavid du Colombier 			continue;
15957dd7cddfSDavid du Colombier 
15967dd7cddfSDavid du Colombier 		/* toggle debugging: 'D' val[1] */
15977dd7cddfSDavid du Colombier 		case 'D':
15987dd7cddfSDavid du Colombier 			printmesg(fmt="b", a, 0);
15997dd7cddfSDavid du Colombier 			m = 1+1;
16007dd7cddfSDavid du Colombier 			if(n < m)
16017dd7cddfSDavid du Colombier 				error(Eshortdraw);
16027dd7cddfSDavid du Colombier 			drawdebug = a[1];
16037dd7cddfSDavid du Colombier 			continue;
16047dd7cddfSDavid du Colombier 
16057dd7cddfSDavid du Colombier 		/* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
16067dd7cddfSDavid du Colombier 		case 'e':
16077dd7cddfSDavid du Colombier 		case 'E':
16087dd7cddfSDavid du Colombier 			printmesg(fmt="LLPlllPll", a, 0);
16097dd7cddfSDavid du Colombier 			m = 1+4+4+2*4+4+4+4+2*4+2*4;
16107dd7cddfSDavid du Colombier 			if(n < m)
16117dd7cddfSDavid du Colombier 				error(Eshortdraw);
16127dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
16137dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
16147dd7cddfSDavid du Colombier 			src = drawimage(client, a+5);
16157dd7cddfSDavid du Colombier 			drawpoint(&p, a+9);
16167dd7cddfSDavid du Colombier 			e0 = BGLONG(a+17);
16177dd7cddfSDavid du Colombier 			e1 = BGLONG(a+21);
16187dd7cddfSDavid du Colombier 			if(e0<0 || e1<0)
16197dd7cddfSDavid du Colombier 				error("invalid ellipse semidiameter");
16207dd7cddfSDavid du Colombier 			j = BGLONG(a+25);
16217dd7cddfSDavid du Colombier 			if(j < 0)
16227dd7cddfSDavid du Colombier 				error("negative ellipse thickness");
16237dd7cddfSDavid du Colombier 			drawpoint(&sp, a+29);
16247dd7cddfSDavid du Colombier 			c = j;
16257dd7cddfSDavid du Colombier 			if(*a == 'E')
16267dd7cddfSDavid du Colombier 				c = -1;
16277dd7cddfSDavid du Colombier 			ox = BGLONG(a+37);
16287dd7cddfSDavid du Colombier 			oy = BGLONG(a+41);
16296a9fc400SDavid du Colombier 			op = drawclientop(client);
16307dd7cddfSDavid du Colombier 			/* high bit indicates arc angles are present */
16317dd7cddfSDavid du Colombier 			if(ox & (1<<31)){
16327dd7cddfSDavid du Colombier 				if((ox & (1<<30)) == 0)
16337dd7cddfSDavid du Colombier 					ox &= ~(1<<31);
16346a9fc400SDavid du Colombier 				memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
16357dd7cddfSDavid du Colombier 			}else
16366a9fc400SDavid du Colombier 				memellipse(dst, p, e0, e1, c, src, sp, op);
16377dd7cddfSDavid du Colombier 			dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
16387dd7cddfSDavid du Colombier 			continue;
16397dd7cddfSDavid du Colombier 
16407dd7cddfSDavid du Colombier 		/* free: 'f' id[4] */
16417dd7cddfSDavid du Colombier 		case 'f':
16427dd7cddfSDavid du Colombier 			printmesg(fmt="L", a, 1);
16437dd7cddfSDavid du Colombier 			m = 1+4;
16447dd7cddfSDavid du Colombier 			if(n < m)
16457dd7cddfSDavid du Colombier 				error(Eshortdraw);
16467dd7cddfSDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1), 0);
16477dd7cddfSDavid du Colombier 			if(ll && ll->dscreen && ll->dscreen->owner != client)
16487dd7cddfSDavid du Colombier 				ll->dscreen->owner->refreshme = 1;
16497dd7cddfSDavid du Colombier 			drawuninstall(client, BGLONG(a+1));
16507dd7cddfSDavid du Colombier 			continue;
16517dd7cddfSDavid du Colombier 
16527dd7cddfSDavid du Colombier 		/* free screen: 'F' id[4] */
16537dd7cddfSDavid du Colombier 		case 'F':
16547dd7cddfSDavid du Colombier 			printmesg(fmt="L", a, 1);
16557dd7cddfSDavid du Colombier 			m = 1+4;
16567dd7cddfSDavid du Colombier 			if(n < m)
16577dd7cddfSDavid du Colombier 				error(Eshortdraw);
16587dd7cddfSDavid du Colombier 			drawlookupscreen(client, BGLONG(a+1), &cs);
16597dd7cddfSDavid du Colombier 			drawuninstallscreen(client, cs);
16607dd7cddfSDavid du Colombier 			continue;
16617dd7cddfSDavid du Colombier 
16627dd7cddfSDavid du Colombier 		/* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
16637dd7cddfSDavid du Colombier 		case 'i':
16647dd7cddfSDavid du Colombier 			printmesg(fmt="Llb", a, 1);
16657dd7cddfSDavid du Colombier 			m = 1+4+4+1;
16667dd7cddfSDavid du Colombier 			if(n < m)
16677dd7cddfSDavid du Colombier 				error(Eshortdraw);
16687dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
16697dd7cddfSDavid du Colombier 			if(dstid == 0)
16708cd4f5a6SDavid du Colombier 				error("cannot use display as font");
16717dd7cddfSDavid du Colombier 			font = drawlookup(client, dstid, 1);
16727dd7cddfSDavid du Colombier 			if(font == 0)
16737dd7cddfSDavid du Colombier 				error(Enodrawimage);
16747dd7cddfSDavid du Colombier 			if(font->image->layer)
16758cd4f5a6SDavid du Colombier 				error("cannot use window as font");
16767dd7cddfSDavid du Colombier 			ni = BGLONG(a+5);
16779a747e4fSDavid du Colombier 			if(ni<=0 || ni>4096)
16789a747e4fSDavid du Colombier 				error("bad font size (4096 chars max)");
16799a747e4fSDavid du Colombier 			free(font->fchar);	/* should we complain if non-zero? */
16807dd7cddfSDavid du Colombier 			font->fchar = malloc(ni*sizeof(FChar));
16817dd7cddfSDavid du Colombier 			if(font->fchar == 0)
16827dd7cddfSDavid du Colombier 				error("no memory for font");
16837dd7cddfSDavid du Colombier 			memset(font->fchar, 0, ni*sizeof(FChar));
16847dd7cddfSDavid du Colombier 			font->nfchar = ni;
16857dd7cddfSDavid du Colombier 			font->ascent = a[9];
16867dd7cddfSDavid du Colombier 			continue;
16877dd7cddfSDavid du Colombier 
16887dd7cddfSDavid du Colombier 		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
16897dd7cddfSDavid du Colombier 		case 'l':
16907dd7cddfSDavid du Colombier 			printmesg(fmt="LLSRPbb", a, 0);
16917dd7cddfSDavid du Colombier 			m = 1+4+4+2+4*4+2*4+1+1;
16927dd7cddfSDavid du Colombier 			if(n < m)
16937dd7cddfSDavid du Colombier 				error(Eshortdraw);
16947dd7cddfSDavid du Colombier 			font = drawlookup(client, BGLONG(a+1), 1);
16957dd7cddfSDavid du Colombier 			if(font == 0)
16967dd7cddfSDavid du Colombier 				error(Enodrawimage);
16977dd7cddfSDavid du Colombier 			if(font->nfchar == 0)
16987dd7cddfSDavid du Colombier 				error(Enotfont);
16997dd7cddfSDavid du Colombier 			src = drawimage(client, a+5);
17007dd7cddfSDavid du Colombier 			ci = BGSHORT(a+9);
17017dd7cddfSDavid du Colombier 			if(ci >= font->nfchar)
17027dd7cddfSDavid du Colombier 				error(Eindex);
17037dd7cddfSDavid du Colombier 			drawrectangle(&r, a+11);
17047dd7cddfSDavid du Colombier 			drawpoint(&p, a+27);
17056a9fc400SDavid du Colombier 			memdraw(font->image, r, src, p, memopaque, p, S);
17067dd7cddfSDavid du Colombier 			fc = &font->fchar[ci];
17077dd7cddfSDavid du Colombier 			fc->minx = r.min.x;
17087dd7cddfSDavid du Colombier 			fc->maxx = r.max.x;
17097dd7cddfSDavid du Colombier 			fc->miny = r.min.y;
17107dd7cddfSDavid du Colombier 			fc->maxy = r.max.y;
17117dd7cddfSDavid du Colombier 			fc->left = a[35];
17127dd7cddfSDavid du Colombier 			fc->width = a[36];
17137dd7cddfSDavid du Colombier 			continue;
17147dd7cddfSDavid du Colombier 
17157dd7cddfSDavid du Colombier 		/* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
17167dd7cddfSDavid du Colombier 		case 'L':
17177dd7cddfSDavid du Colombier 			printmesg(fmt="LPPlllLP", a, 0);
17187dd7cddfSDavid du Colombier 			m = 1+4+2*4+2*4+4+4+4+4+2*4;
17197dd7cddfSDavid du Colombier 			if(n < m)
17207dd7cddfSDavid du Colombier 				error(Eshortdraw);
17217dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
17227dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
17237dd7cddfSDavid du Colombier 			drawpoint(&p, a+5);
17247dd7cddfSDavid du Colombier 			drawpoint(&q, a+13);
17257dd7cddfSDavid du Colombier 			e0 = BGLONG(a+21);
17267dd7cddfSDavid du Colombier 			e1 = BGLONG(a+25);
17277dd7cddfSDavid du Colombier 			j = BGLONG(a+29);
17287dd7cddfSDavid du Colombier 			if(j < 0)
17297dd7cddfSDavid du Colombier 				error("negative line width");
17307dd7cddfSDavid du Colombier 			src = drawimage(client, a+33);
17317dd7cddfSDavid du Colombier 			drawpoint(&sp, a+37);
17326a9fc400SDavid du Colombier 			op = drawclientop(client);
17336a9fc400SDavid du Colombier 			memline(dst, p, q, e0, e1, j, src, sp, op);
17347dd7cddfSDavid du Colombier 			/* avoid memlinebbox if possible */
17357dd7cddfSDavid du Colombier 			if(dstid==0 || dst->layer!=nil){
17367dd7cddfSDavid du Colombier 				/* BUG: this is terribly inefficient: update maximal containing rect*/
17377dd7cddfSDavid du Colombier 				r = memlinebbox(p, q, e0, e1, j);
17387dd7cddfSDavid du Colombier 				dstflush(dstid, dst, insetrect(r, -(1+1+j)));
17397dd7cddfSDavid du Colombier 			}
17407dd7cddfSDavid du Colombier 			continue;
17417dd7cddfSDavid du Colombier 
17427dd7cddfSDavid du Colombier 		/* create image mask: 'm' newid[4] id[4] */
17437dd7cddfSDavid du Colombier /*
17447dd7cddfSDavid du Colombier  *
17457dd7cddfSDavid du Colombier 		case 'm':
17467dd7cddfSDavid du Colombier 			printmesg("LL", a, 0);
17477dd7cddfSDavid du Colombier 			m = 4+4;
17487dd7cddfSDavid du Colombier 			if(n < m)
17497dd7cddfSDavid du Colombier 				error(Eshortdraw);
17507dd7cddfSDavid du Colombier 			break;
17517dd7cddfSDavid du Colombier  *
17527dd7cddfSDavid du Colombier  */
17537dd7cddfSDavid du Colombier 
17547dd7cddfSDavid du Colombier 		/* attach to a named image: 'n' dstid[4] j[1] name[j] */
17557dd7cddfSDavid du Colombier 		case 'n':
17567dd7cddfSDavid du Colombier 			printmesg(fmt="Lz", a, 0);
17577dd7cddfSDavid du Colombier 			m = 1+4+1;
17587dd7cddfSDavid du Colombier 			if(n < m)
17597dd7cddfSDavid du Colombier 				error(Eshortdraw);
17607dd7cddfSDavid du Colombier 			j = a[5];
17617dd7cddfSDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
17627dd7cddfSDavid du Colombier 				error(Eshortdraw);
17637dd7cddfSDavid du Colombier 			m += j;
17647dd7cddfSDavid du Colombier 			if(n < m)
17657dd7cddfSDavid du Colombier 				error(Eshortdraw);
17667dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
17677dd7cddfSDavid du Colombier 			if(drawlookup(client, dstid, 0))
17687dd7cddfSDavid du Colombier 				error(Eimageexists);
17697dd7cddfSDavid du Colombier 			dn = drawlookupname(j, (char*)a+6);
17707dd7cddfSDavid du Colombier 			if(dn == nil)
17717dd7cddfSDavid du Colombier 				error(Enoname);
17727dd7cddfSDavid du Colombier 			if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
17737dd7cddfSDavid du Colombier 				error(Edrawmem);
17747dd7cddfSDavid du Colombier 			di = drawlookup(client, dstid, 0);
17757dd7cddfSDavid du Colombier 			if(di == 0)
17768cd4f5a6SDavid du Colombier 				error("draw: cannot happen");
17777dd7cddfSDavid du Colombier 			di->vers = dn->vers;
17787dd7cddfSDavid du Colombier 			di->name = smalloc(j+1);
17797dd7cddfSDavid du Colombier 			di->fromname = dn->dimage;
17807dd7cddfSDavid du Colombier 			di->fromname->ref++;
17817dd7cddfSDavid du Colombier 			memmove(di->name, a+6, j);
17827dd7cddfSDavid du Colombier 			di->name[j] = 0;
17837dd7cddfSDavid du Colombier 			client->infoid = dstid;
17847dd7cddfSDavid du Colombier 			continue;
17857dd7cddfSDavid du Colombier 
17867dd7cddfSDavid du Colombier 		/* name an image: 'N' dstid[4] in[1] j[1] name[j] */
17877dd7cddfSDavid du Colombier 		case 'N':
17887dd7cddfSDavid du Colombier 			printmesg(fmt="Lbz", a, 0);
17897dd7cddfSDavid du Colombier 			m = 1+4+1+1;
17907dd7cddfSDavid du Colombier 			if(n < m)
17917dd7cddfSDavid du Colombier 				error(Eshortdraw);
17927dd7cddfSDavid du Colombier 			c = a[5];
17937dd7cddfSDavid du Colombier 			j = a[6];
17947dd7cddfSDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
17957dd7cddfSDavid du Colombier 				error(Eshortdraw);
17967dd7cddfSDavid du Colombier 			m += j;
17977dd7cddfSDavid du Colombier 			if(n < m)
17987dd7cddfSDavid du Colombier 				error(Eshortdraw);
17997dd7cddfSDavid du Colombier 			di = drawlookup(client, BGLONG(a+1), 0);
18007dd7cddfSDavid du Colombier 			if(di == 0)
18017dd7cddfSDavid du Colombier 				error(Enodrawimage);
18027dd7cddfSDavid du Colombier 			if(di->name)
18037dd7cddfSDavid du Colombier 				error(Enamed);
18047dd7cddfSDavid du Colombier 			if(c)
18057dd7cddfSDavid du Colombier 				drawaddname(client, di, j, (char*)a+7);
18067dd7cddfSDavid du Colombier 			else{
18077dd7cddfSDavid du Colombier 				dn = drawlookupname(j, (char*)a+7);
18087dd7cddfSDavid du Colombier 				if(dn == nil)
18097dd7cddfSDavid du Colombier 					error(Enoname);
18107dd7cddfSDavid du Colombier 				if(dn->dimage != di)
18117dd7cddfSDavid du Colombier 					error(Ewrongname);
18127dd7cddfSDavid du Colombier 				drawdelname(dn);
18137dd7cddfSDavid du Colombier 			}
18147dd7cddfSDavid du Colombier 			continue;
18157dd7cddfSDavid du Colombier 
18167dd7cddfSDavid du Colombier 		/* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
18177dd7cddfSDavid du Colombier 		case 'o':
18187dd7cddfSDavid du Colombier 			printmesg(fmt="LPP", a, 0);
18197dd7cddfSDavid du Colombier 			m = 1+4+2*4+2*4;
18207dd7cddfSDavid du Colombier 			if(n < m)
18217dd7cddfSDavid du Colombier 				error(Eshortdraw);
18227dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
18237dd7cddfSDavid du Colombier 			if(dst->layer){
18247dd7cddfSDavid du Colombier 				drawpoint(&p, a+5);
18257dd7cddfSDavid du Colombier 				drawpoint(&q, a+13);
18267dd7cddfSDavid du Colombier 				r = dst->layer->screenr;
18277dd7cddfSDavid du Colombier 				ni = memlorigin(dst, p, q);
18287dd7cddfSDavid du Colombier 				if(ni < 0)
18297dd7cddfSDavid du Colombier 					error("image origin failed");
18307dd7cddfSDavid du Colombier 				if(ni > 0){
18317dd7cddfSDavid du Colombier 					addflush(r);
18327dd7cddfSDavid du Colombier 					addflush(dst->layer->screenr);
18337dd7cddfSDavid du Colombier 					ll = drawlookup(client, BGLONG(a+1), 1);
18347dd7cddfSDavid du Colombier 					drawrefreshscreen(ll, client);
18357dd7cddfSDavid du Colombier 				}
18367dd7cddfSDavid du Colombier 			}
18377dd7cddfSDavid du Colombier 			continue;
18387dd7cddfSDavid du Colombier 
18396a9fc400SDavid du Colombier 		/* set compositing operator for next draw operation: 'O' op */
18406a9fc400SDavid du Colombier 		case 'O':
18416a9fc400SDavid du Colombier 			printmesg(fmt="b", a, 0);
18426a9fc400SDavid du Colombier 			m = 1+1;
18436a9fc400SDavid du Colombier 			if(n < m)
18446a9fc400SDavid du Colombier 				error(Eshortdraw);
18456a9fc400SDavid du Colombier 			client->op = a[1];
18466a9fc400SDavid du Colombier 			continue;
18476a9fc400SDavid du Colombier 
18487dd7cddfSDavid 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] */
18497dd7cddfSDavid 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] */
18507dd7cddfSDavid du Colombier 		case 'p':
18517dd7cddfSDavid du Colombier 		case 'P':
18527dd7cddfSDavid du Colombier 			printmesg(fmt="LslllLPP", a, 0);
18537dd7cddfSDavid du Colombier 			m = 1+4+2+4+4+4+4+2*4;
18547dd7cddfSDavid du Colombier 			if(n < m)
18557dd7cddfSDavid du Colombier 				error(Eshortdraw);
18567dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
18577dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
18587dd7cddfSDavid du Colombier 			ni = BGSHORT(a+5);
18597dd7cddfSDavid du Colombier 			if(ni < 0)
18607dd7cddfSDavid du Colombier 				error("negative count in polygon");
18617dd7cddfSDavid du Colombier 			e0 = BGLONG(a+7);
18627dd7cddfSDavid du Colombier 			e1 = BGLONG(a+11);
18637dd7cddfSDavid du Colombier 			j = 0;
18647dd7cddfSDavid du Colombier 			if(*a == 'p'){
18657dd7cddfSDavid du Colombier 				j = BGLONG(a+15);
18667dd7cddfSDavid du Colombier 				if(j < 0)
18677dd7cddfSDavid du Colombier 					error("negative polygon line width");
18687dd7cddfSDavid du Colombier 			}
18697dd7cddfSDavid du Colombier 			src = drawimage(client, a+19);
18707dd7cddfSDavid du Colombier 			drawpoint(&sp, a+23);
18717dd7cddfSDavid du Colombier 			drawpoint(&p, a+31);
18727dd7cddfSDavid du Colombier 			ni++;
18737dd7cddfSDavid du Colombier 			pp = malloc(ni*sizeof(Point));
18747dd7cddfSDavid du Colombier 			if(pp == nil)
18757dd7cddfSDavid du Colombier 				error(Enomem);
18767dd7cddfSDavid du Colombier 			doflush = 0;
18777dd7cddfSDavid du Colombier 			if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
18787dd7cddfSDavid du Colombier 				doflush = 1;	/* simplify test in loop */
18797dd7cddfSDavid du Colombier 			ox = oy = 0;
18806a9fc400SDavid du Colombier 			esize = 0;
18817dd7cddfSDavid du Colombier 			u = a+m;
18827dd7cddfSDavid du Colombier 			for(y=0; y<ni; y++){
18836a9fc400SDavid du Colombier 				q = p;
18846a9fc400SDavid du Colombier 				oesize = esize;
18857dd7cddfSDavid du Colombier 				u = drawcoord(u, a+n, ox, &p.x);
18867dd7cddfSDavid du Colombier 				u = drawcoord(u, a+n, oy, &p.y);
18877dd7cddfSDavid du Colombier 				ox = p.x;
18887dd7cddfSDavid du Colombier 				oy = p.y;
18897dd7cddfSDavid du Colombier 				if(doflush){
18907dd7cddfSDavid du Colombier 					esize = j;
18917dd7cddfSDavid du Colombier 					if(*a == 'p'){
18927dd7cddfSDavid du Colombier 						if(y == 0){
18937dd7cddfSDavid du Colombier 							c = memlineendsize(e0);
18947dd7cddfSDavid du Colombier 							if(c > esize)
18957dd7cddfSDavid du Colombier 								esize = c;
18967dd7cddfSDavid du Colombier 						}
18977dd7cddfSDavid du Colombier 						if(y == ni-1){
18987dd7cddfSDavid du Colombier 							c = memlineendsize(e1);
18997dd7cddfSDavid du Colombier 							if(c > esize)
19007dd7cddfSDavid du Colombier 								esize = c;
19017dd7cddfSDavid du Colombier 						}
19027dd7cddfSDavid du Colombier 					}
19037dd7cddfSDavid du Colombier 					if(*a=='P' && e0!=1 && e0 !=~0)
19047dd7cddfSDavid du Colombier 						r = dst->clipr;
19056a9fc400SDavid du Colombier 					else if(y > 0){
19066a9fc400SDavid du Colombier 						r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
19076a9fc400SDavid du Colombier 						combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
19086a9fc400SDavid du Colombier 					}
19096a9fc400SDavid du Colombier 					if(rectclip(&r, dst->clipr))		/* should perhaps be an arg to dstflush */
19107dd7cddfSDavid du Colombier 						dstflush(dstid, dst, r);
19117dd7cddfSDavid du Colombier 				}
19127dd7cddfSDavid du Colombier 				pp[y] = p;
19137dd7cddfSDavid du Colombier 			}
19146a9fc400SDavid du Colombier 			if(y == 1)
19156a9fc400SDavid du Colombier 				dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
19166a9fc400SDavid du Colombier 			op = drawclientop(client);
19177dd7cddfSDavid du Colombier 			if(*a == 'p')
19186a9fc400SDavid du Colombier 				mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
19197dd7cddfSDavid du Colombier 			else
19206a9fc400SDavid du Colombier 				memfillpoly(dst, pp, ni, e0, src, sp, op);
19217dd7cddfSDavid du Colombier 			free(pp);
19227dd7cddfSDavid du Colombier 			m = u-a;
19237dd7cddfSDavid du Colombier 			continue;
19247dd7cddfSDavid du Colombier 
19257dd7cddfSDavid du Colombier 		/* read: 'r' id[4] R[4*4] */
19267dd7cddfSDavid du Colombier 		case 'r':
19277dd7cddfSDavid du Colombier 			printmesg(fmt="LR", a, 0);
19287dd7cddfSDavid du Colombier 			m = 1+4+4*4;
19297dd7cddfSDavid du Colombier 			if(n < m)
19307dd7cddfSDavid du Colombier 				error(Eshortdraw);
19317dd7cddfSDavid du Colombier 			i = drawimage(client, a+1);
19327dd7cddfSDavid du Colombier 			drawrectangle(&r, a+5);
19337dd7cddfSDavid du Colombier 			if(!rectinrect(r, i->r))
19347dd7cddfSDavid du Colombier 				error(Ereadoutside);
19357dd7cddfSDavid du Colombier 			c = bytesperline(r, i->depth);
19367dd7cddfSDavid du Colombier 			c *= Dy(r);
19377dd7cddfSDavid du Colombier 			free(client->readdata);
19387dd7cddfSDavid du Colombier 			client->readdata = mallocz(c, 0);
19397dd7cddfSDavid du Colombier 			if(client->readdata == nil)
19407dd7cddfSDavid du Colombier 				error("readimage malloc failed");
194180ee5cbfSDavid du Colombier 			client->nreaddata = memunload(i, r, client->readdata, c);
19427dd7cddfSDavid du Colombier 			if(client->nreaddata < 0){
19437dd7cddfSDavid du Colombier 				free(client->readdata);
19447dd7cddfSDavid du Colombier 				client->readdata = nil;
19457dd7cddfSDavid du Colombier 				error("bad readimage call");
19467dd7cddfSDavid du Colombier 			}
19477dd7cddfSDavid du Colombier 			continue;
19487dd7cddfSDavid du Colombier 
19497dd7cddfSDavid du Colombier 		/* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
19507dd7cddfSDavid 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]) */
19517dd7cddfSDavid du Colombier 		case 's':
19527dd7cddfSDavid du Colombier 		case 'x':
19537dd7cddfSDavid du Colombier 			printmesg(fmt="LLLPRPs", a, 0);
19547dd7cddfSDavid du Colombier 			m = 1+4+4+4+2*4+4*4+2*4+2;
19557dd7cddfSDavid du Colombier 			if(*a == 'x')
19567dd7cddfSDavid du Colombier 				m += 4+2*4;
19577dd7cddfSDavid du Colombier 			if(n < m)
19587dd7cddfSDavid du Colombier 				error(Eshortdraw);
19597dd7cddfSDavid du Colombier 
19607dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
19617dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
19627dd7cddfSDavid du Colombier 			src = drawimage(client, a+5);
19637dd7cddfSDavid du Colombier 			font = drawlookup(client, BGLONG(a+9), 1);
19647dd7cddfSDavid du Colombier 			if(font == 0)
19657dd7cddfSDavid du Colombier 				error(Enodrawimage);
19667dd7cddfSDavid du Colombier 			if(font->nfchar == 0)
19677dd7cddfSDavid du Colombier 				error(Enotfont);
19687dd7cddfSDavid du Colombier 			drawpoint(&p, a+13);
19697dd7cddfSDavid du Colombier 			drawrectangle(&r, a+21);
19707dd7cddfSDavid du Colombier 			drawpoint(&sp, a+37);
19717dd7cddfSDavid du Colombier 			ni = BGSHORT(a+45);
19727dd7cddfSDavid du Colombier 			u = a+m;
19737dd7cddfSDavid du Colombier 			m += ni*2;
19747dd7cddfSDavid du Colombier 			if(n < m)
19757dd7cddfSDavid du Colombier 				error(Eshortdraw);
19767dd7cddfSDavid du Colombier 			clipr = dst->clipr;
19777dd7cddfSDavid du Colombier 			dst->clipr = r;
19786a9fc400SDavid du Colombier 			op = drawclientop(client);
19791ee3cffaSDavid du Colombier 			bg = dst;
19807dd7cddfSDavid du Colombier 			if(*a == 'x'){
19817dd7cddfSDavid du Colombier 				/* paint background */
19821ee3cffaSDavid du Colombier 				bg = drawimage(client, a+47);
19837dd7cddfSDavid du Colombier 				drawpoint(&q, a+51);
19847dd7cddfSDavid du Colombier 				r.min.x = p.x;
19857dd7cddfSDavid du Colombier 				r.min.y = p.y-font->ascent;
19867dd7cddfSDavid du Colombier 				r.max.x = p.x;
19877dd7cddfSDavid du Colombier 				r.max.y = r.min.y+Dy(font->image->r);
19887dd7cddfSDavid du Colombier 				j = ni;
19897dd7cddfSDavid du Colombier 				while(--j >= 0){
19907dd7cddfSDavid du Colombier 					ci = BGSHORT(u);
19917dd7cddfSDavid du Colombier 					if(ci<0 || ci>=font->nfchar){
19927dd7cddfSDavid du Colombier 						dst->clipr = clipr;
19937dd7cddfSDavid du Colombier 						error(Eindex);
19947dd7cddfSDavid du Colombier 					}
19957dd7cddfSDavid du Colombier 					r.max.x += font->fchar[ci].width;
19967dd7cddfSDavid du Colombier 					u += 2;
19977dd7cddfSDavid du Colombier 				}
19981ee3cffaSDavid du Colombier 				memdraw(dst, r, bg, q, memopaque, ZP, op);
19997dd7cddfSDavid du Colombier 				u -= 2*ni;
20007dd7cddfSDavid du Colombier 			}
20017dd7cddfSDavid du Colombier 			q = p;
20027dd7cddfSDavid du Colombier 			while(--ni >= 0){
20037dd7cddfSDavid du Colombier 				ci = BGSHORT(u);
20047dd7cddfSDavid du Colombier 				if(ci<0 || ci>=font->nfchar){
20057dd7cddfSDavid du Colombier 					dst->clipr = clipr;
20067dd7cddfSDavid du Colombier 					error(Eindex);
20077dd7cddfSDavid du Colombier 				}
20081ee3cffaSDavid du Colombier 				q = drawchar(dst, bg, q, src, &sp, font, ci, op);
20097dd7cddfSDavid du Colombier 				u += 2;
20107dd7cddfSDavid du Colombier 			}
20117dd7cddfSDavid du Colombier 			dst->clipr = clipr;
20127dd7cddfSDavid du Colombier 			p.y -= font->ascent;
20137dd7cddfSDavid du Colombier 			dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
20147dd7cddfSDavid du Colombier 			continue;
20157dd7cddfSDavid du Colombier 
20167dd7cddfSDavid du Colombier 		/* use public screen: 'S' id[4] chan[4] */
20177dd7cddfSDavid du Colombier 		case 'S':
20187dd7cddfSDavid du Colombier 			printmesg(fmt="Ll", a, 0);
20197dd7cddfSDavid du Colombier 			m = 1+4+4;
20207dd7cddfSDavid du Colombier 			if(n < m)
20217dd7cddfSDavid du Colombier 				error(Eshortdraw);
20227dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
20237dd7cddfSDavid du Colombier 			if(dstid == 0)
20247dd7cddfSDavid du Colombier 				error(Ebadarg);
20257dd7cddfSDavid du Colombier 			dscrn = drawlookupdscreen(dstid);
20267dd7cddfSDavid du Colombier 			if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
20277dd7cddfSDavid du Colombier 				error(Enodrawscreen);
20287dd7cddfSDavid du Colombier 			if(dscrn->screen->image->chan != BGLONG(a+5))
20297dd7cddfSDavid du Colombier 				error("inconsistent chan");
20307dd7cddfSDavid du Colombier 			if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
20317dd7cddfSDavid du Colombier 				error(Edrawmem);
20327dd7cddfSDavid du Colombier 			continue;
20337dd7cddfSDavid du Colombier 
20347dd7cddfSDavid du Colombier 		/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
20357dd7cddfSDavid du Colombier 		case 't':
20367dd7cddfSDavid du Colombier 			printmesg(fmt="bsL", a, 0);
20377dd7cddfSDavid du Colombier 			m = 1+1+2;
20387dd7cddfSDavid du Colombier 			if(n < m)
20397dd7cddfSDavid du Colombier 				error(Eshortdraw);
20407dd7cddfSDavid du Colombier 			nw = BGSHORT(a+2);
20417dd7cddfSDavid du Colombier 			if(nw < 0)
20427dd7cddfSDavid du Colombier 				error(Ebadarg);
20437dd7cddfSDavid du Colombier 			if(nw == 0)
20447dd7cddfSDavid du Colombier 				continue;
20457dd7cddfSDavid du Colombier 			m += nw*4;
20467dd7cddfSDavid du Colombier 			if(n < m)
20477dd7cddfSDavid du Colombier 				error(Eshortdraw);
20487dd7cddfSDavid du Colombier 			lp = malloc(nw*sizeof(Memimage*));
20497dd7cddfSDavid du Colombier 			if(lp == 0)
20507dd7cddfSDavid du Colombier 				error(Enomem);
20517dd7cddfSDavid du Colombier 			if(waserror()){
20527dd7cddfSDavid du Colombier 				free(lp);
20537dd7cddfSDavid du Colombier 				nexterror();
20547dd7cddfSDavid du Colombier 			}
20557dd7cddfSDavid du Colombier 			for(j=0; j<nw; j++)
20567dd7cddfSDavid du Colombier 				lp[j] = drawimage(client, a+1+1+2+j*4);
20577dd7cddfSDavid du Colombier 			if(lp[0]->layer == 0)
20587dd7cddfSDavid du Colombier 				error("images are not windows");
20597dd7cddfSDavid du Colombier 			for(j=1; j<nw; j++)
20607dd7cddfSDavid du Colombier 				if(lp[j]->layer->screen != lp[0]->layer->screen)
20617dd7cddfSDavid du Colombier 					error("images not on same screen");
20627dd7cddfSDavid du Colombier 			if(a[1])
20637dd7cddfSDavid du Colombier 				memltofrontn(lp, nw);
20647dd7cddfSDavid du Colombier 			else
20657dd7cddfSDavid du Colombier 				memltorearn(lp, nw);
20667dd7cddfSDavid du Colombier 			if(lp[0]->layer->screen->image->data == screenimage->data)
20677dd7cddfSDavid du Colombier 				for(j=0; j<nw; j++)
20687dd7cddfSDavid du Colombier 					addflush(lp[j]->layer->screenr);
20697dd7cddfSDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1+1+2), 1);
20707dd7cddfSDavid du Colombier 			drawrefreshscreen(ll, client);
20717dd7cddfSDavid du Colombier 			poperror();
20727dd7cddfSDavid du Colombier 			free(lp);
20737dd7cddfSDavid du Colombier 			continue;
20747dd7cddfSDavid du Colombier 
20757dd7cddfSDavid du Colombier 		/* visible: 'v' */
20767dd7cddfSDavid du Colombier 		case 'v':
20777dd7cddfSDavid du Colombier 			printmesg(fmt="", a, 0);
20787dd7cddfSDavid du Colombier 			m = 1;
20797dd7cddfSDavid du Colombier 			drawflush();
20807dd7cddfSDavid du Colombier 			continue;
20817dd7cddfSDavid du Colombier 
20827dd7cddfSDavid du Colombier 		/* write: 'y' id[4] R[4*4] data[x*1] */
20837dd7cddfSDavid du Colombier 		/* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
20847dd7cddfSDavid du Colombier 		case 'y':
20857dd7cddfSDavid du Colombier 		case 'Y':
20867dd7cddfSDavid du Colombier 			printmesg(fmt="LR", a, 0);
20877dd7cddfSDavid du Colombier 		//	iprint("load %c\n", *a);
20887dd7cddfSDavid du Colombier 			m = 1+4+4*4;
20897dd7cddfSDavid du Colombier 			if(n < m)
20907dd7cddfSDavid du Colombier 				error(Eshortdraw);
20917dd7cddfSDavid du Colombier 			dstid = BGLONG(a+1);
20927dd7cddfSDavid du Colombier 			dst = drawimage(client, a+1);
20937dd7cddfSDavid du Colombier 			drawrectangle(&r, a+5);
20947dd7cddfSDavid du Colombier 			if(!rectinrect(r, dst->r))
20957dd7cddfSDavid du Colombier 				error(Ewriteoutside);
20967dd7cddfSDavid du Colombier 			y = memload(dst, r, a+m, n-m, *a=='Y');
20977dd7cddfSDavid du Colombier 			if(y < 0)
20987dd7cddfSDavid du Colombier 				error("bad writeimage call");
20997dd7cddfSDavid du Colombier 			dstflush(dstid, dst, r);
21007dd7cddfSDavid du Colombier 			m += y;
21017dd7cddfSDavid du Colombier 			continue;
21027dd7cddfSDavid du Colombier 		}
21037dd7cddfSDavid du Colombier 	}
21047dd7cddfSDavid du Colombier 	poperror();
21057dd7cddfSDavid du Colombier }
21067dd7cddfSDavid du Colombier 
21077dd7cddfSDavid du Colombier Dev drawdevtab = {
21087dd7cddfSDavid du Colombier 	'i',
21097dd7cddfSDavid du Colombier 	"draw",
21107dd7cddfSDavid du Colombier 
21117dd7cddfSDavid du Colombier 	devreset,
21127dd7cddfSDavid du Colombier 	devinit,
21139a747e4fSDavid du Colombier 	devshutdown,
21147dd7cddfSDavid du Colombier 	drawattach,
21157dd7cddfSDavid du Colombier 	drawwalk,
21167dd7cddfSDavid du Colombier 	drawstat,
21177dd7cddfSDavid du Colombier 	drawopen,
21187dd7cddfSDavid du Colombier 	devcreate,
21197dd7cddfSDavid du Colombier 	drawclose,
21207dd7cddfSDavid du Colombier 	drawread,
21217dd7cddfSDavid du Colombier 	devbread,
21227dd7cddfSDavid du Colombier 	drawwrite,
21237dd7cddfSDavid du Colombier 	devbwrite,
21247dd7cddfSDavid du Colombier 	devremove,
21257dd7cddfSDavid du Colombier 	devwstat,
21267dd7cddfSDavid du Colombier };
21277dd7cddfSDavid du Colombier 
21287dd7cddfSDavid du Colombier /*
21297dd7cddfSDavid du Colombier  * On 8 bit displays, load the default color map
21307dd7cddfSDavid du Colombier  */
21317dd7cddfSDavid du Colombier void
drawcmap(void)21327dd7cddfSDavid du Colombier drawcmap(void)
21337dd7cddfSDavid du Colombier {
21347dd7cddfSDavid du Colombier 	int r, g, b, cr, cg, cb, v;
21357dd7cddfSDavid du Colombier 	int num, den;
21367dd7cddfSDavid du Colombier 	int i, j;
21377dd7cddfSDavid du Colombier 
21387dd7cddfSDavid du Colombier 	drawactive(1);	/* to restore map from backup */
21397dd7cddfSDavid du Colombier 	for(r=0,i=0; r!=4; r++)
21407dd7cddfSDavid du Colombier 	    for(v=0; v!=4; v++,i+=16){
21417dd7cddfSDavid du Colombier 		for(g=0,j=v-r; g!=4; g++)
21427dd7cddfSDavid du Colombier 		    for(b=0;b!=4;b++,j++){
21437dd7cddfSDavid du Colombier 			den = r;
21447dd7cddfSDavid du Colombier 			if(g > den)
21457dd7cddfSDavid du Colombier 				den = g;
21467dd7cddfSDavid du Colombier 			if(b > den)
21477dd7cddfSDavid du Colombier 				den = b;
21487dd7cddfSDavid du Colombier 			if(den == 0)	/* divide check -- pick grey shades */
21497dd7cddfSDavid du Colombier 				cr = cg = cb = v*17;
21507dd7cddfSDavid du Colombier 			else{
21517dd7cddfSDavid du Colombier 				num = 17*(4*den+v);
21527dd7cddfSDavid du Colombier 				cr = r*num/den;
21537dd7cddfSDavid du Colombier 				cg = g*num/den;
21547dd7cddfSDavid du Colombier 				cb = b*num/den;
21557dd7cddfSDavid du Colombier 			}
21567dd7cddfSDavid du Colombier 			setcolor(i+(j&15),
21577dd7cddfSDavid du Colombier 				cr*0x01010101, cg*0x01010101, cb*0x01010101);
21587dd7cddfSDavid du Colombier 		    }
21597dd7cddfSDavid du Colombier 	}
21607dd7cddfSDavid du Colombier }
21617dd7cddfSDavid du Colombier 
21627dd7cddfSDavid du Colombier void
drawblankscreen(int blank)21637dd7cddfSDavid du Colombier drawblankscreen(int blank)
21647dd7cddfSDavid du Colombier {
21657dd7cddfSDavid du Colombier 	int i, nc;
21667dd7cddfSDavid du Colombier 	ulong *p;
21677dd7cddfSDavid du Colombier 
21687dd7cddfSDavid du Colombier 	if(blank == sdraw.blanked)
21697dd7cddfSDavid du Colombier 		return;
21704de34a7eSDavid du Colombier 	if(!candlock())
21717dd7cddfSDavid du Colombier 		return;
2172cb8c047aSDavid du Colombier 	if(screenimage == nil){
21734de34a7eSDavid du Colombier 		dunlock();
21747dd7cddfSDavid du Colombier 		return;
21757dd7cddfSDavid du Colombier 	}
21767dd7cddfSDavid du Colombier 	p = sdraw.savemap;
21777dd7cddfSDavid du Colombier 	nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
21787dd7cddfSDavid du Colombier 
21797dd7cddfSDavid du Colombier 	/*
21807dd7cddfSDavid du Colombier 	 * blankscreen uses the hardware to blank the screen
21817dd7cddfSDavid du Colombier 	 * when possible.  to help in cases when it is not possible,
21827dd7cddfSDavid du Colombier 	 * we set the color map to be all black.
21837dd7cddfSDavid du Colombier 	 */
21847dd7cddfSDavid du Colombier 	if(blank == 0){	/* turn screen on */
21857dd7cddfSDavid du Colombier 		for(i=0; i<nc; i++, p+=3)
21867dd7cddfSDavid du Colombier 			setcolor(i, p[0], p[1], p[2]);
21877dd7cddfSDavid du Colombier 		blankscreen(0);
21887dd7cddfSDavid du Colombier 	}else{	/* turn screen off */
21897dd7cddfSDavid du Colombier 		blankscreen(1);
21907dd7cddfSDavid du Colombier 		for(i=0; i<nc; i++, p+=3){
21917dd7cddfSDavid du Colombier 			getcolor(i, &p[0], &p[1], &p[2]);
21927dd7cddfSDavid du Colombier 			setcolor(i, 0, 0, 0);
21937dd7cddfSDavid du Colombier 		}
21947dd7cddfSDavid du Colombier 	}
21957dd7cddfSDavid du Colombier 	sdraw.blanked = blank;
21964de34a7eSDavid du Colombier 	dunlock();
21977dd7cddfSDavid du Colombier }
21987dd7cddfSDavid du Colombier 
21997dd7cddfSDavid du Colombier /*
22007dd7cddfSDavid du Colombier  * record activity on screen, changing blanking as appropriate
22017dd7cddfSDavid du Colombier  */
22027dd7cddfSDavid du Colombier void
drawactive(int active)22037dd7cddfSDavid du Colombier drawactive(int active)
22047dd7cddfSDavid du Colombier {
22057dd7cddfSDavid du Colombier 	if(active){
22067dd7cddfSDavid du Colombier 		drawblankscreen(0);
22076a9fc400SDavid du Colombier 		sdraw.blanktime = MACHP(0)->ticks;
22087dd7cddfSDavid du Colombier 	}else{
22096a9fc400SDavid du Colombier 		if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime)
22107dd7cddfSDavid du Colombier 			drawblankscreen(1);
22117dd7cddfSDavid du Colombier 	}
22127dd7cddfSDavid du Colombier }
22136a9fc400SDavid du Colombier 
22146a9fc400SDavid du Colombier int
drawidletime(void)22156a9fc400SDavid du Colombier drawidletime(void)
22166a9fc400SDavid du Colombier {
22176a9fc400SDavid du Colombier 	return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60;
22186a9fc400SDavid du Colombier }
2219