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