xref: /plan9-contrib/sys/src/cmd/unix/drawterm/kern/devdraw.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include	"u.h"
2*8ccd4a63SDavid du Colombier #include	"lib.h"
3*8ccd4a63SDavid du Colombier #include	"dat.h"
4*8ccd4a63SDavid du Colombier #include	"fns.h"
5*8ccd4a63SDavid du Colombier #include	"error.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier #define	Image	IMAGE
8*8ccd4a63SDavid du Colombier #include	<draw.h>
9*8ccd4a63SDavid du Colombier #include	<memdraw.h>
10*8ccd4a63SDavid du Colombier #include	<memlayer.h>
11*8ccd4a63SDavid du Colombier #include	<cursor.h>
12*8ccd4a63SDavid du Colombier #include	"screen.h"
13*8ccd4a63SDavid du Colombier 
14*8ccd4a63SDavid du Colombier enum
15*8ccd4a63SDavid du Colombier {
16*8ccd4a63SDavid du Colombier 	Qtopdir		= 0,
17*8ccd4a63SDavid du Colombier 	Qnew,
18*8ccd4a63SDavid du Colombier 	Q3rd,
19*8ccd4a63SDavid du Colombier 	Q2nd,
20*8ccd4a63SDavid du Colombier 	Qcolormap,
21*8ccd4a63SDavid du Colombier 	Qctl,
22*8ccd4a63SDavid du Colombier 	Qdata,
23*8ccd4a63SDavid du Colombier 	Qrefresh,
24*8ccd4a63SDavid du Colombier };
25*8ccd4a63SDavid du Colombier 
26*8ccd4a63SDavid du Colombier /*
27*8ccd4a63SDavid du Colombier  * Qid path is:
28*8ccd4a63SDavid du Colombier  *	 4 bits of file type (qids above)
29*8ccd4a63SDavid du Colombier  *	24 bits of mux slot number +1; 0 means not attached to client
30*8ccd4a63SDavid du Colombier  */
31*8ccd4a63SDavid du Colombier #define	QSHIFT	4	/* location in qid of client # */
32*8ccd4a63SDavid du Colombier 
33*8ccd4a63SDavid du Colombier #define	QID(q)		((((ulong)(q).path)&0x0000000F)>>0)
34*8ccd4a63SDavid du Colombier #define	CLIENTPATH(q)	((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
35*8ccd4a63SDavid du Colombier #define	CLIENT(q)	CLIENTPATH((q).path)
36*8ccd4a63SDavid du Colombier 
37*8ccd4a63SDavid du Colombier #define	NHASH		(1<<5)
38*8ccd4a63SDavid du Colombier #define	HASHMASK	(NHASH-1)
39*8ccd4a63SDavid du Colombier #define	IOUNIT	(64*1024)
40*8ccd4a63SDavid du Colombier 
41*8ccd4a63SDavid du Colombier typedef struct Client Client;
42*8ccd4a63SDavid du Colombier typedef struct Draw Draw;
43*8ccd4a63SDavid du Colombier typedef struct DImage DImage;
44*8ccd4a63SDavid du Colombier typedef struct DScreen DScreen;
45*8ccd4a63SDavid du Colombier typedef struct CScreen CScreen;
46*8ccd4a63SDavid du Colombier typedef struct FChar FChar;
47*8ccd4a63SDavid du Colombier typedef struct Refresh Refresh;
48*8ccd4a63SDavid du Colombier typedef struct Refx Refx;
49*8ccd4a63SDavid du Colombier typedef struct DName DName;
50*8ccd4a63SDavid du Colombier 
51*8ccd4a63SDavid du Colombier ulong blanktime = 30;	/* in minutes; a half hour */
52*8ccd4a63SDavid du Colombier 
53*8ccd4a63SDavid du Colombier struct Draw
54*8ccd4a63SDavid du Colombier {
55*8ccd4a63SDavid du Colombier 	QLock	lk;
56*8ccd4a63SDavid du Colombier 	int		clientid;
57*8ccd4a63SDavid du Colombier 	int		nclient;
58*8ccd4a63SDavid du Colombier 	Client**	client;
59*8ccd4a63SDavid du Colombier 	int		nname;
60*8ccd4a63SDavid du Colombier 	DName*	name;
61*8ccd4a63SDavid du Colombier 	int		vers;
62*8ccd4a63SDavid du Colombier 	int		softscreen;
63*8ccd4a63SDavid du Colombier 	int		blanked;	/* screen turned off */
64*8ccd4a63SDavid du Colombier 	ulong		blanktime;	/* time of last operation */
65*8ccd4a63SDavid du Colombier 	ulong		savemap[3*256];
66*8ccd4a63SDavid du Colombier };
67*8ccd4a63SDavid du Colombier 
68*8ccd4a63SDavid du Colombier struct Client
69*8ccd4a63SDavid du Colombier {
70*8ccd4a63SDavid du Colombier 	Ref		r;
71*8ccd4a63SDavid du Colombier 	DImage*		dimage[NHASH];
72*8ccd4a63SDavid du Colombier 	CScreen*	cscreen;
73*8ccd4a63SDavid du Colombier 	Refresh*	refresh;
74*8ccd4a63SDavid du Colombier 	Rendez		refrend;
75*8ccd4a63SDavid du Colombier 	uchar*		readdata;
76*8ccd4a63SDavid du Colombier 	int		nreaddata;
77*8ccd4a63SDavid du Colombier 	int		busy;
78*8ccd4a63SDavid du Colombier 	int		clientid;
79*8ccd4a63SDavid du Colombier 	int		slot;
80*8ccd4a63SDavid du Colombier 	int		refreshme;
81*8ccd4a63SDavid du Colombier 	int		infoid;
82*8ccd4a63SDavid du Colombier 	int		op;
83*8ccd4a63SDavid du Colombier };
84*8ccd4a63SDavid du Colombier 
85*8ccd4a63SDavid du Colombier struct Refresh
86*8ccd4a63SDavid du Colombier {
87*8ccd4a63SDavid du Colombier 	DImage*		dimage;
88*8ccd4a63SDavid du Colombier 	Rectangle	r;
89*8ccd4a63SDavid du Colombier 	Refresh*	next;
90*8ccd4a63SDavid du Colombier };
91*8ccd4a63SDavid du Colombier 
92*8ccd4a63SDavid du Colombier struct Refx
93*8ccd4a63SDavid du Colombier {
94*8ccd4a63SDavid du Colombier 	Client*		client;
95*8ccd4a63SDavid du Colombier 	DImage*		dimage;
96*8ccd4a63SDavid du Colombier };
97*8ccd4a63SDavid du Colombier 
98*8ccd4a63SDavid du Colombier struct DName
99*8ccd4a63SDavid du Colombier {
100*8ccd4a63SDavid du Colombier 	char			*name;
101*8ccd4a63SDavid du Colombier 	Client	*client;
102*8ccd4a63SDavid du Colombier 	DImage*		dimage;
103*8ccd4a63SDavid du Colombier 	int			vers;
104*8ccd4a63SDavid du Colombier };
105*8ccd4a63SDavid du Colombier 
106*8ccd4a63SDavid du Colombier struct FChar
107*8ccd4a63SDavid du Colombier {
108*8ccd4a63SDavid du Colombier 	int		minx;	/* left edge of bits */
109*8ccd4a63SDavid du Colombier 	int		maxx;	/* right edge of bits */
110*8ccd4a63SDavid du Colombier 	uchar		miny;	/* first non-zero scan-line */
111*8ccd4a63SDavid du Colombier 	uchar		maxy;	/* last non-zero scan-line + 1 */
112*8ccd4a63SDavid du Colombier 	schar		left;	/* offset of baseline */
113*8ccd4a63SDavid du Colombier 	uchar		width;	/* width of baseline */
114*8ccd4a63SDavid du Colombier };
115*8ccd4a63SDavid du Colombier 
116*8ccd4a63SDavid du Colombier /*
117*8ccd4a63SDavid du Colombier  * Reference counts in DImages:
118*8ccd4a63SDavid du Colombier  *	one per open by original client
119*8ccd4a63SDavid du Colombier  *	one per screen image or fill
120*8ccd4a63SDavid du Colombier  * 	one per image derived from this one by name
121*8ccd4a63SDavid du Colombier  */
122*8ccd4a63SDavid du Colombier struct DImage
123*8ccd4a63SDavid du Colombier {
124*8ccd4a63SDavid du Colombier 	int		id;
125*8ccd4a63SDavid du Colombier 	int		ref;
126*8ccd4a63SDavid du Colombier 	char		*name;
127*8ccd4a63SDavid du Colombier 	int		vers;
128*8ccd4a63SDavid du Colombier 	Memimage*	image;
129*8ccd4a63SDavid du Colombier 	int		ascent;
130*8ccd4a63SDavid du Colombier 	int		nfchar;
131*8ccd4a63SDavid du Colombier 	FChar*		fchar;
132*8ccd4a63SDavid du Colombier 	DScreen*	dscreen;	/* 0 if not a window */
133*8ccd4a63SDavid du Colombier 	DImage*	fromname;	/* image this one is derived from, by name */
134*8ccd4a63SDavid du Colombier 	DImage*		next;
135*8ccd4a63SDavid du Colombier };
136*8ccd4a63SDavid du Colombier 
137*8ccd4a63SDavid du Colombier struct CScreen
138*8ccd4a63SDavid du Colombier {
139*8ccd4a63SDavid du Colombier 	DScreen*	dscreen;
140*8ccd4a63SDavid du Colombier 	CScreen*	next;
141*8ccd4a63SDavid du Colombier };
142*8ccd4a63SDavid du Colombier 
143*8ccd4a63SDavid du Colombier struct DScreen
144*8ccd4a63SDavid du Colombier {
145*8ccd4a63SDavid du Colombier 	int		id;
146*8ccd4a63SDavid du Colombier 	int		public;
147*8ccd4a63SDavid du Colombier 	int		ref;
148*8ccd4a63SDavid du Colombier 	DImage	*dimage;
149*8ccd4a63SDavid du Colombier 	DImage	*dfill;
150*8ccd4a63SDavid du Colombier 	Memscreen*	screen;
151*8ccd4a63SDavid du Colombier 	Client*		owner;
152*8ccd4a63SDavid du Colombier 	DScreen*	next;
153*8ccd4a63SDavid du Colombier };
154*8ccd4a63SDavid du Colombier 
155*8ccd4a63SDavid du Colombier static	Draw		sdraw;
156*8ccd4a63SDavid du Colombier static	Memimage	*screenimage;
157*8ccd4a63SDavid du Colombier static	Memdata	screendata;
158*8ccd4a63SDavid du Colombier static	Rectangle	flushrect;
159*8ccd4a63SDavid du Colombier static	int		waste;
160*8ccd4a63SDavid du Colombier static	DScreen*	dscreen;
161*8ccd4a63SDavid du Colombier extern	void		flushmemscreen(Rectangle);
162*8ccd4a63SDavid du Colombier 	void		drawmesg(Client*, void*, int);
163*8ccd4a63SDavid du Colombier 	void		drawuninstall(Client*, int);
164*8ccd4a63SDavid du Colombier 	void		drawfreedimage(DImage*);
165*8ccd4a63SDavid du Colombier 	Client*		drawclientofpath(ulong);
166*8ccd4a63SDavid du Colombier 
167*8ccd4a63SDavid du Colombier static	char Enodrawimage[] =	"unknown id for draw image";
168*8ccd4a63SDavid du Colombier static	char Enodrawscreen[] =	"unknown id for draw screen";
169*8ccd4a63SDavid du Colombier static	char Eshortdraw[] =	"short draw message";
170*8ccd4a63SDavid du Colombier static	char Eshortread[] =	"draw read too short";
171*8ccd4a63SDavid du Colombier static	char Eimageexists[] =	"image id in use";
172*8ccd4a63SDavid du Colombier static	char Escreenexists[] =	"screen id in use";
173*8ccd4a63SDavid du Colombier static	char Edrawmem[] =	"image memory allocation failed";
174*8ccd4a63SDavid du Colombier static	char Ereadoutside[] =	"readimage outside image";
175*8ccd4a63SDavid du Colombier static	char Ewriteoutside[] =	"writeimage outside image";
176*8ccd4a63SDavid du Colombier static	char Enotfont[] =	"image not a font";
177*8ccd4a63SDavid du Colombier static	char Eindex[] =		"character index out of range";
178*8ccd4a63SDavid du Colombier static	char Enoclient[] =	"no such draw client";
179*8ccd4a63SDavid du Colombier /* static	char Edepth[] =	"image has bad depth"; */
180*8ccd4a63SDavid du Colombier static	char Enameused[] =	"image name in use";
181*8ccd4a63SDavid du Colombier static	char Enoname[] =	"no image with that name";
182*8ccd4a63SDavid du Colombier static	char Eoldname[] =	"named image no longer valid";
183*8ccd4a63SDavid du Colombier static	char Enamed[] = 	"image already has name";
184*8ccd4a63SDavid du Colombier static	char Ewrongname[] = 	"wrong name for image";
185*8ccd4a63SDavid du Colombier 
186*8ccd4a63SDavid du Colombier int
187*8ccd4a63SDavid du Colombier drawcanqlock(void)
188*8ccd4a63SDavid du Colombier {
189*8ccd4a63SDavid du Colombier 	return canqlock(&sdraw.lk);
190*8ccd4a63SDavid du Colombier }
191*8ccd4a63SDavid du Colombier 
192*8ccd4a63SDavid du Colombier void
193*8ccd4a63SDavid du Colombier drawqlock(void)
194*8ccd4a63SDavid du Colombier {
195*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
196*8ccd4a63SDavid du Colombier }
197*8ccd4a63SDavid du Colombier 
198*8ccd4a63SDavid du Colombier void
199*8ccd4a63SDavid du Colombier drawqunlock(void)
200*8ccd4a63SDavid du Colombier {
201*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
202*8ccd4a63SDavid du Colombier }
203*8ccd4a63SDavid du Colombier 
204*8ccd4a63SDavid du Colombier static int
205*8ccd4a63SDavid du Colombier drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
206*8ccd4a63SDavid du Colombier {
207*8ccd4a63SDavid du Colombier 	int t;
208*8ccd4a63SDavid du Colombier 	Qid q;
209*8ccd4a63SDavid du Colombier 	ulong path;
210*8ccd4a63SDavid du Colombier 	Client *cl;
211*8ccd4a63SDavid du Colombier 
212*8ccd4a63SDavid du Colombier 	USED(name);
213*8ccd4a63SDavid du Colombier 	USED(dt);
214*8ccd4a63SDavid du Colombier 	USED(ndt);
215*8ccd4a63SDavid du Colombier 
216*8ccd4a63SDavid du Colombier 	q.vers = 0;
217*8ccd4a63SDavid du Colombier 
218*8ccd4a63SDavid du Colombier 	if(s == DEVDOTDOT){
219*8ccd4a63SDavid du Colombier 		switch(QID(c->qid)){
220*8ccd4a63SDavid du Colombier 		case Qtopdir:
221*8ccd4a63SDavid du Colombier 		case Q2nd:
222*8ccd4a63SDavid du Colombier 			mkqid(&q, Qtopdir, 0, QTDIR);
223*8ccd4a63SDavid du Colombier 			devdir(c, q, "#i", 0, eve, 0500, dp);
224*8ccd4a63SDavid du Colombier 			break;
225*8ccd4a63SDavid du Colombier 		case Q3rd:
226*8ccd4a63SDavid du Colombier 			cl = drawclientofpath(c->qid.path);
227*8ccd4a63SDavid du Colombier 			if(cl == nil)
228*8ccd4a63SDavid du Colombier 				strcpy(up->genbuf, "??");
229*8ccd4a63SDavid du Colombier 			else
230*8ccd4a63SDavid du Colombier 				sprint(up->genbuf, "%d", cl->clientid);
231*8ccd4a63SDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
232*8ccd4a63SDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0500, dp);
233*8ccd4a63SDavid du Colombier 			break;
234*8ccd4a63SDavid du Colombier 		default:
235*8ccd4a63SDavid du Colombier 			panic("drawwalk %llux", c->qid.path);
236*8ccd4a63SDavid du Colombier 		}
237*8ccd4a63SDavid du Colombier 		return 1;
238*8ccd4a63SDavid du Colombier 	}
239*8ccd4a63SDavid du Colombier 
240*8ccd4a63SDavid du Colombier 	/*
241*8ccd4a63SDavid du Colombier 	 * Top level directory contains the name of the device.
242*8ccd4a63SDavid du Colombier 	 */
243*8ccd4a63SDavid du Colombier 	t = QID(c->qid);
244*8ccd4a63SDavid du Colombier 	if(t == Qtopdir){
245*8ccd4a63SDavid du Colombier 		switch(s){
246*8ccd4a63SDavid du Colombier 		case 0:
247*8ccd4a63SDavid du Colombier 			mkqid(&q, Q2nd, 0, QTDIR);
248*8ccd4a63SDavid du Colombier 			devdir(c, q, "draw", 0, eve, 0555, dp);
249*8ccd4a63SDavid du Colombier 			break;
250*8ccd4a63SDavid du Colombier 		default:
251*8ccd4a63SDavid du Colombier 			return -1;
252*8ccd4a63SDavid du Colombier 		}
253*8ccd4a63SDavid du Colombier 		return 1;
254*8ccd4a63SDavid du Colombier 	}
255*8ccd4a63SDavid du Colombier 
256*8ccd4a63SDavid du Colombier 	/*
257*8ccd4a63SDavid du Colombier 	 * Second level contains "new" plus all the clients.
258*8ccd4a63SDavid du Colombier 	 */
259*8ccd4a63SDavid du Colombier 	if(t == Q2nd || t == Qnew){
260*8ccd4a63SDavid du Colombier 		if(s == 0){
261*8ccd4a63SDavid du Colombier 			mkqid(&q, Qnew, 0, QTFILE);
262*8ccd4a63SDavid du Colombier 			devdir(c, q, "new", 0, eve, 0666, dp);
263*8ccd4a63SDavid du Colombier 		}
264*8ccd4a63SDavid du Colombier 		else if(s <= sdraw.nclient){
265*8ccd4a63SDavid du Colombier 			cl = sdraw.client[s-1];
266*8ccd4a63SDavid du Colombier 			if(cl == 0)
267*8ccd4a63SDavid du Colombier 				return 0;
268*8ccd4a63SDavid du Colombier 			sprint(up->genbuf, "%d", cl->clientid);
269*8ccd4a63SDavid du Colombier 			mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
270*8ccd4a63SDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
271*8ccd4a63SDavid du Colombier 			return 1;
272*8ccd4a63SDavid du Colombier 		}
273*8ccd4a63SDavid du Colombier 		else
274*8ccd4a63SDavid du Colombier 			return -1;
275*8ccd4a63SDavid du Colombier 		return 1;
276*8ccd4a63SDavid du Colombier 	}
277*8ccd4a63SDavid du Colombier 
278*8ccd4a63SDavid du Colombier 	/*
279*8ccd4a63SDavid du Colombier 	 * Third level.
280*8ccd4a63SDavid du Colombier 	 */
281*8ccd4a63SDavid du Colombier 	path = c->qid.path&~((1<<QSHIFT)-1);	/* slot component */
282*8ccd4a63SDavid du Colombier 	q.vers = c->qid.vers;
283*8ccd4a63SDavid du Colombier 	q.type = QTFILE;
284*8ccd4a63SDavid du Colombier 	switch(s){
285*8ccd4a63SDavid du Colombier 	case 0:
286*8ccd4a63SDavid du Colombier 		q.path = path|Qcolormap;
287*8ccd4a63SDavid du Colombier 		devdir(c, q, "colormap", 0, eve, 0600, dp);
288*8ccd4a63SDavid du Colombier 		break;
289*8ccd4a63SDavid du Colombier 	case 1:
290*8ccd4a63SDavid du Colombier 		q.path = path|Qctl;
291*8ccd4a63SDavid du Colombier 		devdir(c, q, "ctl", 0, eve, 0600, dp);
292*8ccd4a63SDavid du Colombier 		break;
293*8ccd4a63SDavid du Colombier 	case 2:
294*8ccd4a63SDavid du Colombier 		q.path = path|Qdata;
295*8ccd4a63SDavid du Colombier 		devdir(c, q, "data", 0, eve, 0600, dp);
296*8ccd4a63SDavid du Colombier 		break;
297*8ccd4a63SDavid du Colombier 	case 3:
298*8ccd4a63SDavid du Colombier 		q.path = path|Qrefresh;
299*8ccd4a63SDavid du Colombier 		devdir(c, q, "refresh", 0, eve, 0400, dp);
300*8ccd4a63SDavid du Colombier 		break;
301*8ccd4a63SDavid du Colombier 	default:
302*8ccd4a63SDavid du Colombier 		return -1;
303*8ccd4a63SDavid du Colombier 	}
304*8ccd4a63SDavid du Colombier 	return 1;
305*8ccd4a63SDavid du Colombier }
306*8ccd4a63SDavid du Colombier 
307*8ccd4a63SDavid du Colombier static
308*8ccd4a63SDavid du Colombier int
309*8ccd4a63SDavid du Colombier drawrefactive(void *a)
310*8ccd4a63SDavid du Colombier {
311*8ccd4a63SDavid du Colombier 	Client *c;
312*8ccd4a63SDavid du Colombier 
313*8ccd4a63SDavid du Colombier 	c = a;
314*8ccd4a63SDavid du Colombier 	return c->refreshme || c->refresh!=0;
315*8ccd4a63SDavid du Colombier }
316*8ccd4a63SDavid du Colombier 
317*8ccd4a63SDavid du Colombier static
318*8ccd4a63SDavid du Colombier void
319*8ccd4a63SDavid du Colombier drawrefreshscreen(DImage *l, Client *client)
320*8ccd4a63SDavid du Colombier {
321*8ccd4a63SDavid du Colombier 	while(l != nil && l->dscreen == nil)
322*8ccd4a63SDavid du Colombier 		l = l->fromname;
323*8ccd4a63SDavid du Colombier 	if(l != nil && l->dscreen->owner != client)
324*8ccd4a63SDavid du Colombier 		l->dscreen->owner->refreshme = 1;
325*8ccd4a63SDavid du Colombier }
326*8ccd4a63SDavid du Colombier 
327*8ccd4a63SDavid du Colombier static
328*8ccd4a63SDavid du Colombier void
329*8ccd4a63SDavid du Colombier drawrefresh(Memimage *m, Rectangle r, void *v)
330*8ccd4a63SDavid du Colombier {
331*8ccd4a63SDavid du Colombier 	Refx *x;
332*8ccd4a63SDavid du Colombier 	DImage *d;
333*8ccd4a63SDavid du Colombier 	Client *c;
334*8ccd4a63SDavid du Colombier 	Refresh *ref;
335*8ccd4a63SDavid du Colombier 
336*8ccd4a63SDavid du Colombier 	USED(m);
337*8ccd4a63SDavid du Colombier 
338*8ccd4a63SDavid du Colombier 	if(v == 0)
339*8ccd4a63SDavid du Colombier 		return;
340*8ccd4a63SDavid du Colombier 	x = v;
341*8ccd4a63SDavid du Colombier 	c = x->client;
342*8ccd4a63SDavid du Colombier 	d = x->dimage;
343*8ccd4a63SDavid du Colombier 	for(ref=c->refresh; ref; ref=ref->next)
344*8ccd4a63SDavid du Colombier 		if(ref->dimage == d){
345*8ccd4a63SDavid du Colombier 			combinerect(&ref->r, r);
346*8ccd4a63SDavid du Colombier 			return;
347*8ccd4a63SDavid du Colombier 		}
348*8ccd4a63SDavid du Colombier 	ref = malloc(sizeof(Refresh));
349*8ccd4a63SDavid du Colombier 	if(ref){
350*8ccd4a63SDavid du Colombier 		ref->dimage = d;
351*8ccd4a63SDavid du Colombier 		ref->r = r;
352*8ccd4a63SDavid du Colombier 		ref->next = c->refresh;
353*8ccd4a63SDavid du Colombier 		c->refresh = ref;
354*8ccd4a63SDavid du Colombier 	}
355*8ccd4a63SDavid du Colombier }
356*8ccd4a63SDavid du Colombier 
357*8ccd4a63SDavid du Colombier static void
358*8ccd4a63SDavid du Colombier addflush(Rectangle r)
359*8ccd4a63SDavid du Colombier {
360*8ccd4a63SDavid du Colombier 	int abb, ar, anbb;
361*8ccd4a63SDavid du Colombier 	Rectangle nbb;
362*8ccd4a63SDavid du Colombier 
363*8ccd4a63SDavid du Colombier 	if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
364*8ccd4a63SDavid du Colombier 		return;
365*8ccd4a63SDavid du Colombier 
366*8ccd4a63SDavid du Colombier 	if(flushrect.min.x >= flushrect.max.x){
367*8ccd4a63SDavid du Colombier 		flushrect = r;
368*8ccd4a63SDavid du Colombier 		waste = 0;
369*8ccd4a63SDavid du Colombier 		return;
370*8ccd4a63SDavid du Colombier 	}
371*8ccd4a63SDavid du Colombier 	nbb = flushrect;
372*8ccd4a63SDavid du Colombier 	combinerect(&nbb, r);
373*8ccd4a63SDavid du Colombier 	ar = Dx(r)*Dy(r);
374*8ccd4a63SDavid du Colombier 	abb = Dx(flushrect)*Dy(flushrect);
375*8ccd4a63SDavid du Colombier 	anbb = Dx(nbb)*Dy(nbb);
376*8ccd4a63SDavid du Colombier 	/*
377*8ccd4a63SDavid du Colombier 	 * Area of new waste is area of new bb minus area of old bb,
378*8ccd4a63SDavid du Colombier 	 * less the area of the new segment, which we assume is not waste.
379*8ccd4a63SDavid du Colombier 	 * This could be negative, but that's OK.
380*8ccd4a63SDavid du Colombier 	 */
381*8ccd4a63SDavid du Colombier 	waste += anbb-abb - ar;
382*8ccd4a63SDavid du Colombier 	if(waste < 0)
383*8ccd4a63SDavid du Colombier 		waste = 0;
384*8ccd4a63SDavid du Colombier 	/*
385*8ccd4a63SDavid du Colombier 	 * absorb if:
386*8ccd4a63SDavid du Colombier 	 *	total area is small
387*8ccd4a63SDavid du Colombier 	 *	waste is less than half total area
388*8ccd4a63SDavid du Colombier 	 * 	rectangles touch
389*8ccd4a63SDavid du Colombier 	 */
390*8ccd4a63SDavid du Colombier 	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
391*8ccd4a63SDavid du Colombier 		flushrect = nbb;
392*8ccd4a63SDavid du Colombier 		return;
393*8ccd4a63SDavid du Colombier 	}
394*8ccd4a63SDavid du Colombier 	/* emit current state */
395*8ccd4a63SDavid du Colombier 	if(flushrect.min.x < flushrect.max.x)
396*8ccd4a63SDavid du Colombier 		flushmemscreen(flushrect);
397*8ccd4a63SDavid du Colombier 	flushrect = r;
398*8ccd4a63SDavid du Colombier 	waste = 0;
399*8ccd4a63SDavid du Colombier }
400*8ccd4a63SDavid du Colombier 
401*8ccd4a63SDavid du Colombier static
402*8ccd4a63SDavid du Colombier void
403*8ccd4a63SDavid du Colombier dstflush(int dstid, Memimage *dst, Rectangle r)
404*8ccd4a63SDavid du Colombier {
405*8ccd4a63SDavid du Colombier 	Memlayer *l;
406*8ccd4a63SDavid du Colombier 
407*8ccd4a63SDavid du Colombier 	if(dstid == 0){
408*8ccd4a63SDavid du Colombier 		combinerect(&flushrect, r);
409*8ccd4a63SDavid du Colombier 		return;
410*8ccd4a63SDavid du Colombier 	}
411*8ccd4a63SDavid du Colombier 	/* how can this happen? -rsc, dec 12 2002 */
412*8ccd4a63SDavid du Colombier 	if(dst == 0){
413*8ccd4a63SDavid du Colombier 		print("nil dstflush\n");
414*8ccd4a63SDavid du Colombier 		return;
415*8ccd4a63SDavid du Colombier 	}
416*8ccd4a63SDavid du Colombier 	l = dst->layer;
417*8ccd4a63SDavid du Colombier 	if(l == nil)
418*8ccd4a63SDavid du Colombier 		return;
419*8ccd4a63SDavid du Colombier 	do{
420*8ccd4a63SDavid du Colombier 		if(l->screen->image->data != screenimage->data)
421*8ccd4a63SDavid du Colombier 			return;
422*8ccd4a63SDavid du Colombier 		r = rectaddpt(r, l->delta);
423*8ccd4a63SDavid du Colombier 		l = l->screen->image->layer;
424*8ccd4a63SDavid du Colombier 	}while(l);
425*8ccd4a63SDavid du Colombier 	addflush(r);
426*8ccd4a63SDavid du Colombier }
427*8ccd4a63SDavid du Colombier 
428*8ccd4a63SDavid du Colombier void
429*8ccd4a63SDavid du Colombier drawflush(void)
430*8ccd4a63SDavid du Colombier {
431*8ccd4a63SDavid du Colombier 	if(flushrect.min.x < flushrect.max.x)
432*8ccd4a63SDavid du Colombier 		flushmemscreen(flushrect);
433*8ccd4a63SDavid du Colombier 	flushrect = Rect(10000, 10000, -10000, -10000);
434*8ccd4a63SDavid du Colombier }
435*8ccd4a63SDavid du Colombier 
436*8ccd4a63SDavid du Colombier void
437*8ccd4a63SDavid du Colombier drawflushr(Rectangle r)
438*8ccd4a63SDavid du Colombier {
439*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
440*8ccd4a63SDavid du Colombier 	flushmemscreen(r);
441*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
442*8ccd4a63SDavid du Colombier }
443*8ccd4a63SDavid du Colombier 
444*8ccd4a63SDavid du Colombier static
445*8ccd4a63SDavid du Colombier int
446*8ccd4a63SDavid du Colombier drawcmp(char *a, char *b, int n)
447*8ccd4a63SDavid du Colombier {
448*8ccd4a63SDavid du Colombier 	if(strlen(a) != n)
449*8ccd4a63SDavid du Colombier 		return 1;
450*8ccd4a63SDavid du Colombier 	return memcmp(a, b, n);
451*8ccd4a63SDavid du Colombier }
452*8ccd4a63SDavid du Colombier 
453*8ccd4a63SDavid du Colombier DName*
454*8ccd4a63SDavid du Colombier drawlookupname(int n, char *str)
455*8ccd4a63SDavid du Colombier {
456*8ccd4a63SDavid du Colombier 	DName *name, *ename;
457*8ccd4a63SDavid du Colombier 
458*8ccd4a63SDavid du Colombier 	name = sdraw.name;
459*8ccd4a63SDavid du Colombier 	ename = &name[sdraw.nname];
460*8ccd4a63SDavid du Colombier 	for(; name<ename; name++)
461*8ccd4a63SDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
462*8ccd4a63SDavid du Colombier 			return name;
463*8ccd4a63SDavid du Colombier 	return 0;
464*8ccd4a63SDavid du Colombier }
465*8ccd4a63SDavid du Colombier 
466*8ccd4a63SDavid du Colombier int
467*8ccd4a63SDavid du Colombier drawgoodname(DImage *d)
468*8ccd4a63SDavid du Colombier {
469*8ccd4a63SDavid du Colombier 	DName *n;
470*8ccd4a63SDavid du Colombier 
471*8ccd4a63SDavid du Colombier 	/* if window, validate the screen's own images */
472*8ccd4a63SDavid du Colombier 	if(d->dscreen)
473*8ccd4a63SDavid du Colombier 		if(drawgoodname(d->dscreen->dimage) == 0
474*8ccd4a63SDavid du Colombier 		|| drawgoodname(d->dscreen->dfill) == 0)
475*8ccd4a63SDavid du Colombier 			return 0;
476*8ccd4a63SDavid du Colombier 	if(d->name == nil)
477*8ccd4a63SDavid du Colombier 		return 1;
478*8ccd4a63SDavid du Colombier 	n = drawlookupname(strlen(d->name), d->name);
479*8ccd4a63SDavid du Colombier 	if(n==nil || n->vers!=d->vers)
480*8ccd4a63SDavid du Colombier 		return 0;
481*8ccd4a63SDavid du Colombier 	return 1;
482*8ccd4a63SDavid du Colombier }
483*8ccd4a63SDavid du Colombier 
484*8ccd4a63SDavid du Colombier DImage*
485*8ccd4a63SDavid du Colombier drawlookup(Client *client, int id, int checkname)
486*8ccd4a63SDavid du Colombier {
487*8ccd4a63SDavid du Colombier 	DImage *d;
488*8ccd4a63SDavid du Colombier 
489*8ccd4a63SDavid du Colombier 	d = client->dimage[id&HASHMASK];
490*8ccd4a63SDavid du Colombier 	while(d){
491*8ccd4a63SDavid du Colombier 		if(d->id == id){
492*8ccd4a63SDavid du Colombier 			if(checkname && !drawgoodname(d))
493*8ccd4a63SDavid du Colombier 				error(Eoldname);
494*8ccd4a63SDavid du Colombier 			return d;
495*8ccd4a63SDavid du Colombier 		}
496*8ccd4a63SDavid du Colombier 		d = d->next;
497*8ccd4a63SDavid du Colombier 	}
498*8ccd4a63SDavid du Colombier 	return 0;
499*8ccd4a63SDavid du Colombier }
500*8ccd4a63SDavid du Colombier 
501*8ccd4a63SDavid du Colombier DScreen*
502*8ccd4a63SDavid du Colombier drawlookupdscreen(int id)
503*8ccd4a63SDavid du Colombier {
504*8ccd4a63SDavid du Colombier 	DScreen *s;
505*8ccd4a63SDavid du Colombier 
506*8ccd4a63SDavid du Colombier 	s = dscreen;
507*8ccd4a63SDavid du Colombier 	while(s){
508*8ccd4a63SDavid du Colombier 		if(s->id == id)
509*8ccd4a63SDavid du Colombier 			return s;
510*8ccd4a63SDavid du Colombier 		s = s->next;
511*8ccd4a63SDavid du Colombier 	}
512*8ccd4a63SDavid du Colombier 	return 0;
513*8ccd4a63SDavid du Colombier }
514*8ccd4a63SDavid du Colombier 
515*8ccd4a63SDavid du Colombier DScreen*
516*8ccd4a63SDavid du Colombier drawlookupscreen(Client *client, int id, CScreen **cs)
517*8ccd4a63SDavid du Colombier {
518*8ccd4a63SDavid du Colombier 	CScreen *s;
519*8ccd4a63SDavid du Colombier 
520*8ccd4a63SDavid du Colombier 	s = client->cscreen;
521*8ccd4a63SDavid du Colombier 	while(s){
522*8ccd4a63SDavid du Colombier 		if(s->dscreen->id == id){
523*8ccd4a63SDavid du Colombier 			*cs = s;
524*8ccd4a63SDavid du Colombier 			return s->dscreen;
525*8ccd4a63SDavid du Colombier 		}
526*8ccd4a63SDavid du Colombier 		s = s->next;
527*8ccd4a63SDavid du Colombier 	}
528*8ccd4a63SDavid du Colombier 	error(Enodrawscreen);
529*8ccd4a63SDavid du Colombier 	return 0;
530*8ccd4a63SDavid du Colombier }
531*8ccd4a63SDavid du Colombier 
532*8ccd4a63SDavid du Colombier Memimage*
533*8ccd4a63SDavid du Colombier drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
534*8ccd4a63SDavid du Colombier {
535*8ccd4a63SDavid du Colombier 	DImage *d;
536*8ccd4a63SDavid du Colombier 
537*8ccd4a63SDavid du Colombier 	d = malloc(sizeof(DImage));
538*8ccd4a63SDavid du Colombier 	if(d == 0)
539*8ccd4a63SDavid du Colombier 		return 0;
540*8ccd4a63SDavid du Colombier 	d->id = id;
541*8ccd4a63SDavid du Colombier 	d->ref = 1;
542*8ccd4a63SDavid du Colombier 	d->name = 0;
543*8ccd4a63SDavid du Colombier 	d->vers = 0;
544*8ccd4a63SDavid du Colombier 	d->image = i;
545*8ccd4a63SDavid du Colombier 	d->nfchar = 0;
546*8ccd4a63SDavid du Colombier 	d->fchar = 0;
547*8ccd4a63SDavid du Colombier 	d->fromname = 0;
548*8ccd4a63SDavid du Colombier 	d->dscreen = dscreen;
549*8ccd4a63SDavid du Colombier 	d->next = client->dimage[id&HASHMASK];
550*8ccd4a63SDavid du Colombier 	client->dimage[id&HASHMASK] = d;
551*8ccd4a63SDavid du Colombier 	return i;
552*8ccd4a63SDavid du Colombier }
553*8ccd4a63SDavid du Colombier 
554*8ccd4a63SDavid du Colombier Memscreen*
555*8ccd4a63SDavid du Colombier drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
556*8ccd4a63SDavid du Colombier {
557*8ccd4a63SDavid du Colombier 	Memscreen *s;
558*8ccd4a63SDavid du Colombier 	CScreen *c;
559*8ccd4a63SDavid du Colombier 
560*8ccd4a63SDavid du Colombier 	c = malloc(sizeof(CScreen));
561*8ccd4a63SDavid du Colombier 	if(dimage && dimage->image && dimage->image->chan == 0)
562*8ccd4a63SDavid du Colombier 		panic("bad image %p in drawinstallscreen", dimage->image);
563*8ccd4a63SDavid du Colombier 
564*8ccd4a63SDavid du Colombier 	if(c == 0)
565*8ccd4a63SDavid du Colombier 		return 0;
566*8ccd4a63SDavid du Colombier 	if(d == 0){
567*8ccd4a63SDavid du Colombier 		d = malloc(sizeof(DScreen));
568*8ccd4a63SDavid du Colombier 		if(d == 0){
569*8ccd4a63SDavid du Colombier 			free(c);
570*8ccd4a63SDavid du Colombier 			return 0;
571*8ccd4a63SDavid du Colombier 		}
572*8ccd4a63SDavid du Colombier 		s = malloc(sizeof(Memscreen));
573*8ccd4a63SDavid du Colombier 		if(s == 0){
574*8ccd4a63SDavid du Colombier 			free(c);
575*8ccd4a63SDavid du Colombier 			free(d);
576*8ccd4a63SDavid du Colombier 			return 0;
577*8ccd4a63SDavid du Colombier 		}
578*8ccd4a63SDavid du Colombier 		s->frontmost = 0;
579*8ccd4a63SDavid du Colombier 		s->rearmost = 0;
580*8ccd4a63SDavid du Colombier 		d->dimage = dimage;
581*8ccd4a63SDavid du Colombier 		if(dimage){
582*8ccd4a63SDavid du Colombier 			s->image = dimage->image;
583*8ccd4a63SDavid du Colombier 			dimage->ref++;
584*8ccd4a63SDavid du Colombier 		}
585*8ccd4a63SDavid du Colombier 		d->dfill = dfill;
586*8ccd4a63SDavid du Colombier 		if(dfill){
587*8ccd4a63SDavid du Colombier 			s->fill = dfill->image;
588*8ccd4a63SDavid du Colombier 			dfill->ref++;
589*8ccd4a63SDavid du Colombier 		}
590*8ccd4a63SDavid du Colombier 		d->ref = 0;
591*8ccd4a63SDavid du Colombier 		d->id = id;
592*8ccd4a63SDavid du Colombier 		d->screen = s;
593*8ccd4a63SDavid du Colombier 		d->public = public;
594*8ccd4a63SDavid du Colombier 		d->next = dscreen;
595*8ccd4a63SDavid du Colombier 		d->owner = client;
596*8ccd4a63SDavid du Colombier 		dscreen = d;
597*8ccd4a63SDavid du Colombier 	}
598*8ccd4a63SDavid du Colombier 	c->dscreen = d;
599*8ccd4a63SDavid du Colombier 	d->ref++;
600*8ccd4a63SDavid du Colombier 	c->next = client->cscreen;
601*8ccd4a63SDavid du Colombier 	client->cscreen = c;
602*8ccd4a63SDavid du Colombier 	return d->screen;
603*8ccd4a63SDavid du Colombier }
604*8ccd4a63SDavid du Colombier 
605*8ccd4a63SDavid du Colombier void
606*8ccd4a63SDavid du Colombier drawdelname(DName *name)
607*8ccd4a63SDavid du Colombier {
608*8ccd4a63SDavid du Colombier 	int i;
609*8ccd4a63SDavid du Colombier 
610*8ccd4a63SDavid du Colombier 	i = name-sdraw.name;
611*8ccd4a63SDavid du Colombier 	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
612*8ccd4a63SDavid du Colombier 	sdraw.nname--;
613*8ccd4a63SDavid du Colombier }
614*8ccd4a63SDavid du Colombier 
615*8ccd4a63SDavid du Colombier void
616*8ccd4a63SDavid du Colombier drawfreedscreen(DScreen *this)
617*8ccd4a63SDavid du Colombier {
618*8ccd4a63SDavid du Colombier 	DScreen *ds, *next;
619*8ccd4a63SDavid du Colombier 
620*8ccd4a63SDavid du Colombier 	this->ref--;
621*8ccd4a63SDavid du Colombier 	if(this->ref < 0)
622*8ccd4a63SDavid du Colombier 		print("negative ref in drawfreedscreen\n");
623*8ccd4a63SDavid du Colombier 	if(this->ref > 0)
624*8ccd4a63SDavid du Colombier 		return;
625*8ccd4a63SDavid du Colombier 	ds = dscreen;
626*8ccd4a63SDavid du Colombier 	if(ds == this){
627*8ccd4a63SDavid du Colombier 		dscreen = this->next;
628*8ccd4a63SDavid du Colombier 		goto Found;
629*8ccd4a63SDavid du Colombier 	}
630*8ccd4a63SDavid du Colombier 	while((next = ds->next)){	/* assign = */
631*8ccd4a63SDavid du Colombier 		if(next == this){
632*8ccd4a63SDavid du Colombier 			ds->next = this->next;
633*8ccd4a63SDavid du Colombier 			goto Found;
634*8ccd4a63SDavid du Colombier 		}
635*8ccd4a63SDavid du Colombier 		ds = next;
636*8ccd4a63SDavid du Colombier 	}
637*8ccd4a63SDavid du Colombier 	error(Enodrawimage);
638*8ccd4a63SDavid du Colombier 
639*8ccd4a63SDavid du Colombier     Found:
640*8ccd4a63SDavid du Colombier 	if(this->dimage)
641*8ccd4a63SDavid du Colombier 		drawfreedimage(this->dimage);
642*8ccd4a63SDavid du Colombier 	if(this->dfill)
643*8ccd4a63SDavid du Colombier 		drawfreedimage(this->dfill);
644*8ccd4a63SDavid du Colombier 	free(this->screen);
645*8ccd4a63SDavid du Colombier 	free(this);
646*8ccd4a63SDavid du Colombier }
647*8ccd4a63SDavid du Colombier 
648*8ccd4a63SDavid du Colombier void
649*8ccd4a63SDavid du Colombier drawfreedimage(DImage *dimage)
650*8ccd4a63SDavid du Colombier {
651*8ccd4a63SDavid du Colombier 	int i;
652*8ccd4a63SDavid du Colombier 	Memimage *l;
653*8ccd4a63SDavid du Colombier 	DScreen *ds;
654*8ccd4a63SDavid du Colombier 
655*8ccd4a63SDavid du Colombier 	dimage->ref--;
656*8ccd4a63SDavid du Colombier 	if(dimage->ref < 0)
657*8ccd4a63SDavid du Colombier 		print("negative ref in drawfreedimage\n");
658*8ccd4a63SDavid du Colombier 	if(dimage->ref > 0)
659*8ccd4a63SDavid du Colombier 		return;
660*8ccd4a63SDavid du Colombier 
661*8ccd4a63SDavid du Colombier 	/* any names? */
662*8ccd4a63SDavid du Colombier 	for(i=0; i<sdraw.nname; )
663*8ccd4a63SDavid du Colombier 		if(sdraw.name[i].dimage == dimage)
664*8ccd4a63SDavid du Colombier 			drawdelname(sdraw.name+i);
665*8ccd4a63SDavid du Colombier 		else
666*8ccd4a63SDavid du Colombier 			i++;
667*8ccd4a63SDavid du Colombier 	if(dimage->fromname){	/* acquired by name; owned by someone else*/
668*8ccd4a63SDavid du Colombier 		drawfreedimage(dimage->fromname);
669*8ccd4a63SDavid du Colombier 		goto Return;
670*8ccd4a63SDavid du Colombier 	}
671*8ccd4a63SDavid du Colombier 	if(dimage->image == screenimage)	/* don't free the display */
672*8ccd4a63SDavid du Colombier 		goto Return;
673*8ccd4a63SDavid du Colombier 	ds = dimage->dscreen;
674*8ccd4a63SDavid du Colombier 	if(ds){
675*8ccd4a63SDavid du Colombier 		l = dimage->image;
676*8ccd4a63SDavid du Colombier 		if(l->data == screenimage->data)
677*8ccd4a63SDavid du Colombier 			addflush(l->layer->screenr);
678*8ccd4a63SDavid du Colombier 		if(l->layer->refreshfn == drawrefresh)	/* else true owner will clean up */
679*8ccd4a63SDavid du Colombier 			free(l->layer->refreshptr);
680*8ccd4a63SDavid du Colombier 		l->layer->refreshptr = nil;
681*8ccd4a63SDavid du Colombier 		if(drawgoodname(dimage))
682*8ccd4a63SDavid du Colombier 			memldelete(l);
683*8ccd4a63SDavid du Colombier 		else
684*8ccd4a63SDavid du Colombier 			memlfree(l);
685*8ccd4a63SDavid du Colombier 		drawfreedscreen(ds);
686*8ccd4a63SDavid du Colombier 	}else
687*8ccd4a63SDavid du Colombier 		freememimage(dimage->image);
688*8ccd4a63SDavid du Colombier     Return:
689*8ccd4a63SDavid du Colombier 	free(dimage->fchar);
690*8ccd4a63SDavid du Colombier 	free(dimage);
691*8ccd4a63SDavid du Colombier }
692*8ccd4a63SDavid du Colombier 
693*8ccd4a63SDavid du Colombier void
694*8ccd4a63SDavid du Colombier drawuninstallscreen(Client *client, CScreen *this)
695*8ccd4a63SDavid du Colombier {
696*8ccd4a63SDavid du Colombier 	CScreen *cs, *next;
697*8ccd4a63SDavid du Colombier 
698*8ccd4a63SDavid du Colombier 	cs = client->cscreen;
699*8ccd4a63SDavid du Colombier 	if(cs == this){
700*8ccd4a63SDavid du Colombier 		client->cscreen = this->next;
701*8ccd4a63SDavid du Colombier 		drawfreedscreen(this->dscreen);
702*8ccd4a63SDavid du Colombier 		free(this);
703*8ccd4a63SDavid du Colombier 		return;
704*8ccd4a63SDavid du Colombier 	}
705*8ccd4a63SDavid du Colombier 	while((next = cs->next)){	/* assign = */
706*8ccd4a63SDavid du Colombier 		if(next == this){
707*8ccd4a63SDavid du Colombier 			cs->next = this->next;
708*8ccd4a63SDavid du Colombier 			drawfreedscreen(this->dscreen);
709*8ccd4a63SDavid du Colombier 			free(this);
710*8ccd4a63SDavid du Colombier 			return;
711*8ccd4a63SDavid du Colombier 		}
712*8ccd4a63SDavid du Colombier 		cs = next;
713*8ccd4a63SDavid du Colombier 	}
714*8ccd4a63SDavid du Colombier }
715*8ccd4a63SDavid du Colombier 
716*8ccd4a63SDavid du Colombier void
717*8ccd4a63SDavid du Colombier drawuninstall(Client *client, int id)
718*8ccd4a63SDavid du Colombier {
719*8ccd4a63SDavid du Colombier 	DImage *d, *next;
720*8ccd4a63SDavid du Colombier 
721*8ccd4a63SDavid du Colombier 	d = client->dimage[id&HASHMASK];
722*8ccd4a63SDavid du Colombier 	if(d == 0)
723*8ccd4a63SDavid du Colombier 		error(Enodrawimage);
724*8ccd4a63SDavid du Colombier 	if(d->id == id){
725*8ccd4a63SDavid du Colombier 		client->dimage[id&HASHMASK] = d->next;
726*8ccd4a63SDavid du Colombier 		drawfreedimage(d);
727*8ccd4a63SDavid du Colombier 		return;
728*8ccd4a63SDavid du Colombier 	}
729*8ccd4a63SDavid du Colombier 	while((next = d->next)){	/* assign = */
730*8ccd4a63SDavid du Colombier 		if(next->id == id){
731*8ccd4a63SDavid du Colombier 			d->next = next->next;
732*8ccd4a63SDavid du Colombier 			drawfreedimage(next);
733*8ccd4a63SDavid du Colombier 			return;
734*8ccd4a63SDavid du Colombier 		}
735*8ccd4a63SDavid du Colombier 		d = next;
736*8ccd4a63SDavid du Colombier 	}
737*8ccd4a63SDavid du Colombier 	error(Enodrawimage);
738*8ccd4a63SDavid du Colombier }
739*8ccd4a63SDavid du Colombier 
740*8ccd4a63SDavid du Colombier void
741*8ccd4a63SDavid du Colombier drawaddname(Client *client, DImage *di, int n, char *str)
742*8ccd4a63SDavid du Colombier {
743*8ccd4a63SDavid du Colombier 	DName *name, *ename, *new, *t;
744*8ccd4a63SDavid du Colombier 
745*8ccd4a63SDavid du Colombier 	name = sdraw.name;
746*8ccd4a63SDavid du Colombier 	ename = &name[sdraw.nname];
747*8ccd4a63SDavid du Colombier 	for(; name<ename; name++)
748*8ccd4a63SDavid du Colombier 		if(drawcmp(name->name, str, n) == 0)
749*8ccd4a63SDavid du Colombier 			error(Enameused);
750*8ccd4a63SDavid du Colombier 	t = smalloc((sdraw.nname+1)*sizeof(DName));
751*8ccd4a63SDavid du Colombier 	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
752*8ccd4a63SDavid du Colombier 	free(sdraw.name);
753*8ccd4a63SDavid du Colombier 	sdraw.name = t;
754*8ccd4a63SDavid du Colombier 	new = &sdraw.name[sdraw.nname++];
755*8ccd4a63SDavid du Colombier 	new->name = smalloc(n+1);
756*8ccd4a63SDavid du Colombier 	memmove(new->name, str, n);
757*8ccd4a63SDavid du Colombier 	new->name[n] = 0;
758*8ccd4a63SDavid du Colombier 	new->dimage = di;
759*8ccd4a63SDavid du Colombier 	new->client = client;
760*8ccd4a63SDavid du Colombier 	new->vers = ++sdraw.vers;
761*8ccd4a63SDavid du Colombier }
762*8ccd4a63SDavid du Colombier 
763*8ccd4a63SDavid du Colombier Client*
764*8ccd4a63SDavid du Colombier drawnewclient(void)
765*8ccd4a63SDavid du Colombier {
766*8ccd4a63SDavid du Colombier 	Client *cl, **cp;
767*8ccd4a63SDavid du Colombier 	int i;
768*8ccd4a63SDavid du Colombier 
769*8ccd4a63SDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
770*8ccd4a63SDavid du Colombier 		cl = sdraw.client[i];
771*8ccd4a63SDavid du Colombier 		if(cl == 0)
772*8ccd4a63SDavid du Colombier 			break;
773*8ccd4a63SDavid du Colombier 	}
774*8ccd4a63SDavid du Colombier 	if(i == sdraw.nclient){
775*8ccd4a63SDavid du Colombier 		cp = malloc((sdraw.nclient+1)*sizeof(Client*));
776*8ccd4a63SDavid du Colombier 		if(cp == 0)
777*8ccd4a63SDavid du Colombier 			return 0;
778*8ccd4a63SDavid du Colombier 		memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
779*8ccd4a63SDavid du Colombier 		free(sdraw.client);
780*8ccd4a63SDavid du Colombier 		sdraw.client = cp;
781*8ccd4a63SDavid du Colombier 		sdraw.nclient++;
782*8ccd4a63SDavid du Colombier 		cp[i] = 0;
783*8ccd4a63SDavid du Colombier 	}
784*8ccd4a63SDavid du Colombier 	cl = malloc(sizeof(Client));
785*8ccd4a63SDavid du Colombier 	if(cl == 0)
786*8ccd4a63SDavid du Colombier 		return 0;
787*8ccd4a63SDavid du Colombier 	memset(cl, 0, sizeof(Client));
788*8ccd4a63SDavid du Colombier 	cl->slot = i;
789*8ccd4a63SDavid du Colombier 	cl->clientid = ++sdraw.clientid;
790*8ccd4a63SDavid du Colombier 	cl->op = SoverD;
791*8ccd4a63SDavid du Colombier 	sdraw.client[i] = cl;
792*8ccd4a63SDavid du Colombier 	return cl;
793*8ccd4a63SDavid du Colombier }
794*8ccd4a63SDavid du Colombier 
795*8ccd4a63SDavid du Colombier static int
796*8ccd4a63SDavid du Colombier drawclientop(Client *cl)
797*8ccd4a63SDavid du Colombier {
798*8ccd4a63SDavid du Colombier 	int op;
799*8ccd4a63SDavid du Colombier 
800*8ccd4a63SDavid du Colombier 	op = cl->op;
801*8ccd4a63SDavid du Colombier 	cl->op = SoverD;
802*8ccd4a63SDavid du Colombier 	return op;
803*8ccd4a63SDavid du Colombier }
804*8ccd4a63SDavid du Colombier 
805*8ccd4a63SDavid du Colombier int
806*8ccd4a63SDavid du Colombier drawhasclients(void)
807*8ccd4a63SDavid du Colombier {
808*8ccd4a63SDavid du Colombier 	/*
809*8ccd4a63SDavid du Colombier 	 * if draw has ever been used, we can't resize the frame buffer,
810*8ccd4a63SDavid du Colombier 	 * even if all clients have exited (nclients is cumulative); it's too
811*8ccd4a63SDavid du Colombier 	 * hard to make work.
812*8ccd4a63SDavid du Colombier 	 */
813*8ccd4a63SDavid du Colombier 	return sdraw.nclient != 0;
814*8ccd4a63SDavid du Colombier }
815*8ccd4a63SDavid du Colombier 
816*8ccd4a63SDavid du Colombier Client*
817*8ccd4a63SDavid du Colombier drawclientofpath(ulong path)
818*8ccd4a63SDavid du Colombier {
819*8ccd4a63SDavid du Colombier 	Client *cl;
820*8ccd4a63SDavid du Colombier 	int slot;
821*8ccd4a63SDavid du Colombier 
822*8ccd4a63SDavid du Colombier 	slot = CLIENTPATH(path);
823*8ccd4a63SDavid du Colombier 	if(slot == 0)
824*8ccd4a63SDavid du Colombier 		return nil;
825*8ccd4a63SDavid du Colombier 	cl = sdraw.client[slot-1];
826*8ccd4a63SDavid du Colombier 	if(cl==0 || cl->clientid==0)
827*8ccd4a63SDavid du Colombier 		return nil;
828*8ccd4a63SDavid du Colombier 	return cl;
829*8ccd4a63SDavid du Colombier }
830*8ccd4a63SDavid du Colombier 
831*8ccd4a63SDavid du Colombier 
832*8ccd4a63SDavid du Colombier Client*
833*8ccd4a63SDavid du Colombier drawclient(Chan *c)
834*8ccd4a63SDavid du Colombier {
835*8ccd4a63SDavid du Colombier 	Client *client;
836*8ccd4a63SDavid du Colombier 
837*8ccd4a63SDavid du Colombier 	client = drawclientofpath(c->qid.path);
838*8ccd4a63SDavid du Colombier 	if(client == nil)
839*8ccd4a63SDavid du Colombier 		error(Enoclient);
840*8ccd4a63SDavid du Colombier 	return client;
841*8ccd4a63SDavid du Colombier }
842*8ccd4a63SDavid du Colombier 
843*8ccd4a63SDavid du Colombier Memimage*
844*8ccd4a63SDavid du Colombier drawimage(Client *client, uchar *a)
845*8ccd4a63SDavid du Colombier {
846*8ccd4a63SDavid du Colombier 	DImage *d;
847*8ccd4a63SDavid du Colombier 
848*8ccd4a63SDavid du Colombier 	d = drawlookup(client, BGLONG(a), 1);
849*8ccd4a63SDavid du Colombier 	if(d == nil)
850*8ccd4a63SDavid du Colombier 		error(Enodrawimage);
851*8ccd4a63SDavid du Colombier 	return d->image;
852*8ccd4a63SDavid du Colombier }
853*8ccd4a63SDavid du Colombier 
854*8ccd4a63SDavid du Colombier void
855*8ccd4a63SDavid du Colombier drawrectangle(Rectangle *r, uchar *a)
856*8ccd4a63SDavid du Colombier {
857*8ccd4a63SDavid du Colombier 	r->min.x = BGLONG(a+0*4);
858*8ccd4a63SDavid du Colombier 	r->min.y = BGLONG(a+1*4);
859*8ccd4a63SDavid du Colombier 	r->max.x = BGLONG(a+2*4);
860*8ccd4a63SDavid du Colombier 	r->max.y = BGLONG(a+3*4);
861*8ccd4a63SDavid du Colombier }
862*8ccd4a63SDavid du Colombier 
863*8ccd4a63SDavid du Colombier void
864*8ccd4a63SDavid du Colombier drawpoint(Point *p, uchar *a)
865*8ccd4a63SDavid du Colombier {
866*8ccd4a63SDavid du Colombier 	p->x = BGLONG(a+0*4);
867*8ccd4a63SDavid du Colombier 	p->y = BGLONG(a+1*4);
868*8ccd4a63SDavid du Colombier }
869*8ccd4a63SDavid du Colombier 
870*8ccd4a63SDavid du Colombier Point
871*8ccd4a63SDavid du Colombier drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
872*8ccd4a63SDavid du Colombier {
873*8ccd4a63SDavid du Colombier 	FChar *fc;
874*8ccd4a63SDavid du Colombier 	Rectangle r;
875*8ccd4a63SDavid du Colombier 	Point sp1;
876*8ccd4a63SDavid du Colombier 
877*8ccd4a63SDavid du Colombier 	fc = &font->fchar[index];
878*8ccd4a63SDavid du Colombier 	r.min.x = p.x+fc->left;
879*8ccd4a63SDavid du Colombier 	r.min.y = p.y-(font->ascent-fc->miny);
880*8ccd4a63SDavid du Colombier 	r.max.x = r.min.x+(fc->maxx-fc->minx);
881*8ccd4a63SDavid du Colombier 	r.max.y = r.min.y+(fc->maxy-fc->miny);
882*8ccd4a63SDavid du Colombier 	sp1.x = sp->x+fc->left;
883*8ccd4a63SDavid du Colombier 	sp1.y = sp->y+fc->miny;
884*8ccd4a63SDavid du Colombier 	memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
885*8ccd4a63SDavid du Colombier 	p.x += fc->width;
886*8ccd4a63SDavid du Colombier 	sp->x += fc->width;
887*8ccd4a63SDavid du Colombier 	return p;
888*8ccd4a63SDavid du Colombier }
889*8ccd4a63SDavid du Colombier 
890*8ccd4a63SDavid du Colombier static int
891*8ccd4a63SDavid du Colombier initscreenimage(void)
892*8ccd4a63SDavid du Colombier {
893*8ccd4a63SDavid du Colombier 	int width, depth;
894*8ccd4a63SDavid du Colombier 	ulong chan;
895*8ccd4a63SDavid du Colombier 	void *X;
896*8ccd4a63SDavid du Colombier 	Rectangle r;
897*8ccd4a63SDavid du Colombier 
898*8ccd4a63SDavid du Colombier 	if(screenimage != nil)
899*8ccd4a63SDavid du Colombier 		return 1;
900*8ccd4a63SDavid du Colombier 
901*8ccd4a63SDavid du Colombier 	screendata.base = nil;
902*8ccd4a63SDavid du Colombier 	screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);
903*8ccd4a63SDavid du Colombier 	if(screendata.bdata == nil && X == nil)
904*8ccd4a63SDavid du Colombier 		return 0;
905*8ccd4a63SDavid du Colombier 	screendata.ref = 1;
906*8ccd4a63SDavid du Colombier 
907*8ccd4a63SDavid du Colombier 	screenimage = allocmemimaged(r, chan, &screendata, X);
908*8ccd4a63SDavid du Colombier 	if(screenimage == nil){
909*8ccd4a63SDavid du Colombier 		/* RSC: BUG: detach screen */
910*8ccd4a63SDavid du Colombier 		return 0;
911*8ccd4a63SDavid du Colombier 	}
912*8ccd4a63SDavid du Colombier 
913*8ccd4a63SDavid du Colombier 	screenimage->width = width;
914*8ccd4a63SDavid du Colombier 	screenimage->clipr = r;
915*8ccd4a63SDavid du Colombier 	return 1;
916*8ccd4a63SDavid du Colombier }
917*8ccd4a63SDavid du Colombier 
918*8ccd4a63SDavid du Colombier void
919*8ccd4a63SDavid du Colombier deletescreenimage(void)
920*8ccd4a63SDavid du Colombier {
921*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
922*8ccd4a63SDavid du Colombier 	/* RSC: BUG: detach screen */
923*8ccd4a63SDavid du Colombier 	if(screenimage)
924*8ccd4a63SDavid du Colombier 		freememimage(screenimage);
925*8ccd4a63SDavid du Colombier 	screenimage = nil;
926*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
927*8ccd4a63SDavid du Colombier }
928*8ccd4a63SDavid du Colombier 
929*8ccd4a63SDavid du Colombier static Chan*
930*8ccd4a63SDavid du Colombier drawattach(char *spec)
931*8ccd4a63SDavid du Colombier {
932*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
933*8ccd4a63SDavid du Colombier 	if(!initscreenimage()){
934*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
935*8ccd4a63SDavid du Colombier 		error("no frame buffer");
936*8ccd4a63SDavid du Colombier 	}
937*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
938*8ccd4a63SDavid du Colombier 	return devattach('i', spec);
939*8ccd4a63SDavid du Colombier }
940*8ccd4a63SDavid du Colombier 
941*8ccd4a63SDavid du Colombier static Walkqid*
942*8ccd4a63SDavid du Colombier drawwalk(Chan *c, Chan *nc, char **name, int nname)
943*8ccd4a63SDavid du Colombier {
944*8ccd4a63SDavid du Colombier 	if(screendata.bdata == nil)
945*8ccd4a63SDavid du Colombier 		error("no frame buffer");
946*8ccd4a63SDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, drawgen);
947*8ccd4a63SDavid du Colombier }
948*8ccd4a63SDavid du Colombier 
949*8ccd4a63SDavid du Colombier static int
950*8ccd4a63SDavid du Colombier drawstat(Chan *c, uchar *db, int n)
951*8ccd4a63SDavid du Colombier {
952*8ccd4a63SDavid du Colombier 	return devstat(c, db, n, 0, 0, drawgen);
953*8ccd4a63SDavid du Colombier }
954*8ccd4a63SDavid du Colombier 
955*8ccd4a63SDavid du Colombier static Chan*
956*8ccd4a63SDavid du Colombier drawopen(Chan *c, int omode)
957*8ccd4a63SDavid du Colombier {
958*8ccd4a63SDavid du Colombier 	Client *cl;
959*8ccd4a63SDavid du Colombier 
960*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR){
961*8ccd4a63SDavid du Colombier 		c = devopen(c, omode, 0, 0, drawgen);
962*8ccd4a63SDavid du Colombier 		c->iounit = IOUNIT;
963*8ccd4a63SDavid du Colombier 	}
964*8ccd4a63SDavid du Colombier 
965*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
966*8ccd4a63SDavid du Colombier 	if(waserror()){
967*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
968*8ccd4a63SDavid du Colombier 		nexterror();
969*8ccd4a63SDavid du Colombier 	}
970*8ccd4a63SDavid du Colombier 
971*8ccd4a63SDavid du Colombier 	if(QID(c->qid) == Qnew){
972*8ccd4a63SDavid du Colombier 		cl = drawnewclient();
973*8ccd4a63SDavid du Colombier 		if(cl == 0)
974*8ccd4a63SDavid du Colombier 			error(Enodev);
975*8ccd4a63SDavid du Colombier 		c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
976*8ccd4a63SDavid du Colombier 	}
977*8ccd4a63SDavid du Colombier 
978*8ccd4a63SDavid du Colombier 	switch(QID(c->qid)){
979*8ccd4a63SDavid du Colombier 	case Qnew:
980*8ccd4a63SDavid du Colombier 		break;
981*8ccd4a63SDavid du Colombier 
982*8ccd4a63SDavid du Colombier 	case Qctl:
983*8ccd4a63SDavid du Colombier 		cl = drawclient(c);
984*8ccd4a63SDavid du Colombier 		if(cl->busy)
985*8ccd4a63SDavid du Colombier 			error(Einuse);
986*8ccd4a63SDavid du Colombier 		cl->busy = 1;
987*8ccd4a63SDavid du Colombier 		flushrect = Rect(10000, 10000, -10000, -10000);
988*8ccd4a63SDavid du Colombier 		drawinstall(cl, 0, screenimage, 0);
989*8ccd4a63SDavid du Colombier 		incref(&cl->r);
990*8ccd4a63SDavid du Colombier 		break;
991*8ccd4a63SDavid du Colombier 	case Qcolormap:
992*8ccd4a63SDavid du Colombier 	case Qdata:
993*8ccd4a63SDavid du Colombier 	case Qrefresh:
994*8ccd4a63SDavid du Colombier 		cl = drawclient(c);
995*8ccd4a63SDavid du Colombier 		incref(&cl->r);
996*8ccd4a63SDavid du Colombier 		break;
997*8ccd4a63SDavid du Colombier 	}
998*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
999*8ccd4a63SDavid du Colombier 	poperror();
1000*8ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
1001*8ccd4a63SDavid du Colombier 	c->flag |= COPEN;
1002*8ccd4a63SDavid du Colombier 	c->offset = 0;
1003*8ccd4a63SDavid du Colombier 	c->iounit = IOUNIT;
1004*8ccd4a63SDavid du Colombier 	return c;
1005*8ccd4a63SDavid du Colombier }
1006*8ccd4a63SDavid du Colombier 
1007*8ccd4a63SDavid du Colombier static void
1008*8ccd4a63SDavid du Colombier drawclose(Chan *c)
1009*8ccd4a63SDavid du Colombier {
1010*8ccd4a63SDavid du Colombier 	int i;
1011*8ccd4a63SDavid du Colombier 	DImage *d, **dp;
1012*8ccd4a63SDavid du Colombier 	Client *cl;
1013*8ccd4a63SDavid du Colombier 	Refresh *r;
1014*8ccd4a63SDavid du Colombier 
1015*8ccd4a63SDavid du Colombier 	if(QID(c->qid) < Qcolormap)	/* Qtopdir, Qnew, Q3rd, Q2nd have no client */
1016*8ccd4a63SDavid du Colombier 		return;
1017*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
1018*8ccd4a63SDavid du Colombier 	if(waserror()){
1019*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
1020*8ccd4a63SDavid du Colombier 		nexterror();
1021*8ccd4a63SDavid du Colombier 	}
1022*8ccd4a63SDavid du Colombier 
1023*8ccd4a63SDavid du Colombier 	cl = drawclient(c);
1024*8ccd4a63SDavid du Colombier 	if(QID(c->qid) == Qctl)
1025*8ccd4a63SDavid du Colombier 		cl->busy = 0;
1026*8ccd4a63SDavid du Colombier 	if((c->flag&COPEN) && (decref(&cl->r)==0)){
1027*8ccd4a63SDavid du Colombier 		while((r = cl->refresh)){	/* assign = */
1028*8ccd4a63SDavid du Colombier 			cl->refresh = r->next;
1029*8ccd4a63SDavid du Colombier 			free(r);
1030*8ccd4a63SDavid du Colombier 		}
1031*8ccd4a63SDavid du Colombier 		/* free names */
1032*8ccd4a63SDavid du Colombier 		for(i=0; i<sdraw.nname; )
1033*8ccd4a63SDavid du Colombier 			if(sdraw.name[i].client == cl)
1034*8ccd4a63SDavid du Colombier 				drawdelname(sdraw.name+i);
1035*8ccd4a63SDavid du Colombier 			else
1036*8ccd4a63SDavid du Colombier 				i++;
1037*8ccd4a63SDavid du Colombier 		while(cl->cscreen)
1038*8ccd4a63SDavid du Colombier 			drawuninstallscreen(cl, cl->cscreen);
1039*8ccd4a63SDavid du Colombier 		/* all screens are freed, so now we can free images */
1040*8ccd4a63SDavid du Colombier 		dp = cl->dimage;
1041*8ccd4a63SDavid du Colombier 		for(i=0; i<NHASH; i++){
1042*8ccd4a63SDavid du Colombier 			while((d = *dp) != nil){
1043*8ccd4a63SDavid du Colombier 				*dp = d->next;
1044*8ccd4a63SDavid du Colombier 				drawfreedimage(d);
1045*8ccd4a63SDavid du Colombier 			}
1046*8ccd4a63SDavid du Colombier 			dp++;
1047*8ccd4a63SDavid du Colombier 		}
1048*8ccd4a63SDavid du Colombier 		sdraw.client[cl->slot] = 0;
1049*8ccd4a63SDavid du Colombier 		drawflush();	/* to erase visible, now dead windows */
1050*8ccd4a63SDavid du Colombier 		free(cl);
1051*8ccd4a63SDavid du Colombier 	}
1052*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
1053*8ccd4a63SDavid du Colombier 	poperror();
1054*8ccd4a63SDavid du Colombier }
1055*8ccd4a63SDavid du Colombier 
1056*8ccd4a63SDavid du Colombier long
1057*8ccd4a63SDavid du Colombier drawread(Chan *c, void *a, long n, vlong off)
1058*8ccd4a63SDavid du Colombier {
1059*8ccd4a63SDavid du Colombier 	int index, m;
1060*8ccd4a63SDavid du Colombier 	ulong red, green, blue;
1061*8ccd4a63SDavid du Colombier 	Client *cl;
1062*8ccd4a63SDavid du Colombier 	uchar *p;
1063*8ccd4a63SDavid du Colombier 	Refresh *r;
1064*8ccd4a63SDavid du Colombier 	DImage *di;
1065*8ccd4a63SDavid du Colombier 	Memimage *i;
1066*8ccd4a63SDavid du Colombier 	ulong offset = off;
1067*8ccd4a63SDavid du Colombier 	char buf[16];
1068*8ccd4a63SDavid du Colombier 
1069*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
1070*8ccd4a63SDavid du Colombier 		return devdirread(c, a, n, 0, 0, drawgen);
1071*8ccd4a63SDavid du Colombier 	cl = drawclient(c);
1072*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
1073*8ccd4a63SDavid du Colombier 	if(waserror()){
1074*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
1075*8ccd4a63SDavid du Colombier 		nexterror();
1076*8ccd4a63SDavid du Colombier 	}
1077*8ccd4a63SDavid du Colombier 	switch(QID(c->qid)){
1078*8ccd4a63SDavid du Colombier 	case Qctl:
1079*8ccd4a63SDavid du Colombier 		if(n < 12*12)
1080*8ccd4a63SDavid du Colombier 			error(Eshortread);
1081*8ccd4a63SDavid du Colombier 		if(cl->infoid < 0)
1082*8ccd4a63SDavid du Colombier 			error(Enodrawimage);
1083*8ccd4a63SDavid du Colombier 		if(cl->infoid == 0){
1084*8ccd4a63SDavid du Colombier 			i = screenimage;
1085*8ccd4a63SDavid du Colombier 			if(i == nil)
1086*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1087*8ccd4a63SDavid du Colombier 		}else{
1088*8ccd4a63SDavid du Colombier 			di = drawlookup(cl, cl->infoid, 1);
1089*8ccd4a63SDavid du Colombier 			if(di == nil)
1090*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1091*8ccd4a63SDavid du Colombier 			i = di->image;
1092*8ccd4a63SDavid du Colombier 		}
1093*8ccd4a63SDavid du Colombier 		n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
1094*8ccd4a63SDavid du Colombier 			cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
1095*8ccd4a63SDavid du Colombier 			i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
1096*8ccd4a63SDavid du Colombier 			i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
1097*8ccd4a63SDavid du Colombier 		cl->infoid = -1;
1098*8ccd4a63SDavid du Colombier 		break;
1099*8ccd4a63SDavid du Colombier 
1100*8ccd4a63SDavid du Colombier 	case Qcolormap:
1101*8ccd4a63SDavid du Colombier 		drawactive(1);	/* to restore map from backup */
1102*8ccd4a63SDavid du Colombier 		p = malloc(4*12*256+1);
1103*8ccd4a63SDavid du Colombier 		if(p == 0)
1104*8ccd4a63SDavid du Colombier 			error(Enomem);
1105*8ccd4a63SDavid du Colombier 		m = 0;
1106*8ccd4a63SDavid du Colombier 		for(index = 0; index < 256; index++){
1107*8ccd4a63SDavid du Colombier 			getcolor(index, &red, &green, &blue);
1108*8ccd4a63SDavid du Colombier 			m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
1109*8ccd4a63SDavid du Colombier 		}
1110*8ccd4a63SDavid du Colombier 		n = readstr(offset, a, n, (char*)p);
1111*8ccd4a63SDavid du Colombier 		free(p);
1112*8ccd4a63SDavid du Colombier 		break;
1113*8ccd4a63SDavid du Colombier 
1114*8ccd4a63SDavid du Colombier 	case Qdata:
1115*8ccd4a63SDavid du Colombier 		if(cl->readdata == nil)
1116*8ccd4a63SDavid du Colombier 			error("no draw data");
1117*8ccd4a63SDavid du Colombier 		if(n < cl->nreaddata)
1118*8ccd4a63SDavid du Colombier 			error(Eshortread);
1119*8ccd4a63SDavid du Colombier 		n = cl->nreaddata;
1120*8ccd4a63SDavid du Colombier 		memmove(a, cl->readdata, cl->nreaddata);
1121*8ccd4a63SDavid du Colombier 		free(cl->readdata);
1122*8ccd4a63SDavid du Colombier 		cl->readdata = nil;
1123*8ccd4a63SDavid du Colombier 		break;
1124*8ccd4a63SDavid du Colombier 
1125*8ccd4a63SDavid du Colombier 	case Qrefresh:
1126*8ccd4a63SDavid du Colombier 		if(n < 5*4)
1127*8ccd4a63SDavid du Colombier 			error(Ebadarg);
1128*8ccd4a63SDavid du Colombier 		for(;;){
1129*8ccd4a63SDavid du Colombier 			if(cl->refreshme || cl->refresh)
1130*8ccd4a63SDavid du Colombier 				break;
1131*8ccd4a63SDavid du Colombier 			qunlock(&sdraw.lk);
1132*8ccd4a63SDavid du Colombier 			if(waserror()){
1133*8ccd4a63SDavid du Colombier 				qlock(&sdraw.lk);	/* restore lock for waserror() above */
1134*8ccd4a63SDavid du Colombier 				nexterror();
1135*8ccd4a63SDavid du Colombier 			}
1136*8ccd4a63SDavid du Colombier 			sleep(&cl->refrend, drawrefactive, cl);
1137*8ccd4a63SDavid du Colombier 			poperror();
1138*8ccd4a63SDavid du Colombier 			qlock(&sdraw.lk);
1139*8ccd4a63SDavid du Colombier 		}
1140*8ccd4a63SDavid du Colombier 		p = a;
1141*8ccd4a63SDavid du Colombier 		while(cl->refresh && n>=5*4){
1142*8ccd4a63SDavid du Colombier 			r = cl->refresh;
1143*8ccd4a63SDavid du Colombier 			BPLONG(p+0*4, r->dimage->id);
1144*8ccd4a63SDavid du Colombier 			BPLONG(p+1*4, r->r.min.x);
1145*8ccd4a63SDavid du Colombier 			BPLONG(p+2*4, r->r.min.y);
1146*8ccd4a63SDavid du Colombier 			BPLONG(p+3*4, r->r.max.x);
1147*8ccd4a63SDavid du Colombier 			BPLONG(p+4*4, r->r.max.y);
1148*8ccd4a63SDavid du Colombier 			cl->refresh = r->next;
1149*8ccd4a63SDavid du Colombier 			free(r);
1150*8ccd4a63SDavid du Colombier 			p += 5*4;
1151*8ccd4a63SDavid du Colombier 			n -= 5*4;
1152*8ccd4a63SDavid du Colombier 		}
1153*8ccd4a63SDavid du Colombier 		cl->refreshme = 0;
1154*8ccd4a63SDavid du Colombier 		n = p-(uchar*)a;
1155*8ccd4a63SDavid du Colombier 	}
1156*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
1157*8ccd4a63SDavid du Colombier 	poperror();
1158*8ccd4a63SDavid du Colombier 	return n;
1159*8ccd4a63SDavid du Colombier }
1160*8ccd4a63SDavid du Colombier 
1161*8ccd4a63SDavid du Colombier void
1162*8ccd4a63SDavid du Colombier drawwakeall(void)
1163*8ccd4a63SDavid du Colombier {
1164*8ccd4a63SDavid du Colombier 	Client *cl;
1165*8ccd4a63SDavid du Colombier 	int i;
1166*8ccd4a63SDavid du Colombier 
1167*8ccd4a63SDavid du Colombier 	for(i=0; i<sdraw.nclient; i++){
1168*8ccd4a63SDavid du Colombier 		cl = sdraw.client[i];
1169*8ccd4a63SDavid du Colombier 		if(cl && (cl->refreshme || cl->refresh))
1170*8ccd4a63SDavid du Colombier 			wakeup(&cl->refrend);
1171*8ccd4a63SDavid du Colombier 	}
1172*8ccd4a63SDavid du Colombier }
1173*8ccd4a63SDavid du Colombier 
1174*8ccd4a63SDavid du Colombier static long
1175*8ccd4a63SDavid du Colombier drawwrite(Chan *c, void *a, long n, vlong offset)
1176*8ccd4a63SDavid du Colombier {
1177*8ccd4a63SDavid du Colombier 	char buf[128], *fields[4], *q;
1178*8ccd4a63SDavid du Colombier 	Client *cl;
1179*8ccd4a63SDavid du Colombier 	int i, m, red, green, blue, x;
1180*8ccd4a63SDavid du Colombier 
1181*8ccd4a63SDavid du Colombier 	USED(offset);
1182*8ccd4a63SDavid du Colombier 
1183*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
1184*8ccd4a63SDavid du Colombier 		error(Eisdir);
1185*8ccd4a63SDavid du Colombier 	cl = drawclient(c);
1186*8ccd4a63SDavid du Colombier 	qlock(&sdraw.lk);
1187*8ccd4a63SDavid du Colombier 	if(waserror()){
1188*8ccd4a63SDavid du Colombier 		drawwakeall();
1189*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
1190*8ccd4a63SDavid du Colombier 		nexterror();
1191*8ccd4a63SDavid du Colombier 	}
1192*8ccd4a63SDavid du Colombier 	switch(QID(c->qid)){
1193*8ccd4a63SDavid du Colombier 	case Qctl:
1194*8ccd4a63SDavid du Colombier 		if(n != 4)
1195*8ccd4a63SDavid du Colombier 			error("unknown draw control request");
1196*8ccd4a63SDavid du Colombier 		cl->infoid = BGLONG((uchar*)a);
1197*8ccd4a63SDavid du Colombier 		break;
1198*8ccd4a63SDavid du Colombier 
1199*8ccd4a63SDavid du Colombier 	case Qcolormap:
1200*8ccd4a63SDavid du Colombier 		drawactive(1);	/* to restore map from backup */
1201*8ccd4a63SDavid du Colombier 		m = n;
1202*8ccd4a63SDavid du Colombier 		n = 0;
1203*8ccd4a63SDavid du Colombier 		while(m > 0){
1204*8ccd4a63SDavid du Colombier 			x = m;
1205*8ccd4a63SDavid du Colombier 			if(x > sizeof(buf)-1)
1206*8ccd4a63SDavid du Colombier 				x = sizeof(buf)-1;
1207*8ccd4a63SDavid du Colombier 			q = memccpy(buf, a, '\n', x);
1208*8ccd4a63SDavid du Colombier 			if(q == 0)
1209*8ccd4a63SDavid du Colombier 				break;
1210*8ccd4a63SDavid du Colombier 			i = q-buf;
1211*8ccd4a63SDavid du Colombier 			n += i;
1212*8ccd4a63SDavid du Colombier 			a = (char*)a + i;
1213*8ccd4a63SDavid du Colombier 			m -= i;
1214*8ccd4a63SDavid du Colombier 			*q = 0;
1215*8ccd4a63SDavid du Colombier 			if(tokenize(buf, fields, nelem(fields)) != 4)
1216*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1217*8ccd4a63SDavid du Colombier 			i = strtoul(fields[0], 0, 0);
1218*8ccd4a63SDavid du Colombier 			red = strtoul(fields[1], 0, 0);
1219*8ccd4a63SDavid du Colombier 			green = strtoul(fields[2], 0, 0);
1220*8ccd4a63SDavid du Colombier 			blue = strtoul(fields[3], &q, 0);
1221*8ccd4a63SDavid du Colombier 			if(fields[3] == q)
1222*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1223*8ccd4a63SDavid du Colombier 			if(red>255 || green>255 || blue>255 || i<0 || i>255)
1224*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1225*8ccd4a63SDavid du Colombier 			red |= red<<8;
1226*8ccd4a63SDavid du Colombier 			red |= red<<16;
1227*8ccd4a63SDavid du Colombier 			green |= green<<8;
1228*8ccd4a63SDavid du Colombier 			green |= green<<16;
1229*8ccd4a63SDavid du Colombier 			blue |= blue<<8;
1230*8ccd4a63SDavid du Colombier 			blue |= blue<<16;
1231*8ccd4a63SDavid du Colombier 			setcolor(i, red, green, blue);
1232*8ccd4a63SDavid du Colombier 		}
1233*8ccd4a63SDavid du Colombier 		break;
1234*8ccd4a63SDavid du Colombier 
1235*8ccd4a63SDavid du Colombier 	case Qdata:
1236*8ccd4a63SDavid du Colombier 		drawmesg(cl, a, n);
1237*8ccd4a63SDavid du Colombier 		drawwakeall();
1238*8ccd4a63SDavid du Colombier 		break;
1239*8ccd4a63SDavid du Colombier 
1240*8ccd4a63SDavid du Colombier 	default:
1241*8ccd4a63SDavid du Colombier 		error(Ebadusefd);
1242*8ccd4a63SDavid du Colombier 	}
1243*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
1244*8ccd4a63SDavid du Colombier 	poperror();
1245*8ccd4a63SDavid du Colombier 	return n;
1246*8ccd4a63SDavid du Colombier }
1247*8ccd4a63SDavid du Colombier 
1248*8ccd4a63SDavid du Colombier uchar*
1249*8ccd4a63SDavid du Colombier drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
1250*8ccd4a63SDavid du Colombier {
1251*8ccd4a63SDavid du Colombier 	int b, x;
1252*8ccd4a63SDavid du Colombier 
1253*8ccd4a63SDavid du Colombier 	if(p >= maxp)
1254*8ccd4a63SDavid du Colombier 		error(Eshortdraw);
1255*8ccd4a63SDavid du Colombier 	b = *p++;
1256*8ccd4a63SDavid du Colombier 	x = b & 0x7F;
1257*8ccd4a63SDavid du Colombier 	if(b & 0x80){
1258*8ccd4a63SDavid du Colombier 		if(p+1 >= maxp)
1259*8ccd4a63SDavid du Colombier 			error(Eshortdraw);
1260*8ccd4a63SDavid du Colombier 		x |= *p++ << 7;
1261*8ccd4a63SDavid du Colombier 		x |= *p++ << 15;
1262*8ccd4a63SDavid du Colombier 		if(x & (1<<22))
1263*8ccd4a63SDavid du Colombier 			x |= ~0<<23;
1264*8ccd4a63SDavid du Colombier 	}else{
1265*8ccd4a63SDavid du Colombier 		if(b & 0x40)
1266*8ccd4a63SDavid du Colombier 			x |= ~0<<7;
1267*8ccd4a63SDavid du Colombier 		x += oldx;
1268*8ccd4a63SDavid du Colombier 	}
1269*8ccd4a63SDavid du Colombier 	*newx = x;
1270*8ccd4a63SDavid du Colombier 	return p;
1271*8ccd4a63SDavid du Colombier }
1272*8ccd4a63SDavid du Colombier 
1273*8ccd4a63SDavid du Colombier static void
1274*8ccd4a63SDavid du Colombier printmesg(char *fmt, uchar *a, int plsprnt)
1275*8ccd4a63SDavid du Colombier {
1276*8ccd4a63SDavid du Colombier 	char buf[256];
1277*8ccd4a63SDavid du Colombier 	char *p, *q;
1278*8ccd4a63SDavid du Colombier 	int s;
1279*8ccd4a63SDavid du Colombier 
1280*8ccd4a63SDavid du Colombier 	if(1|| plsprnt==0){
1281*8ccd4a63SDavid du Colombier 		SET(s);
1282*8ccd4a63SDavid du Colombier 		SET(q);
1283*8ccd4a63SDavid du Colombier 		SET(p);
1284*8ccd4a63SDavid du Colombier 		USED(fmt);
1285*8ccd4a63SDavid du Colombier 		USED(a);
1286*8ccd4a63SDavid du Colombier 		USED(buf);
1287*8ccd4a63SDavid du Colombier 		USED(p);
1288*8ccd4a63SDavid du Colombier 		USED(q);
1289*8ccd4a63SDavid du Colombier 		USED(s);
1290*8ccd4a63SDavid du Colombier 		return;
1291*8ccd4a63SDavid du Colombier 	}
1292*8ccd4a63SDavid du Colombier 	q = buf;
1293*8ccd4a63SDavid du Colombier 	*q++ = *a++;
1294*8ccd4a63SDavid du Colombier 	for(p=fmt; *p; p++){
1295*8ccd4a63SDavid du Colombier 		switch(*p){
1296*8ccd4a63SDavid du Colombier 		case 'l':
1297*8ccd4a63SDavid du Colombier 			q += sprint(q, " %ld", (long)BGLONG(a));
1298*8ccd4a63SDavid du Colombier 			a += 4;
1299*8ccd4a63SDavid du Colombier 			break;
1300*8ccd4a63SDavid du Colombier 		case 'L':
1301*8ccd4a63SDavid du Colombier 			q += sprint(q, " %.8lux", (ulong)BGLONG(a));
1302*8ccd4a63SDavid du Colombier 			a += 4;
1303*8ccd4a63SDavid du Colombier 			break;
1304*8ccd4a63SDavid du Colombier 		case 'R':
1305*8ccd4a63SDavid du Colombier 			q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
1306*8ccd4a63SDavid du Colombier 			a += 16;
1307*8ccd4a63SDavid du Colombier 			break;
1308*8ccd4a63SDavid du Colombier 		case 'P':
1309*8ccd4a63SDavid du Colombier 			q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
1310*8ccd4a63SDavid du Colombier 			a += 8;
1311*8ccd4a63SDavid du Colombier 			break;
1312*8ccd4a63SDavid du Colombier 		case 'b':
1313*8ccd4a63SDavid du Colombier 			q += sprint(q, " %d", *a++);
1314*8ccd4a63SDavid du Colombier 			break;
1315*8ccd4a63SDavid du Colombier 		case 's':
1316*8ccd4a63SDavid du Colombier 			q += sprint(q, " %d", BGSHORT(a));
1317*8ccd4a63SDavid du Colombier 			a += 2;
1318*8ccd4a63SDavid du Colombier 			break;
1319*8ccd4a63SDavid du Colombier 		case 'S':
1320*8ccd4a63SDavid du Colombier 			q += sprint(q, " %.4ux", BGSHORT(a));
1321*8ccd4a63SDavid du Colombier 			a += 2;
1322*8ccd4a63SDavid du Colombier 			break;
1323*8ccd4a63SDavid du Colombier 		}
1324*8ccd4a63SDavid du Colombier 	}
1325*8ccd4a63SDavid du Colombier 	*q++ = '\n';
1326*8ccd4a63SDavid du Colombier 	*q = 0;
1327*8ccd4a63SDavid du Colombier 	iprint("%.*s", (int)(q-buf), buf);
1328*8ccd4a63SDavid du Colombier }
1329*8ccd4a63SDavid du Colombier 
1330*8ccd4a63SDavid du Colombier void
1331*8ccd4a63SDavid du Colombier drawmesg(Client *client, void *av, int n)
1332*8ccd4a63SDavid du Colombier {
1333*8ccd4a63SDavid du Colombier 	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
1334*8ccd4a63SDavid du Colombier 	uchar *u, *a, refresh;
1335*8ccd4a63SDavid du Colombier 	char *fmt;
1336*8ccd4a63SDavid du Colombier 	ulong value, chan;
1337*8ccd4a63SDavid du Colombier 	Rectangle r, clipr;
1338*8ccd4a63SDavid du Colombier 	Point p, q, *pp, sp;
1339*8ccd4a63SDavid du Colombier 	Memimage *i, *dst, *src, *mask;
1340*8ccd4a63SDavid du Colombier 	Memimage *l, **lp;
1341*8ccd4a63SDavid du Colombier 	Memscreen *scrn;
1342*8ccd4a63SDavid du Colombier 	DImage *font, *ll, *di, *ddst, *dsrc;
1343*8ccd4a63SDavid du Colombier 	DName *dn;
1344*8ccd4a63SDavid du Colombier 	DScreen *dscrn;
1345*8ccd4a63SDavid du Colombier 	FChar *fc;
1346*8ccd4a63SDavid du Colombier 	Refx *refx;
1347*8ccd4a63SDavid du Colombier 	CScreen *cs;
1348*8ccd4a63SDavid du Colombier 	Refreshfn reffn;
1349*8ccd4a63SDavid du Colombier 
1350*8ccd4a63SDavid du Colombier 	a = av;
1351*8ccd4a63SDavid du Colombier 	m = 0;
1352*8ccd4a63SDavid du Colombier 	fmt = nil;
1353*8ccd4a63SDavid du Colombier 	if(waserror()){
1354*8ccd4a63SDavid du Colombier 		if(fmt) printmesg(fmt, a, 1);
1355*8ccd4a63SDavid du Colombier 	/*	iprint("error: %s\n", up->errstr);	*/
1356*8ccd4a63SDavid du Colombier 		nexterror();
1357*8ccd4a63SDavid du Colombier 	}
1358*8ccd4a63SDavid du Colombier 	while((n-=m) > 0){
1359*8ccd4a63SDavid du Colombier 		USED(fmt);
1360*8ccd4a63SDavid du Colombier 		a += m;
1361*8ccd4a63SDavid du Colombier 		switch(*a){
1362*8ccd4a63SDavid du Colombier 		default:
1363*8ccd4a63SDavid du Colombier 			error("bad draw command");
1364*8ccd4a63SDavid du Colombier 		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
1365*8ccd4a63SDavid du Colombier 		case 'b':
1366*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLbLbRRL", a, 0);
1367*8ccd4a63SDavid du Colombier 			m = 1+4+4+1+4+1+4*4+4*4+4;
1368*8ccd4a63SDavid du Colombier 			if(n < m)
1369*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1370*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1371*8ccd4a63SDavid du Colombier 			scrnid = BGSHORT(a+5);
1372*8ccd4a63SDavid du Colombier 			refresh = a[9];
1373*8ccd4a63SDavid du Colombier 			chan = BGLONG(a+10);
1374*8ccd4a63SDavid du Colombier 			repl = a[14];
1375*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+15);
1376*8ccd4a63SDavid du Colombier 			drawrectangle(&clipr, a+31);
1377*8ccd4a63SDavid du Colombier 			value = BGLONG(a+47);
1378*8ccd4a63SDavid du Colombier 			if(drawlookup(client, dstid, 0))
1379*8ccd4a63SDavid du Colombier 				error(Eimageexists);
1380*8ccd4a63SDavid du Colombier 			if(scrnid){
1381*8ccd4a63SDavid du Colombier 				dscrn = drawlookupscreen(client, scrnid, &cs);
1382*8ccd4a63SDavid du Colombier 				scrn = dscrn->screen;
1383*8ccd4a63SDavid du Colombier 				if(repl || chan!=scrn->image->chan)
1384*8ccd4a63SDavid du Colombier 					error("image parameters incompatible with screen");
1385*8ccd4a63SDavid du Colombier 				reffn = nil;
1386*8ccd4a63SDavid du Colombier 				switch(refresh){
1387*8ccd4a63SDavid du Colombier 				case Refbackup:
1388*8ccd4a63SDavid du Colombier 					break;
1389*8ccd4a63SDavid du Colombier 				case Refnone:
1390*8ccd4a63SDavid du Colombier 					reffn = memlnorefresh;
1391*8ccd4a63SDavid du Colombier 					break;
1392*8ccd4a63SDavid du Colombier 				case Refmesg:
1393*8ccd4a63SDavid du Colombier 					reffn = drawrefresh;
1394*8ccd4a63SDavid du Colombier 					break;
1395*8ccd4a63SDavid du Colombier 				default:
1396*8ccd4a63SDavid du Colombier 					error("unknown refresh method");
1397*8ccd4a63SDavid du Colombier 				}
1398*8ccd4a63SDavid du Colombier 				l = memlalloc(scrn, r, reffn, 0, value);
1399*8ccd4a63SDavid du Colombier 				if(l == 0)
1400*8ccd4a63SDavid du Colombier 					error(Edrawmem);
1401*8ccd4a63SDavid du Colombier 				addflush(l->layer->screenr);
1402*8ccd4a63SDavid du Colombier 				l->clipr = clipr;
1403*8ccd4a63SDavid du Colombier 				rectclip(&l->clipr, r);
1404*8ccd4a63SDavid du Colombier 				if(drawinstall(client, dstid, l, dscrn) == 0){
1405*8ccd4a63SDavid du Colombier 					memldelete(l);
1406*8ccd4a63SDavid du Colombier 					error(Edrawmem);
1407*8ccd4a63SDavid du Colombier 				}
1408*8ccd4a63SDavid du Colombier 				dscrn->ref++;
1409*8ccd4a63SDavid du Colombier 				if(reffn){
1410*8ccd4a63SDavid du Colombier 					refx = nil;
1411*8ccd4a63SDavid du Colombier 					if(reffn == drawrefresh){
1412*8ccd4a63SDavid du Colombier 						refx = malloc(sizeof(Refx));
1413*8ccd4a63SDavid du Colombier 						if(refx == 0){
1414*8ccd4a63SDavid du Colombier 							drawuninstall(client, dstid);
1415*8ccd4a63SDavid du Colombier 							error(Edrawmem);
1416*8ccd4a63SDavid du Colombier 						}
1417*8ccd4a63SDavid du Colombier 						refx->client = client;
1418*8ccd4a63SDavid du Colombier 						refx->dimage = drawlookup(client, dstid, 1);
1419*8ccd4a63SDavid du Colombier 					}
1420*8ccd4a63SDavid du Colombier 					memlsetrefresh(l, reffn, refx);
1421*8ccd4a63SDavid du Colombier 				}
1422*8ccd4a63SDavid du Colombier 				continue;
1423*8ccd4a63SDavid du Colombier 			}
1424*8ccd4a63SDavid du Colombier 			i = allocmemimage(r, chan);
1425*8ccd4a63SDavid du Colombier 			if(i == 0)
1426*8ccd4a63SDavid du Colombier 				error(Edrawmem);
1427*8ccd4a63SDavid du Colombier 			if(repl)
1428*8ccd4a63SDavid du Colombier 				i->flags |= Frepl;
1429*8ccd4a63SDavid du Colombier 			i->clipr = clipr;
1430*8ccd4a63SDavid du Colombier 			if(!repl)
1431*8ccd4a63SDavid du Colombier 				rectclip(&i->clipr, r);
1432*8ccd4a63SDavid du Colombier 			if(drawinstall(client, dstid, i, 0) == 0){
1433*8ccd4a63SDavid du Colombier 				freememimage(i);
1434*8ccd4a63SDavid du Colombier 				error(Edrawmem);
1435*8ccd4a63SDavid du Colombier 			}
1436*8ccd4a63SDavid du Colombier 			memfillcolor(i, value);
1437*8ccd4a63SDavid du Colombier 			continue;
1438*8ccd4a63SDavid du Colombier 
1439*8ccd4a63SDavid du Colombier 		/* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
1440*8ccd4a63SDavid du Colombier 		case 'A':
1441*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLLb", a, 1);
1442*8ccd4a63SDavid du Colombier 			m = 1+4+4+4+1;
1443*8ccd4a63SDavid du Colombier 			if(n < m)
1444*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1445*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1446*8ccd4a63SDavid du Colombier 			if(dstid == 0)
1447*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1448*8ccd4a63SDavid du Colombier 			if(drawlookupdscreen(dstid))
1449*8ccd4a63SDavid du Colombier 				error(Escreenexists);
1450*8ccd4a63SDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+5), 1);
1451*8ccd4a63SDavid du Colombier 			dsrc = drawlookup(client, BGLONG(a+9), 1);
1452*8ccd4a63SDavid du Colombier 			if(ddst==0 || dsrc==0)
1453*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1454*8ccd4a63SDavid du Colombier 			if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
1455*8ccd4a63SDavid du Colombier 				error(Edrawmem);
1456*8ccd4a63SDavid du Colombier 			continue;
1457*8ccd4a63SDavid du Colombier 
1458*8ccd4a63SDavid du Colombier 		/* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
1459*8ccd4a63SDavid du Colombier 		case 'c':
1460*8ccd4a63SDavid du Colombier 			printmesg(fmt="LbR", a, 0);
1461*8ccd4a63SDavid du Colombier 			m = 1+4+1+4*4;
1462*8ccd4a63SDavid du Colombier 			if(n < m)
1463*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1464*8ccd4a63SDavid du Colombier 			ddst = drawlookup(client, BGLONG(a+1), 1);
1465*8ccd4a63SDavid du Colombier 			if(ddst == nil)
1466*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1467*8ccd4a63SDavid du Colombier 			if(ddst->name)
1468*8ccd4a63SDavid du Colombier 				error("can't change repl/clipr of shared image");
1469*8ccd4a63SDavid du Colombier 			dst = ddst->image;
1470*8ccd4a63SDavid du Colombier 			if(a[5])
1471*8ccd4a63SDavid du Colombier 				dst->flags |= Frepl;
1472*8ccd4a63SDavid du Colombier 			drawrectangle(&dst->clipr, a+6);
1473*8ccd4a63SDavid du Colombier 			continue;
1474*8ccd4a63SDavid du Colombier 
1475*8ccd4a63SDavid du Colombier 		/* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
1476*8ccd4a63SDavid du Colombier 		case 'd':
1477*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLLRPP", a, 0);
1478*8ccd4a63SDavid du Colombier 			m = 1+4+4+4+4*4+2*4+2*4;
1479*8ccd4a63SDavid du Colombier 			if(n < m)
1480*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1481*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1482*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1483*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+5);
1484*8ccd4a63SDavid du Colombier 			mask = drawimage(client, a+9);
1485*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+13);
1486*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+29);
1487*8ccd4a63SDavid du Colombier 			drawpoint(&q, a+37);
1488*8ccd4a63SDavid du Colombier 			op = drawclientop(client);
1489*8ccd4a63SDavid du Colombier 			memdraw(dst, r, src, p, mask, q, op);
1490*8ccd4a63SDavid du Colombier 			dstflush(dstid, dst, r);
1491*8ccd4a63SDavid du Colombier 			continue;
1492*8ccd4a63SDavid du Colombier 
1493*8ccd4a63SDavid du Colombier 		/* toggle debugging: 'D' val[1] */
1494*8ccd4a63SDavid du Colombier 		case 'D':
1495*8ccd4a63SDavid du Colombier 			printmesg(fmt="b", a, 0);
1496*8ccd4a63SDavid du Colombier 			m = 1+1;
1497*8ccd4a63SDavid du Colombier 			if(n < m)
1498*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1499*8ccd4a63SDavid du Colombier 			drawdebug = a[1];
1500*8ccd4a63SDavid du Colombier 			continue;
1501*8ccd4a63SDavid du Colombier 
1502*8ccd4a63SDavid du Colombier 		/* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
1503*8ccd4a63SDavid du Colombier 		case 'e':
1504*8ccd4a63SDavid du Colombier 		case 'E':
1505*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLPlllPll", a, 0);
1506*8ccd4a63SDavid du Colombier 			m = 1+4+4+2*4+4+4+4+2*4+2*4;
1507*8ccd4a63SDavid du Colombier 			if(n < m)
1508*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1509*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1510*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1511*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+5);
1512*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+9);
1513*8ccd4a63SDavid du Colombier 			e0 = BGLONG(a+17);
1514*8ccd4a63SDavid du Colombier 			e1 = BGLONG(a+21);
1515*8ccd4a63SDavid du Colombier 			if(e0<0 || e1<0)
1516*8ccd4a63SDavid du Colombier 				error("invalid ellipse semidiameter");
1517*8ccd4a63SDavid du Colombier 			j = BGLONG(a+25);
1518*8ccd4a63SDavid du Colombier 			if(j < 0)
1519*8ccd4a63SDavid du Colombier 				error("negative ellipse thickness");
1520*8ccd4a63SDavid du Colombier 			drawpoint(&sp, a+29);
1521*8ccd4a63SDavid du Colombier 			c = j;
1522*8ccd4a63SDavid du Colombier 			if(*a == 'E')
1523*8ccd4a63SDavid du Colombier 				c = -1;
1524*8ccd4a63SDavid du Colombier 			ox = BGLONG(a+37);
1525*8ccd4a63SDavid du Colombier 			oy = BGLONG(a+41);
1526*8ccd4a63SDavid du Colombier 			op = drawclientop(client);
1527*8ccd4a63SDavid du Colombier 			/* high bit indicates arc angles are present */
1528*8ccd4a63SDavid du Colombier 			if(ox & (1<<31)){
1529*8ccd4a63SDavid du Colombier 				if((ox & (1<<30)) == 0)
1530*8ccd4a63SDavid du Colombier 					ox &= ~(1<<31);
1531*8ccd4a63SDavid du Colombier 				memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
1532*8ccd4a63SDavid du Colombier 			}else
1533*8ccd4a63SDavid du Colombier 				memellipse(dst, p, e0, e1, c, src, sp, op);
1534*8ccd4a63SDavid du Colombier 			dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
1535*8ccd4a63SDavid du Colombier 			continue;
1536*8ccd4a63SDavid du Colombier 
1537*8ccd4a63SDavid du Colombier 		/* free: 'f' id[4] */
1538*8ccd4a63SDavid du Colombier 		case 'f':
1539*8ccd4a63SDavid du Colombier 			printmesg(fmt="L", a, 1);
1540*8ccd4a63SDavid du Colombier 			m = 1+4;
1541*8ccd4a63SDavid du Colombier 			if(n < m)
1542*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1543*8ccd4a63SDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1), 0);
1544*8ccd4a63SDavid du Colombier 			if(ll && ll->dscreen && ll->dscreen->owner != client)
1545*8ccd4a63SDavid du Colombier 				ll->dscreen->owner->refreshme = 1;
1546*8ccd4a63SDavid du Colombier 			drawuninstall(client, BGLONG(a+1));
1547*8ccd4a63SDavid du Colombier 			continue;
1548*8ccd4a63SDavid du Colombier 
1549*8ccd4a63SDavid du Colombier 		/* free screen: 'F' id[4] */
1550*8ccd4a63SDavid du Colombier 		case 'F':
1551*8ccd4a63SDavid du Colombier 			printmesg(fmt="L", a, 1);
1552*8ccd4a63SDavid du Colombier 			m = 1+4;
1553*8ccd4a63SDavid du Colombier 			if(n < m)
1554*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1555*8ccd4a63SDavid du Colombier 			drawlookupscreen(client, BGLONG(a+1), &cs);
1556*8ccd4a63SDavid du Colombier 			drawuninstallscreen(client, cs);
1557*8ccd4a63SDavid du Colombier 			continue;
1558*8ccd4a63SDavid du Colombier 
1559*8ccd4a63SDavid du Colombier 		/* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
1560*8ccd4a63SDavid du Colombier 		case 'i':
1561*8ccd4a63SDavid du Colombier 			printmesg(fmt="Llb", a, 1);
1562*8ccd4a63SDavid du Colombier 			m = 1+4+4+1;
1563*8ccd4a63SDavid du Colombier 			if(n < m)
1564*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1565*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1566*8ccd4a63SDavid du Colombier 			if(dstid == 0)
1567*8ccd4a63SDavid du Colombier 				error("can't use display as font");
1568*8ccd4a63SDavid du Colombier 			font = drawlookup(client, dstid, 1);
1569*8ccd4a63SDavid du Colombier 			if(font == 0)
1570*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1571*8ccd4a63SDavid du Colombier 			if(font->image->layer)
1572*8ccd4a63SDavid du Colombier 				error("can't use window as font");
1573*8ccd4a63SDavid du Colombier 			ni = BGLONG(a+5);
1574*8ccd4a63SDavid du Colombier 			if(ni<=0 || ni>4096)
1575*8ccd4a63SDavid du Colombier 				error("bad font size (4096 chars max)");
1576*8ccd4a63SDavid du Colombier 			free(font->fchar);	/* should we complain if non-zero? */
1577*8ccd4a63SDavid du Colombier 			font->fchar = malloc(ni*sizeof(FChar));
1578*8ccd4a63SDavid du Colombier 			if(font->fchar == 0)
1579*8ccd4a63SDavid du Colombier 				error("no memory for font");
1580*8ccd4a63SDavid du Colombier 			memset(font->fchar, 0, ni*sizeof(FChar));
1581*8ccd4a63SDavid du Colombier 			font->nfchar = ni;
1582*8ccd4a63SDavid du Colombier 			font->ascent = a[9];
1583*8ccd4a63SDavid du Colombier 			continue;
1584*8ccd4a63SDavid du Colombier 
1585*8ccd4a63SDavid du Colombier 		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
1586*8ccd4a63SDavid du Colombier 		case 'l':
1587*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLSRPbb", a, 0);
1588*8ccd4a63SDavid du Colombier 			m = 1+4+4+2+4*4+2*4+1+1;
1589*8ccd4a63SDavid du Colombier 			if(n < m)
1590*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1591*8ccd4a63SDavid du Colombier 			font = drawlookup(client, BGLONG(a+1), 1);
1592*8ccd4a63SDavid du Colombier 			if(font == 0)
1593*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1594*8ccd4a63SDavid du Colombier 			if(font->nfchar == 0)
1595*8ccd4a63SDavid du Colombier 				error(Enotfont);
1596*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+5);
1597*8ccd4a63SDavid du Colombier 			ci = BGSHORT(a+9);
1598*8ccd4a63SDavid du Colombier 			if(ci >= font->nfchar)
1599*8ccd4a63SDavid du Colombier 				error(Eindex);
1600*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+11);
1601*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+27);
1602*8ccd4a63SDavid du Colombier 			memdraw(font->image, r, src, p, memopaque, p, S);
1603*8ccd4a63SDavid du Colombier 			fc = &font->fchar[ci];
1604*8ccd4a63SDavid du Colombier 			fc->minx = r.min.x;
1605*8ccd4a63SDavid du Colombier 			fc->maxx = r.max.x;
1606*8ccd4a63SDavid du Colombier 			fc->miny = r.min.y;
1607*8ccd4a63SDavid du Colombier 			fc->maxy = r.max.y;
1608*8ccd4a63SDavid du Colombier 			fc->left = a[35];
1609*8ccd4a63SDavid du Colombier 			fc->width = a[36];
1610*8ccd4a63SDavid du Colombier 			continue;
1611*8ccd4a63SDavid du Colombier 
1612*8ccd4a63SDavid du Colombier 		/* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
1613*8ccd4a63SDavid du Colombier 		case 'L':
1614*8ccd4a63SDavid du Colombier 			printmesg(fmt="LPPlllLP", a, 0);
1615*8ccd4a63SDavid du Colombier 			m = 1+4+2*4+2*4+4+4+4+4+2*4;
1616*8ccd4a63SDavid du Colombier 			if(n < m)
1617*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1618*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1619*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1620*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+5);
1621*8ccd4a63SDavid du Colombier 			drawpoint(&q, a+13);
1622*8ccd4a63SDavid du Colombier 			e0 = BGLONG(a+21);
1623*8ccd4a63SDavid du Colombier 			e1 = BGLONG(a+25);
1624*8ccd4a63SDavid du Colombier 			j = BGLONG(a+29);
1625*8ccd4a63SDavid du Colombier 			if(j < 0)
1626*8ccd4a63SDavid du Colombier 				error("negative line width");
1627*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+33);
1628*8ccd4a63SDavid du Colombier 			drawpoint(&sp, a+37);
1629*8ccd4a63SDavid du Colombier 			op = drawclientop(client);
1630*8ccd4a63SDavid du Colombier 			memline(dst, p, q, e0, e1, j, src, sp, op);
1631*8ccd4a63SDavid du Colombier 			/* avoid memlinebbox if possible */
1632*8ccd4a63SDavid du Colombier 			if(dstid==0 || dst->layer!=nil){
1633*8ccd4a63SDavid du Colombier 				/* BUG: this is terribly inefficient: update maximal containing rect*/
1634*8ccd4a63SDavid du Colombier 				r = memlinebbox(p, q, e0, e1, j);
1635*8ccd4a63SDavid du Colombier 				dstflush(dstid, dst, insetrect(r, -(1+1+j)));
1636*8ccd4a63SDavid du Colombier 			}
1637*8ccd4a63SDavid du Colombier 			continue;
1638*8ccd4a63SDavid du Colombier 
1639*8ccd4a63SDavid du Colombier 		/* create image mask: 'm' newid[4] id[4] */
1640*8ccd4a63SDavid du Colombier /*
1641*8ccd4a63SDavid du Colombier  *
1642*8ccd4a63SDavid du Colombier 		case 'm':
1643*8ccd4a63SDavid du Colombier 			printmesg("LL", a, 0);
1644*8ccd4a63SDavid du Colombier 			m = 4+4;
1645*8ccd4a63SDavid du Colombier 			if(n < m)
1646*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1647*8ccd4a63SDavid du Colombier 			break;
1648*8ccd4a63SDavid du Colombier  *
1649*8ccd4a63SDavid du Colombier  */
1650*8ccd4a63SDavid du Colombier 
1651*8ccd4a63SDavid du Colombier 		/* attach to a named image: 'n' dstid[4] j[1] name[j] */
1652*8ccd4a63SDavid du Colombier 		case 'n':
1653*8ccd4a63SDavid du Colombier 			printmesg(fmt="Lz", a, 0);
1654*8ccd4a63SDavid du Colombier 			m = 1+4+1;
1655*8ccd4a63SDavid du Colombier 			if(n < m)
1656*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1657*8ccd4a63SDavid du Colombier 			j = a[5];
1658*8ccd4a63SDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
1659*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1660*8ccd4a63SDavid du Colombier 			m += j;
1661*8ccd4a63SDavid du Colombier 			if(n < m)
1662*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1663*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1664*8ccd4a63SDavid du Colombier 			if(drawlookup(client, dstid, 0))
1665*8ccd4a63SDavid du Colombier 				error(Eimageexists);
1666*8ccd4a63SDavid du Colombier 			dn = drawlookupname(j, (char*)a+6);
1667*8ccd4a63SDavid du Colombier 			if(dn == nil)
1668*8ccd4a63SDavid du Colombier 				error(Enoname);
1669*8ccd4a63SDavid du Colombier 			if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
1670*8ccd4a63SDavid du Colombier 				error(Edrawmem);
1671*8ccd4a63SDavid du Colombier 			di = drawlookup(client, dstid, 0);
1672*8ccd4a63SDavid du Colombier 			if(di == 0)
1673*8ccd4a63SDavid du Colombier 				error("draw: can't happen");
1674*8ccd4a63SDavid du Colombier 			di->vers = dn->vers;
1675*8ccd4a63SDavid du Colombier 			di->name = smalloc(j+1);
1676*8ccd4a63SDavid du Colombier 			di->fromname = dn->dimage;
1677*8ccd4a63SDavid du Colombier 			di->fromname->ref++;
1678*8ccd4a63SDavid du Colombier 			memmove(di->name, a+6, j);
1679*8ccd4a63SDavid du Colombier 			di->name[j] = 0;
1680*8ccd4a63SDavid du Colombier 			client->infoid = dstid;
1681*8ccd4a63SDavid du Colombier 			continue;
1682*8ccd4a63SDavid du Colombier 
1683*8ccd4a63SDavid du Colombier 		/* name an image: 'N' dstid[4] in[1] j[1] name[j] */
1684*8ccd4a63SDavid du Colombier 		case 'N':
1685*8ccd4a63SDavid du Colombier 			printmesg(fmt="Lbz", a, 0);
1686*8ccd4a63SDavid du Colombier 			m = 1+4+1+1;
1687*8ccd4a63SDavid du Colombier 			if(n < m)
1688*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1689*8ccd4a63SDavid du Colombier 			c = a[5];
1690*8ccd4a63SDavid du Colombier 			j = a[6];
1691*8ccd4a63SDavid du Colombier 			if(j == 0)	/* give me a non-empty name please */
1692*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1693*8ccd4a63SDavid du Colombier 			m += j;
1694*8ccd4a63SDavid du Colombier 			if(n < m)
1695*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1696*8ccd4a63SDavid du Colombier 			di = drawlookup(client, BGLONG(a+1), 0);
1697*8ccd4a63SDavid du Colombier 			if(di == 0)
1698*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1699*8ccd4a63SDavid du Colombier 			if(di->name)
1700*8ccd4a63SDavid du Colombier 				error(Enamed);
1701*8ccd4a63SDavid du Colombier 			if(c)
1702*8ccd4a63SDavid du Colombier 				drawaddname(client, di, j, (char*)a+7);
1703*8ccd4a63SDavid du Colombier 			else{
1704*8ccd4a63SDavid du Colombier 				dn = drawlookupname(j, (char*)a+7);
1705*8ccd4a63SDavid du Colombier 				if(dn == nil)
1706*8ccd4a63SDavid du Colombier 					error(Enoname);
1707*8ccd4a63SDavid du Colombier 				if(dn->dimage != di)
1708*8ccd4a63SDavid du Colombier 					error(Ewrongname);
1709*8ccd4a63SDavid du Colombier 				drawdelname(dn);
1710*8ccd4a63SDavid du Colombier 			}
1711*8ccd4a63SDavid du Colombier 			continue;
1712*8ccd4a63SDavid du Colombier 
1713*8ccd4a63SDavid du Colombier 		/* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
1714*8ccd4a63SDavid du Colombier 		case 'o':
1715*8ccd4a63SDavid du Colombier 			printmesg(fmt="LPP", a, 0);
1716*8ccd4a63SDavid du Colombier 			m = 1+4+2*4+2*4;
1717*8ccd4a63SDavid du Colombier 			if(n < m)
1718*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1719*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1720*8ccd4a63SDavid du Colombier 			if(dst->layer){
1721*8ccd4a63SDavid du Colombier 				drawpoint(&p, a+5);
1722*8ccd4a63SDavid du Colombier 				drawpoint(&q, a+13);
1723*8ccd4a63SDavid du Colombier 				r = dst->layer->screenr;
1724*8ccd4a63SDavid du Colombier 				ni = memlorigin(dst, p, q);
1725*8ccd4a63SDavid du Colombier 				if(ni < 0)
1726*8ccd4a63SDavid du Colombier 					error("image origin failed");
1727*8ccd4a63SDavid du Colombier 				if(ni > 0){
1728*8ccd4a63SDavid du Colombier 					addflush(r);
1729*8ccd4a63SDavid du Colombier 					addflush(dst->layer->screenr);
1730*8ccd4a63SDavid du Colombier 					ll = drawlookup(client, BGLONG(a+1), 1);
1731*8ccd4a63SDavid du Colombier 					drawrefreshscreen(ll, client);
1732*8ccd4a63SDavid du Colombier 				}
1733*8ccd4a63SDavid du Colombier 			}
1734*8ccd4a63SDavid du Colombier 			continue;
1735*8ccd4a63SDavid du Colombier 
1736*8ccd4a63SDavid du Colombier 		/* set compositing operator for next draw operation: 'O' op */
1737*8ccd4a63SDavid du Colombier 		case 'O':
1738*8ccd4a63SDavid du Colombier 			printmesg(fmt="b", a, 0);
1739*8ccd4a63SDavid du Colombier 			m = 1+1;
1740*8ccd4a63SDavid du Colombier 			if(n < m)
1741*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1742*8ccd4a63SDavid du Colombier 			client->op = a[1];
1743*8ccd4a63SDavid du Colombier 			continue;
1744*8ccd4a63SDavid du Colombier 
1745*8ccd4a63SDavid 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] */
1746*8ccd4a63SDavid 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] */
1747*8ccd4a63SDavid du Colombier 		case 'p':
1748*8ccd4a63SDavid du Colombier 		case 'P':
1749*8ccd4a63SDavid du Colombier 			printmesg(fmt="LslllLPP", a, 0);
1750*8ccd4a63SDavid du Colombier 			m = 1+4+2+4+4+4+4+2*4;
1751*8ccd4a63SDavid du Colombier 			if(n < m)
1752*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1753*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1754*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1755*8ccd4a63SDavid du Colombier 			ni = BGSHORT(a+5);
1756*8ccd4a63SDavid du Colombier 			if(ni < 0)
1757*8ccd4a63SDavid du Colombier 				error("negative count in polygon");
1758*8ccd4a63SDavid du Colombier 			e0 = BGLONG(a+7);
1759*8ccd4a63SDavid du Colombier 			e1 = BGLONG(a+11);
1760*8ccd4a63SDavid du Colombier 			j = 0;
1761*8ccd4a63SDavid du Colombier 			if(*a == 'p'){
1762*8ccd4a63SDavid du Colombier 				j = BGLONG(a+15);
1763*8ccd4a63SDavid du Colombier 				if(j < 0)
1764*8ccd4a63SDavid du Colombier 					error("negative polygon line width");
1765*8ccd4a63SDavid du Colombier 			}
1766*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+19);
1767*8ccd4a63SDavid du Colombier 			drawpoint(&sp, a+23);
1768*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+31);
1769*8ccd4a63SDavid du Colombier 			ni++;
1770*8ccd4a63SDavid du Colombier 			pp = malloc(ni*sizeof(Point));
1771*8ccd4a63SDavid du Colombier 			if(pp == nil)
1772*8ccd4a63SDavid du Colombier 				error(Enomem);
1773*8ccd4a63SDavid du Colombier 			doflush = 0;
1774*8ccd4a63SDavid du Colombier 			if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
1775*8ccd4a63SDavid du Colombier 				doflush = 1;	/* simplify test in loop */
1776*8ccd4a63SDavid du Colombier 			ox = oy = 0;
1777*8ccd4a63SDavid du Colombier 			esize = 0;
1778*8ccd4a63SDavid du Colombier 			u = a+m;
1779*8ccd4a63SDavid du Colombier 			for(y=0; y<ni; y++){
1780*8ccd4a63SDavid du Colombier 				q = p;
1781*8ccd4a63SDavid du Colombier 				oesize = esize;
1782*8ccd4a63SDavid du Colombier 				u = drawcoord(u, a+n, ox, &p.x);
1783*8ccd4a63SDavid du Colombier 				u = drawcoord(u, a+n, oy, &p.y);
1784*8ccd4a63SDavid du Colombier 				ox = p.x;
1785*8ccd4a63SDavid du Colombier 				oy = p.y;
1786*8ccd4a63SDavid du Colombier 				if(doflush){
1787*8ccd4a63SDavid du Colombier 					esize = j;
1788*8ccd4a63SDavid du Colombier 					if(*a == 'p'){
1789*8ccd4a63SDavid du Colombier 						if(y == 0){
1790*8ccd4a63SDavid du Colombier 							c = memlineendsize(e0);
1791*8ccd4a63SDavid du Colombier 							if(c > esize)
1792*8ccd4a63SDavid du Colombier 								esize = c;
1793*8ccd4a63SDavid du Colombier 						}
1794*8ccd4a63SDavid du Colombier 						if(y == ni-1){
1795*8ccd4a63SDavid du Colombier 							c = memlineendsize(e1);
1796*8ccd4a63SDavid du Colombier 							if(c > esize)
1797*8ccd4a63SDavid du Colombier 								esize = c;
1798*8ccd4a63SDavid du Colombier 						}
1799*8ccd4a63SDavid du Colombier 					}
1800*8ccd4a63SDavid du Colombier 					if(*a=='P' && e0!=1 && e0 !=~0)
1801*8ccd4a63SDavid du Colombier 						r = dst->clipr;
1802*8ccd4a63SDavid du Colombier 					else if(y > 0){
1803*8ccd4a63SDavid du Colombier 						r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
1804*8ccd4a63SDavid du Colombier 						combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
1805*8ccd4a63SDavid du Colombier 					}
1806*8ccd4a63SDavid du Colombier 					if(rectclip(&r, dst->clipr))		/* should perhaps be an arg to dstflush */
1807*8ccd4a63SDavid du Colombier 						dstflush(dstid, dst, r);
1808*8ccd4a63SDavid du Colombier 				}
1809*8ccd4a63SDavid du Colombier 				pp[y] = p;
1810*8ccd4a63SDavid du Colombier 			}
1811*8ccd4a63SDavid du Colombier 			if(y == 1)
1812*8ccd4a63SDavid du Colombier 				dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
1813*8ccd4a63SDavid du Colombier 			op = drawclientop(client);
1814*8ccd4a63SDavid du Colombier 			if(*a == 'p')
1815*8ccd4a63SDavid du Colombier 				mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
1816*8ccd4a63SDavid du Colombier 			else
1817*8ccd4a63SDavid du Colombier 				memfillpoly(dst, pp, ni, e0, src, sp, op);
1818*8ccd4a63SDavid du Colombier 			free(pp);
1819*8ccd4a63SDavid du Colombier 			m = u-a;
1820*8ccd4a63SDavid du Colombier 			continue;
1821*8ccd4a63SDavid du Colombier 
1822*8ccd4a63SDavid du Colombier 		/* read: 'r' id[4] R[4*4] */
1823*8ccd4a63SDavid du Colombier 		case 'r':
1824*8ccd4a63SDavid du Colombier 			printmesg(fmt="LR", a, 0);
1825*8ccd4a63SDavid du Colombier 			m = 1+4+4*4;
1826*8ccd4a63SDavid du Colombier 			if(n < m)
1827*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1828*8ccd4a63SDavid du Colombier 			i = drawimage(client, a+1);
1829*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+5);
1830*8ccd4a63SDavid du Colombier 			if(!rectinrect(r, i->r))
1831*8ccd4a63SDavid du Colombier 				error(Ereadoutside);
1832*8ccd4a63SDavid du Colombier 			c = bytesperline(r, i->depth);
1833*8ccd4a63SDavid du Colombier 			c *= Dy(r);
1834*8ccd4a63SDavid du Colombier 			free(client->readdata);
1835*8ccd4a63SDavid du Colombier 			client->readdata = mallocz(c, 0);
1836*8ccd4a63SDavid du Colombier 			if(client->readdata == nil)
1837*8ccd4a63SDavid du Colombier 				error("readimage malloc failed");
1838*8ccd4a63SDavid du Colombier 			client->nreaddata = memunload(i, r, client->readdata, c);
1839*8ccd4a63SDavid du Colombier 			if(client->nreaddata < 0){
1840*8ccd4a63SDavid du Colombier 				free(client->readdata);
1841*8ccd4a63SDavid du Colombier 				client->readdata = nil;
1842*8ccd4a63SDavid du Colombier 				error("bad readimage call");
1843*8ccd4a63SDavid du Colombier 			}
1844*8ccd4a63SDavid du Colombier 			continue;
1845*8ccd4a63SDavid du Colombier 
1846*8ccd4a63SDavid du Colombier 		/* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
1847*8ccd4a63SDavid 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]) */
1848*8ccd4a63SDavid du Colombier 		case 's':
1849*8ccd4a63SDavid du Colombier 		case 'x':
1850*8ccd4a63SDavid du Colombier 			printmesg(fmt="LLLPRPs", a, 0);
1851*8ccd4a63SDavid du Colombier 			m = 1+4+4+4+2*4+4*4+2*4+2;
1852*8ccd4a63SDavid du Colombier 			if(*a == 'x')
1853*8ccd4a63SDavid du Colombier 				m += 4+2*4;
1854*8ccd4a63SDavid du Colombier 			if(n < m)
1855*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1856*8ccd4a63SDavid du Colombier 
1857*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1858*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1859*8ccd4a63SDavid du Colombier 			src = drawimage(client, a+5);
1860*8ccd4a63SDavid du Colombier 			font = drawlookup(client, BGLONG(a+9), 1);
1861*8ccd4a63SDavid du Colombier 			if(font == 0)
1862*8ccd4a63SDavid du Colombier 				error(Enodrawimage);
1863*8ccd4a63SDavid du Colombier 			if(font->nfchar == 0)
1864*8ccd4a63SDavid du Colombier 				error(Enotfont);
1865*8ccd4a63SDavid du Colombier 			drawpoint(&p, a+13);
1866*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+21);
1867*8ccd4a63SDavid du Colombier 			drawpoint(&sp, a+37);
1868*8ccd4a63SDavid du Colombier 			ni = BGSHORT(a+45);
1869*8ccd4a63SDavid du Colombier 			u = a+m;
1870*8ccd4a63SDavid du Colombier 			m += ni*2;
1871*8ccd4a63SDavid du Colombier 			if(n < m)
1872*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1873*8ccd4a63SDavid du Colombier 			clipr = dst->clipr;
1874*8ccd4a63SDavid du Colombier 			dst->clipr = r;
1875*8ccd4a63SDavid du Colombier 			op = drawclientop(client);
1876*8ccd4a63SDavid du Colombier 			if(*a == 'x'){
1877*8ccd4a63SDavid du Colombier 				/* paint background */
1878*8ccd4a63SDavid du Colombier 				l = drawimage(client, a+47);
1879*8ccd4a63SDavid du Colombier 				drawpoint(&q, a+51);
1880*8ccd4a63SDavid du Colombier 				r.min.x = p.x;
1881*8ccd4a63SDavid du Colombier 				r.min.y = p.y-font->ascent;
1882*8ccd4a63SDavid du Colombier 				r.max.x = p.x;
1883*8ccd4a63SDavid du Colombier 				r.max.y = r.min.y+Dy(font->image->r);
1884*8ccd4a63SDavid du Colombier 				j = ni;
1885*8ccd4a63SDavid du Colombier 				while(--j >= 0){
1886*8ccd4a63SDavid du Colombier 					ci = BGSHORT(u);
1887*8ccd4a63SDavid du Colombier 					if(ci<0 || ci>=font->nfchar){
1888*8ccd4a63SDavid du Colombier 						dst->clipr = clipr;
1889*8ccd4a63SDavid du Colombier 						error(Eindex);
1890*8ccd4a63SDavid du Colombier 					}
1891*8ccd4a63SDavid du Colombier 					r.max.x += font->fchar[ci].width;
1892*8ccd4a63SDavid du Colombier 					u += 2;
1893*8ccd4a63SDavid du Colombier 				}
1894*8ccd4a63SDavid du Colombier 				memdraw(dst, r, l, q, memopaque, ZP, op);
1895*8ccd4a63SDavid du Colombier 				u -= 2*ni;
1896*8ccd4a63SDavid du Colombier 			}
1897*8ccd4a63SDavid du Colombier 			q = p;
1898*8ccd4a63SDavid du Colombier 			while(--ni >= 0){
1899*8ccd4a63SDavid du Colombier 				ci = BGSHORT(u);
1900*8ccd4a63SDavid du Colombier 				if(ci<0 || ci>=font->nfchar){
1901*8ccd4a63SDavid du Colombier 					dst->clipr = clipr;
1902*8ccd4a63SDavid du Colombier 					error(Eindex);
1903*8ccd4a63SDavid du Colombier 				}
1904*8ccd4a63SDavid du Colombier 				q = drawchar(dst, q, src, &sp, font, ci, op);
1905*8ccd4a63SDavid du Colombier 				u += 2;
1906*8ccd4a63SDavid du Colombier 			}
1907*8ccd4a63SDavid du Colombier 			dst->clipr = clipr;
1908*8ccd4a63SDavid du Colombier 			p.y -= font->ascent;
1909*8ccd4a63SDavid du Colombier 			dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
1910*8ccd4a63SDavid du Colombier 			continue;
1911*8ccd4a63SDavid du Colombier 
1912*8ccd4a63SDavid du Colombier 		/* use public screen: 'S' id[4] chan[4] */
1913*8ccd4a63SDavid du Colombier 		case 'S':
1914*8ccd4a63SDavid du Colombier 			printmesg(fmt="Ll", a, 0);
1915*8ccd4a63SDavid du Colombier 			m = 1+4+4;
1916*8ccd4a63SDavid du Colombier 			if(n < m)
1917*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1918*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1919*8ccd4a63SDavid du Colombier 			if(dstid == 0)
1920*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1921*8ccd4a63SDavid du Colombier 			dscrn = drawlookupdscreen(dstid);
1922*8ccd4a63SDavid du Colombier 			if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
1923*8ccd4a63SDavid du Colombier 				error(Enodrawscreen);
1924*8ccd4a63SDavid du Colombier 			if(dscrn->screen->image->chan != BGLONG(a+5))
1925*8ccd4a63SDavid du Colombier 				error("inconsistent chan");
1926*8ccd4a63SDavid du Colombier 			if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
1927*8ccd4a63SDavid du Colombier 				error(Edrawmem);
1928*8ccd4a63SDavid du Colombier 			continue;
1929*8ccd4a63SDavid du Colombier 
1930*8ccd4a63SDavid du Colombier 		/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
1931*8ccd4a63SDavid du Colombier 		case 't':
1932*8ccd4a63SDavid du Colombier 			printmesg(fmt="bsL", a, 0);
1933*8ccd4a63SDavid du Colombier 			m = 1+1+2;
1934*8ccd4a63SDavid du Colombier 			if(n < m)
1935*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1936*8ccd4a63SDavid du Colombier 			nw = BGSHORT(a+2);
1937*8ccd4a63SDavid du Colombier 			if(nw < 0)
1938*8ccd4a63SDavid du Colombier 				error(Ebadarg);
1939*8ccd4a63SDavid du Colombier 			if(nw == 0)
1940*8ccd4a63SDavid du Colombier 				continue;
1941*8ccd4a63SDavid du Colombier 			m += nw*4;
1942*8ccd4a63SDavid du Colombier 			if(n < m)
1943*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1944*8ccd4a63SDavid du Colombier 			lp = malloc(nw*sizeof(Memimage*));
1945*8ccd4a63SDavid du Colombier 			if(lp == 0)
1946*8ccd4a63SDavid du Colombier 				error(Enomem);
1947*8ccd4a63SDavid du Colombier 			if(waserror()){
1948*8ccd4a63SDavid du Colombier 				free(lp);
1949*8ccd4a63SDavid du Colombier 				nexterror();
1950*8ccd4a63SDavid du Colombier 			}
1951*8ccd4a63SDavid du Colombier 			for(j=0; j<nw; j++)
1952*8ccd4a63SDavid du Colombier 				lp[j] = drawimage(client, a+1+1+2+j*4);
1953*8ccd4a63SDavid du Colombier 			if(lp[0]->layer == 0)
1954*8ccd4a63SDavid du Colombier 				error("images are not windows");
1955*8ccd4a63SDavid du Colombier 			for(j=1; j<nw; j++)
1956*8ccd4a63SDavid du Colombier 				if(lp[j]->layer->screen != lp[0]->layer->screen)
1957*8ccd4a63SDavid du Colombier 					error("images not on same screen");
1958*8ccd4a63SDavid du Colombier 			if(a[1])
1959*8ccd4a63SDavid du Colombier 				memltofrontn(lp, nw);
1960*8ccd4a63SDavid du Colombier 			else
1961*8ccd4a63SDavid du Colombier 				memltorearn(lp, nw);
1962*8ccd4a63SDavid du Colombier 			if(lp[0]->layer->screen->image->data == screenimage->data)
1963*8ccd4a63SDavid du Colombier 				for(j=0; j<nw; j++)
1964*8ccd4a63SDavid du Colombier 					addflush(lp[j]->layer->screenr);
1965*8ccd4a63SDavid du Colombier 			ll = drawlookup(client, BGLONG(a+1+1+2), 1);
1966*8ccd4a63SDavid du Colombier 			drawrefreshscreen(ll, client);
1967*8ccd4a63SDavid du Colombier 			poperror();
1968*8ccd4a63SDavid du Colombier 			free(lp);
1969*8ccd4a63SDavid du Colombier 			continue;
1970*8ccd4a63SDavid du Colombier 
1971*8ccd4a63SDavid du Colombier 		/* visible: 'v' */
1972*8ccd4a63SDavid du Colombier 		case 'v':
1973*8ccd4a63SDavid du Colombier 			printmesg(fmt="", a, 0);
1974*8ccd4a63SDavid du Colombier 			m = 1;
1975*8ccd4a63SDavid du Colombier 			drawflush();
1976*8ccd4a63SDavid du Colombier 			continue;
1977*8ccd4a63SDavid du Colombier 
1978*8ccd4a63SDavid du Colombier 		/* write: 'y' id[4] R[4*4] data[x*1] */
1979*8ccd4a63SDavid du Colombier 		/* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
1980*8ccd4a63SDavid du Colombier 		case 'y':
1981*8ccd4a63SDavid du Colombier 		case 'Y':
1982*8ccd4a63SDavid du Colombier 			printmesg(fmt="LR", a, 0);
1983*8ccd4a63SDavid du Colombier 		//	iprint("load %c\n", *a);
1984*8ccd4a63SDavid du Colombier 			m = 1+4+4*4;
1985*8ccd4a63SDavid du Colombier 			if(n < m)
1986*8ccd4a63SDavid du Colombier 				error(Eshortdraw);
1987*8ccd4a63SDavid du Colombier 			dstid = BGLONG(a+1);
1988*8ccd4a63SDavid du Colombier 			dst = drawimage(client, a+1);
1989*8ccd4a63SDavid du Colombier 			drawrectangle(&r, a+5);
1990*8ccd4a63SDavid du Colombier 			if(!rectinrect(r, dst->r))
1991*8ccd4a63SDavid du Colombier 				error(Ewriteoutside);
1992*8ccd4a63SDavid du Colombier 			y = memload(dst, r, a+m, n-m, *a=='Y');
1993*8ccd4a63SDavid du Colombier 			if(y < 0)
1994*8ccd4a63SDavid du Colombier 				error("bad writeimage call");
1995*8ccd4a63SDavid du Colombier 			dstflush(dstid, dst, r);
1996*8ccd4a63SDavid du Colombier 			m += y;
1997*8ccd4a63SDavid du Colombier 			continue;
1998*8ccd4a63SDavid du Colombier 		}
1999*8ccd4a63SDavid du Colombier 	}
2000*8ccd4a63SDavid du Colombier 	poperror();
2001*8ccd4a63SDavid du Colombier }
2002*8ccd4a63SDavid du Colombier 
2003*8ccd4a63SDavid du Colombier Dev drawdevtab = {
2004*8ccd4a63SDavid du Colombier 	'i',
2005*8ccd4a63SDavid du Colombier 	"draw",
2006*8ccd4a63SDavid du Colombier 
2007*8ccd4a63SDavid du Colombier 	devreset,
2008*8ccd4a63SDavid du Colombier 	devinit,
2009*8ccd4a63SDavid du Colombier 	devshutdown,
2010*8ccd4a63SDavid du Colombier 	drawattach,
2011*8ccd4a63SDavid du Colombier 	drawwalk,
2012*8ccd4a63SDavid du Colombier 	drawstat,
2013*8ccd4a63SDavid du Colombier 	drawopen,
2014*8ccd4a63SDavid du Colombier 	devcreate,
2015*8ccd4a63SDavid du Colombier 	drawclose,
2016*8ccd4a63SDavid du Colombier 	drawread,
2017*8ccd4a63SDavid du Colombier 	devbread,
2018*8ccd4a63SDavid du Colombier 	drawwrite,
2019*8ccd4a63SDavid du Colombier 	devbwrite,
2020*8ccd4a63SDavid du Colombier 	devremove,
2021*8ccd4a63SDavid du Colombier 	devwstat,
2022*8ccd4a63SDavid du Colombier };
2023*8ccd4a63SDavid du Colombier 
2024*8ccd4a63SDavid du Colombier /*
2025*8ccd4a63SDavid du Colombier  * On 8 bit displays, load the default color map
2026*8ccd4a63SDavid du Colombier  */
2027*8ccd4a63SDavid du Colombier void
2028*8ccd4a63SDavid du Colombier drawcmap(void)
2029*8ccd4a63SDavid du Colombier {
2030*8ccd4a63SDavid du Colombier 	int r, g, b, cr, cg, cb, v;
2031*8ccd4a63SDavid du Colombier 	int num, den;
2032*8ccd4a63SDavid du Colombier 	int i, j;
2033*8ccd4a63SDavid du Colombier 
2034*8ccd4a63SDavid du Colombier 	drawactive(1);	/* to restore map from backup */
2035*8ccd4a63SDavid du Colombier 	for(r=0,i=0; r!=4; r++)
2036*8ccd4a63SDavid du Colombier 	    for(v=0; v!=4; v++,i+=16){
2037*8ccd4a63SDavid du Colombier 		for(g=0,j=v-r; g!=4; g++)
2038*8ccd4a63SDavid du Colombier 		    for(b=0;b!=4;b++,j++){
2039*8ccd4a63SDavid du Colombier 			den = r;
2040*8ccd4a63SDavid du Colombier 			if(g > den)
2041*8ccd4a63SDavid du Colombier 				den = g;
2042*8ccd4a63SDavid du Colombier 			if(b > den)
2043*8ccd4a63SDavid du Colombier 				den = b;
2044*8ccd4a63SDavid du Colombier 			if(den == 0)	/* divide check -- pick grey shades */
2045*8ccd4a63SDavid du Colombier 				cr = cg = cb = v*17;
2046*8ccd4a63SDavid du Colombier 			else{
2047*8ccd4a63SDavid du Colombier 				num = 17*(4*den+v);
2048*8ccd4a63SDavid du Colombier 				cr = r*num/den;
2049*8ccd4a63SDavid du Colombier 				cg = g*num/den;
2050*8ccd4a63SDavid du Colombier 				cb = b*num/den;
2051*8ccd4a63SDavid du Colombier 			}
2052*8ccd4a63SDavid du Colombier 			setcolor(i+(j&15),
2053*8ccd4a63SDavid du Colombier 				cr*0x01010101, cg*0x01010101, cb*0x01010101);
2054*8ccd4a63SDavid du Colombier 		    }
2055*8ccd4a63SDavid du Colombier 	}
2056*8ccd4a63SDavid du Colombier }
2057*8ccd4a63SDavid du Colombier 
2058*8ccd4a63SDavid du Colombier void
2059*8ccd4a63SDavid du Colombier drawblankscreen(int blank)
2060*8ccd4a63SDavid du Colombier {
2061*8ccd4a63SDavid du Colombier 	int i, nc;
2062*8ccd4a63SDavid du Colombier 	ulong *p;
2063*8ccd4a63SDavid du Colombier 
2064*8ccd4a63SDavid du Colombier 	if(blank == sdraw.blanked)
2065*8ccd4a63SDavid du Colombier 		return;
2066*8ccd4a63SDavid du Colombier 	if(!canqlock(&sdraw.lk))
2067*8ccd4a63SDavid du Colombier 		return;
2068*8ccd4a63SDavid du Colombier 	if(!initscreenimage()){
2069*8ccd4a63SDavid du Colombier 		qunlock(&sdraw.lk);
2070*8ccd4a63SDavid du Colombier 		return;
2071*8ccd4a63SDavid du Colombier 	}
2072*8ccd4a63SDavid du Colombier 	p = sdraw.savemap;
2073*8ccd4a63SDavid du Colombier 	nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
2074*8ccd4a63SDavid du Colombier 
2075*8ccd4a63SDavid du Colombier 	/*
2076*8ccd4a63SDavid du Colombier 	 * blankscreen uses the hardware to blank the screen
2077*8ccd4a63SDavid du Colombier 	 * when possible.  to help in cases when it is not possible,
2078*8ccd4a63SDavid du Colombier 	 * we set the color map to be all black.
2079*8ccd4a63SDavid du Colombier 	 */
2080*8ccd4a63SDavid du Colombier 	if(blank == 0){	/* turn screen on */
2081*8ccd4a63SDavid du Colombier 		for(i=0; i<nc; i++, p+=3)
2082*8ccd4a63SDavid du Colombier 			setcolor(i, p[0], p[1], p[2]);
2083*8ccd4a63SDavid du Colombier 	//	blankscreen(0);
2084*8ccd4a63SDavid du Colombier 	}else{	/* turn screen off */
2085*8ccd4a63SDavid du Colombier 	//	blankscreen(1);
2086*8ccd4a63SDavid du Colombier 		for(i=0; i<nc; i++, p+=3){
2087*8ccd4a63SDavid du Colombier 			getcolor(i, &p[0], &p[1], &p[2]);
2088*8ccd4a63SDavid du Colombier 			setcolor(i, 0, 0, 0);
2089*8ccd4a63SDavid du Colombier 		}
2090*8ccd4a63SDavid du Colombier 	}
2091*8ccd4a63SDavid du Colombier 	sdraw.blanked = blank;
2092*8ccd4a63SDavid du Colombier 	qunlock(&sdraw.lk);
2093*8ccd4a63SDavid du Colombier }
2094*8ccd4a63SDavid du Colombier 
2095*8ccd4a63SDavid du Colombier /*
2096*8ccd4a63SDavid du Colombier  * record activity on screen, changing blanking as appropriate
2097*8ccd4a63SDavid du Colombier  */
2098*8ccd4a63SDavid du Colombier void
2099*8ccd4a63SDavid du Colombier drawactive(int active)
2100*8ccd4a63SDavid du Colombier {
2101*8ccd4a63SDavid du Colombier /*
2102*8ccd4a63SDavid du Colombier 	if(active){
2103*8ccd4a63SDavid du Colombier 		drawblankscreen(0);
2104*8ccd4a63SDavid du Colombier 		sdraw.blanktime = MACHP(0)->ticks;
2105*8ccd4a63SDavid du Colombier 	}else{
2106*8ccd4a63SDavid du Colombier 		if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime)
2107*8ccd4a63SDavid du Colombier 			drawblankscreen(1);
2108*8ccd4a63SDavid du Colombier 	}
2109*8ccd4a63SDavid du Colombier */
2110*8ccd4a63SDavid du Colombier }
2111*8ccd4a63SDavid du Colombier 
2112*8ccd4a63SDavid du Colombier int
2113*8ccd4a63SDavid du Colombier drawidletime(void)
2114*8ccd4a63SDavid du Colombier {
2115*8ccd4a63SDavid du Colombier 	return 0;
2116*8ccd4a63SDavid du Colombier /*	return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */
2117*8ccd4a63SDavid du Colombier }
2118*8ccd4a63SDavid du Colombier 
2119