Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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