vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devdraw.c (45970B)


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