Commit Diff


commit - e0ef95dce18a85730c5d9d596a26271ac43f9958
commit + 150f88023b1fd3aa82fd5213367bc1f091715be6
blob - f4a3fd963cf419c417479286f21725db9495575e (mode 644)
blob + /dev/null
--- src/libdraw/devdraw.c
+++ /dev/null
@@ -1,1608 +0,0 @@
-/*
- * /dev/draw simulator -- handles the messages prepared by the draw library.
- * Includes all the memlayer code even though most programs don't use it.
- * This whole approach is overkill, but cpu is cheap and it keeps things simple.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <memlayer.h>
-
-extern void _flushmemscreen(Rectangle);
-
-#define NHASH (1<<5)
-#define HASHMASK (NHASH-1)
-
-typedef struct Client Client;
-typedef struct Draw Draw;
-typedef struct DImage DImage;
-typedef struct DScreen DScreen;
-typedef struct CScreen CScreen;
-typedef struct FChar FChar;
-typedef struct Refresh Refresh;
-typedef struct Refx Refx;
-typedef struct DName DName;
-
-struct Draw
-{
-	QLock		lk;
-	int		clientid;
-	int		nclient;
-	Client*		client[1];
-	int		nname;
-	DName*		name;
-	int		vers;
-	int		softscreen;
-};
-
-struct Client
-{
-	/*Ref		r;*/
-	DImage*		dimage[NHASH];
-	CScreen*	cscreen;
-	Refresh*	refresh;
-	Rendez		refrend;
-	uchar*		readdata;
-	int		nreaddata;
-	int		busy;
-	int		clientid;
-	int		slot;
-	int		refreshme;
-	int		infoid;
-	int		op;
-};
-
-struct Refresh
-{
-	DImage*		dimage;
-	Rectangle	r;
-	Refresh*	next;
-};
-
-struct Refx
-{
-	Client*		client;
-	DImage*		dimage;
-};
-
-struct DName
-{
-	char			*name;
-	Client	*client;
-	DImage*		dimage;
-	int			vers;
-};
-
-struct FChar
-{
-	int		minx;	/* left edge of bits */
-	int		maxx;	/* right edge of bits */
-	uchar		miny;	/* first non-zero scan-line */
-	uchar		maxy;	/* last non-zero scan-line + 1 */
-	schar		left;	/* offset of baseline */
-	uchar		width;	/* width of baseline */
-};
-
-/*
- * Reference counts in DImages:
- *	one per open by original client
- *	one per screen image or fill
- * 	one per image derived from this one by name
- */
-struct DImage
-{
-	int		id;
-	int		ref;
-	char		*name;
-	int		vers;
-	Memimage*	image;
-	int		ascent;
-	int		nfchar;
-	FChar*		fchar;
-	DScreen*	dscreen;	/* 0 if not a window */
-	DImage*	fromname;	/* image this one is derived from, by name */
-	DImage*		next;
-};
-
-struct CScreen
-{
-	DScreen*	dscreen;
-	CScreen*	next;
-};
-
-struct DScreen
-{
-	int		id;
-	int		public;
-	int		ref;
-	DImage	*dimage;
-	DImage	*dfill;
-	Memscreen*	screen;
-	Client*		owner;
-	DScreen*	next;
-};
-
-static	Draw		sdraw;
-static	Client		*client0;
-static	Memimage	*screenimage;
-static	Rectangle	flushrect;
-static	int		waste;
-static	DScreen*	dscreen;
-static	int		drawuninstall(Client*, int);
-static	Memimage*	drawinstall(Client*, int, Memimage*, DScreen*);
-static	void		drawfreedimage(DImage*);
-
-void
-_initdisplaymemimage(Display *d, Memimage *m)
-{
-	screenimage = m;
-	m->screenref = 1;
-	client0 = mallocz(sizeof(Client), 1);
-	if(client0 == nil){
-		fprint(2, "initdraw: allocating client0: out of memory");
-		abort();
-	}
-	client0->slot = 0;
-	client0->clientid = ++sdraw.clientid;
-	client0->op = SoverD;
-	sdraw.client[0] = client0;
-	sdraw.nclient = 1;
-	sdraw.softscreen = 1;
-}
-
-void
-_drawreplacescreenimage(Memimage *m)
-{
-	/*
-	 * Replace the screen image because the screen
-	 * was resized.
-	 * 
-	 * In theory there should only be one reference
-	 * to the current screen image, and that's through
-	 * client0's image 0, installed a few lines above.
-	 * Once the client drops the image, the underlying backing 
-	 * store freed properly.  The client is being notified
-	 * about the resize through external means, so all we
-	 * need to do is this assignment.
-	 */
-	Memimage *om;
-
-	qlock(&sdraw.lk);
-	om = screenimage;
-	screenimage = m;
-	m->screenref = 1;
-	if(om && --om->screenref == 0){
-		_freememimage(om);
-	}
-	qunlock(&sdraw.lk);
-}
-
-static
-void
-drawrefreshscreen(DImage *l, Client *client)
-{
-	while(l != nil && l->dscreen == nil)
-		l = l->fromname;
-	if(l != nil && l->dscreen->owner != client)
-		l->dscreen->owner->refreshme = 1;
-}
-
-static
-void
-drawrefresh(Memimage *m, Rectangle r, void *v)
-{
-	Refx *x;
-	DImage *d;
-	Client *c;
-	Refresh *ref;
-
-	USED(m);
-
-	if(v == 0)
-		return;
-	x = v;
-	c = x->client;
-	d = x->dimage;
-	for(ref=c->refresh; ref; ref=ref->next)
-		if(ref->dimage == d){
-			combinerect(&ref->r, r);
-			return;
-		}
-	ref = mallocz(sizeof(Refresh), 1);
-	if(ref){
-		ref->dimage = d;
-		ref->r = r;
-		ref->next = c->refresh;
-		c->refresh = ref;
-	}
-}
-
-static void
-addflush(Rectangle r)
-{
-	int abb, ar, anbb;
-	Rectangle nbb;
-
-	if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
-		return;
-
-	if(flushrect.min.x >= flushrect.max.x){
-		flushrect = r;
-		waste = 0;
-		return;
-	}
-	nbb = flushrect;
-	combinerect(&nbb, r);
-	ar = Dx(r)*Dy(r);
-	abb = Dx(flushrect)*Dy(flushrect);
-	anbb = Dx(nbb)*Dy(nbb);
-	/*
-	 * Area of new waste is area of new bb minus area of old bb,
-	 * less the area of the new segment, which we assume is not waste.
-	 * This could be negative, but that's OK.
-	 */
-	waste += anbb-abb - ar;
-	if(waste < 0)
-		waste = 0;
-	/*
-	 * absorb if:
-	 *	total area is small
-	 *	waste is less than half total area
-	 * 	rectangles touch
-	 */
-	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
-		flushrect = nbb;
-		return;
-	}
-	/* emit current state */
-	if(flushrect.min.x < flushrect.max.x)
-		_flushmemscreen(flushrect);
-	flushrect = r;
-	waste = 0;
-}
-
-static
-void
-dstflush(int dstid, Memimage *dst, Rectangle r)
-{
-	Memlayer *l;
-
-	if(dstid == 0){
-		combinerect(&flushrect, r);
-		return;
-	}
-	/* how can this happen? -rsc, dec 12 2002 */
-	if(dst == 0){
-		print("nil dstflush\n");
-		return;
-	}
-	l = dst->layer;
-	if(l == nil)
-		return;
-	do{
-		if(l->screen->image->data != screenimage->data)
-			return;
-		r = rectaddpt(r, l->delta);
-		l = l->screen->image->layer;
-	}while(l);
-	addflush(r);
-}
-
-static
-void
-drawflush(void)
-{
-	if(flushrect.min.x < flushrect.max.x)
-		_flushmemscreen(flushrect);
-	flushrect = Rect(10000, 10000, -10000, -10000);
-}
-
-static
-int
-drawcmp(char *a, char *b, int n)
-{
-	if(strlen(a) != n)
-		return 1;
-	return memcmp(a, b, n);
-}
-
-static
-DName*
-drawlookupname(int n, char *str)
-{
-	DName *name, *ename;
-
-	name = sdraw.name;
-	ename = &name[sdraw.nname];
-	for(; name<ename; name++)
-		if(drawcmp(name->name, str, n) == 0)
-			return name;
-	return 0;
-}
-
-static
-int
-drawgoodname(DImage *d)
-{
-	DName *n;
-
-	/* if window, validate the screen's own images */
-	if(d->dscreen)
-		if(drawgoodname(d->dscreen->dimage) == 0
-		|| drawgoodname(d->dscreen->dfill) == 0)
-			return 0;
-	if(d->name == nil)
-		return 1;
-	n = drawlookupname(strlen(d->name), d->name);
-	if(n==nil || n->vers!=d->vers)
-		return 0;
-	return 1;
-}
-
-static
-DImage*
-drawlookup(Client *client, int id, int checkname)
-{
-	DImage *d;
-
-	d = client->dimage[id&HASHMASK];
-	while(d){
-		if(d->id == id){
-			/*
-			 * BUG: should error out but too hard.
-			 * Return 0 instead.
-			 */
-			if(checkname && !drawgoodname(d))
-				return 0;
-			return d;
-		}
-		d = d->next;
-	}
-	return 0;
-}
-
-static
-DScreen*
-drawlookupdscreen(int id)
-{
-	DScreen *s;
-
-	s = dscreen;
-	while(s){
-		if(s->id == id)
-			return s;
-		s = s->next;
-	}
-	return 0;
-}
-
-static
-DScreen*
-drawlookupscreen(Client *client, int id, CScreen **cs)
-{
-	CScreen *s;
-
-	s = client->cscreen;
-	while(s){
-		if(s->dscreen->id == id){
-			*cs = s;
-			return s->dscreen;
-		}
-		s = s->next;
-	}
-	/* caller must check! */
-	return 0;
-}
-
-static
-Memimage*
-drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
-{
-	DImage *d;
-
-	d = mallocz(sizeof(DImage), 1);
-	if(d == 0)
-		return 0;
-	d->id = id;
-	d->ref = 1;
-	d->name = 0;
-	d->vers = 0;
-	d->image = i;
-	if(i->screenref)
-		++i->screenref;
-	d->nfchar = 0;
-	d->fchar = 0;
-	d->fromname = 0;
-	d->dscreen = dscreen;
-	d->next = client->dimage[id&HASHMASK];
-	client->dimage[id&HASHMASK] = d;
-	return i;
-}
-
-static
-Memscreen*
-drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
-{
-	Memscreen *s;
-	CScreen *c;
-
-	c = mallocz(sizeof(CScreen), 1);
-	if(dimage && dimage->image && dimage->image->chan == 0){
-		print("bad image %p in drawinstallscreen", dimage->image);
-		abort();
-	}
-
-	if(c == 0)
-		return 0;
-	if(d == 0){
-		d = mallocz(sizeof(DScreen), 1);
-		if(d == 0){
-			free(c);
-			return 0;
-		}
-		s = mallocz(sizeof(Memscreen), 1);
-		if(s == 0){
-			free(c);
-			free(d);
-			return 0;
-		}
-		s->frontmost = 0;
-		s->rearmost = 0;
-		d->dimage = dimage;
-		if(dimage){
-			s->image = dimage->image;
-			dimage->ref++;
-		}
-		d->dfill = dfill;
-		if(dfill){
-			s->fill = dfill->image;
-			dfill->ref++;
-		}
-		d->ref = 0;
-		d->id = id;
-		d->screen = s;
-		d->public = public;
-		d->next = dscreen;
-		d->owner = client;
-		dscreen = d;
-	}
-	c->dscreen = d;
-	d->ref++;
-	c->next = client->cscreen;
-	client->cscreen = c;
-	return d->screen;
-}
-
-static
-void
-drawdelname(DName *name)
-{
-	int i;
-
-	i = name-sdraw.name;
-	memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
-	sdraw.nname--;
-}
-
-static
-void
-drawfreedscreen(DScreen *this)
-{
-	DScreen *ds, *next;
-
-	this->ref--;
-	if(this->ref < 0)
-		print("negative ref in drawfreedscreen\n");
-	if(this->ref > 0)
-		return;
-	ds = dscreen;
-	if(ds == this){
-		dscreen = this->next;
-		goto Found;
-	}
-	while(next = ds->next){	/* assign = */
-		if(next == this){
-			ds->next = this->next;
-			goto Found;
-		}
-		ds = next;
-	}
-	/*
-	 * Should signal Enodrawimage, but too hard.
-	 */
-	return;
-
-    Found:
-	if(this->dimage)
-		drawfreedimage(this->dimage);
-	if(this->dfill)
-		drawfreedimage(this->dfill);
-	free(this->screen);
-	free(this);
-}
-
-static
-void
-drawfreedimage(DImage *dimage)
-{
-	int i;
-	Memimage *l;
-	DScreen *ds;
-
-	dimage->ref--;
-	if(dimage->ref < 0)
-		print("negative ref in drawfreedimage\n");
-	if(dimage->ref > 0)
-		return;
-
-	/* any names? */
-	for(i=0; i<sdraw.nname; )
-		if(sdraw.name[i].dimage == dimage)
-			drawdelname(sdraw.name+i);
-		else
-			i++;
-	if(dimage->fromname){	/* acquired by name; owned by someone else*/
-		drawfreedimage(dimage->fromname);
-		goto Return;
-	}
-	ds = dimage->dscreen;
-	l = dimage->image;
-	dimage->dscreen = nil;	/* paranoia */
-	dimage->image = nil;
-	if(ds){
-		if(l->data == screenimage->data)
-			addflush(l->layer->screenr);
-		if(l->layer->refreshfn == drawrefresh)	/* else true owner will clean up */
-			free(l->layer->refreshptr);
-		l->layer->refreshptr = nil;
-		if(drawgoodname(dimage))
-			memldelete(l);
-		else
-			memlfree(l);
-		drawfreedscreen(ds);
-	}else{
-		if(l->screenref==0)
-			freememimage(l);
-		else if(--l->screenref==0)
-			_freememimage(l);
-	}
-    Return:
-	free(dimage->fchar);
-	free(dimage);
-}
-
-static
-void
-drawuninstallscreen(Client *client, CScreen *this)
-{
-	CScreen *cs, *next;
-
-	cs = client->cscreen;
-	if(cs == this){
-		client->cscreen = this->next;
-		drawfreedscreen(this->dscreen);
-		free(this);
-		return;
-	}
-	while(next = cs->next){	/* assign = */
-		if(next == this){
-			cs->next = this->next;
-			drawfreedscreen(this->dscreen);
-			free(this);
-			return;
-		}
-		cs = next;
-	}
-}
-
-static
-int
-drawuninstall(Client *client, int id)
-{
-	DImage *d, **l;
-
-	for(l=&client->dimage[id&HASHMASK]; (d=*l) != nil; l=&d->next){
-		if(d->id == id){
-			*l = d->next;
-			drawfreedimage(d);
-			return 0;
-		}
-	}
-	return -1;
-}
-
-static
-int
-drawaddname(Client *client, DImage *di, int n, char *str, char **err)
-{
-	DName *name, *ename, *new, *t;
-	char *ns;
-
-	name = sdraw.name;
-	ename = &name[sdraw.nname];
-	for(; name<ename; name++)
-		if(drawcmp(name->name, str, n) == 0){
-			*err = "image name in use";
-			return -1;
-		}
-	t = mallocz((sdraw.nname+1)*sizeof(DName), 1);
-	ns = malloc(n+1);
-	if(t == nil || ns == nil){
-		free(t);
-		free(ns);
-		*err = "out of memory";
-		return -1;
-	}
-	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
-	free(sdraw.name);
-	sdraw.name = t;
-	new = &sdraw.name[sdraw.nname++];
-	new->name = ns;
-	memmove(new->name, str, n);
-	new->name[n] = 0;
-	new->dimage = di;
-	new->client = client;
-	new->vers = ++sdraw.vers;
-	return 0;
-}
-
-static int
-drawclientop(Client *cl)
-{
-	int op;
-
-	op = cl->op;
-	cl->op = SoverD;
-	return op;
-}
-
-static
-Memimage*
-drawimage(Client *client, uchar *a)
-{
-	DImage *d;
-
-	d = drawlookup(client, BGLONG(a), 1);
-	if(d == nil)
-		return nil;	/* caller must check! */
-	return d->image;
-}
-
-static
-void
-drawrectangle(Rectangle *r, uchar *a)
-{
-	r->min.x = BGLONG(a+0*4);
-	r->min.y = BGLONG(a+1*4);
-	r->max.x = BGLONG(a+2*4);
-	r->max.y = BGLONG(a+3*4);
-}
-
-static
-void
-drawpoint(Point *p, uchar *a)
-{
-	p->x = BGLONG(a+0*4);
-	p->y = BGLONG(a+1*4);
-}
-
-static
-Point
-drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
-{
-	FChar *fc;
-	Rectangle r;
-	Point sp1;
-
-	fc = &font->fchar[index];
-	r.min.x = p.x+fc->left;
-	r.min.y = p.y-(font->ascent-fc->miny);
-	r.max.x = r.min.x+(fc->maxx-fc->minx);
-	r.max.y = r.min.y+(fc->maxy-fc->miny);
-	sp1.x = sp->x+fc->left;
-	sp1.y = sp->y+fc->miny;
-	memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
-	p.x += fc->width;
-	sp->x += fc->width;
-	return p;
-}
-
-static
-uchar*
-drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
-{
-	int b, x;
-
-	if(p >= maxp)
-		return nil;
-	b = *p++;
-	x = b & 0x7F;
-	if(b & 0x80){
-		if(p+1 >= maxp)
-			return nil;
-		x |= *p++ << 7;
-		x |= *p++ << 15;
-		if(x & (1<<22))
-			x |= ~0<<23;
-	}else{
-		if(b & 0x40)
-			x |= ~0<<7;
-		x += oldx;
-	}
-	*newx = x;
-	return p;
-}
-
-int
-_drawmsgread(Display *d, void *a, int n)
-{
-	Client *cl;
-
-	qlock(&sdraw.lk);
-	cl = client0;
-	if(cl->readdata == nil){
-		werrstr("no draw data");
-		goto err;
-	}
-	if(n < cl->nreaddata){
-		werrstr("short read");
-		goto err;
-	}
-	n = cl->nreaddata;
-	memmove(a, cl->readdata, cl->nreaddata);
-	free(cl->readdata);
-	cl->readdata = nil;
-	qunlock(&sdraw.lk);
-	return n;
-
-err:
-	qunlock(&sdraw.lk);
-	return -1;
-}
-
-int
-_drawmsgwrite(Display *d, void *v, int n)
-{
-	char cbuf[40], *err, ibuf[12*12+1], *s;
-	int c, ci, doflush, dstid, e0, e1, esize, j, m;
-	int ni, nw, oesize, oldn, op, ox, oy, repl, scrnid, y; 
-	uchar *a, refresh, *u;
-	u32int chan, value;
-	Client *client;
-	CScreen *cs;
-	DImage *di, *ddst, *dsrc, *font, *ll;
-	DName *dn;
-	DScreen *dscrn;
-	FChar *fc;
-	Memimage *dst, *i, *l, **lp, *mask, *src;
-	Memscreen *scrn;
-	Point p, *pp, q, sp;
-	Rectangle clipr, r;
-	Refreshfn reffn;
-	Refx *refx;
-
-	qlock(&sdraw.lk);
-	d->obufp = d->obuf;
-	a = v;
-	m = 0;
-	oldn = n;
-	client = client0;
-
-	while((n-=m) > 0){
-		a += m;
-/*fprint(2, "msgwrite %d(%d)...", n, *a); */
-		switch(*a){
-		default:
-/*fprint(2, "bad command %d\n", *a); */
-			err = "bad draw command";
-			goto error;
-
-		/* allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1]
-			R[4*4] clipR[4*4] rrggbbaa[4]
-		 */
-		case 'b':
-			m = 1+4+4+1+4+1+4*4+4*4+4;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			scrnid = BGSHORT(a+5);
-			refresh = a[9];
-			chan = BGLONG(a+10);
-			repl = a[14];
-			drawrectangle(&r, a+15);
-			drawrectangle(&clipr, a+31);
-			value = BGLONG(a+47);
-			if(drawlookup(client, dstid, 0))
-				goto Eimageexists;
-			if(scrnid){
-				dscrn = drawlookupscreen(client, scrnid, &cs);
-				if(!dscrn)
-					goto Enodrawscreen;
-				scrn = dscrn->screen;
-				if(repl || chan!=scrn->image->chan){
-					err = "image parameters incompatibile with screen";
-					goto error;
-				}
-				reffn = 0;
-				switch(refresh){
-				case Refbackup:
-					break;
-				case Refnone:
-					reffn = memlnorefresh;
-					break;
-				case Refmesg:
-					reffn = drawrefresh;
-					break;
-				default:
-					err = "unknown refresh method";
-					goto error;
-				}
-				l = memlalloc(scrn, r, reffn, 0, value);
-				if(l == 0)
-					goto Edrawmem;
-				addflush(l->layer->screenr);
-				l->clipr = clipr;
-				rectclip(&l->clipr, r);
-				if(drawinstall(client, dstid, l, dscrn) == 0){
-					memldelete(l);
-					goto Edrawmem;
-				}
-				dscrn->ref++;
-				if(reffn){
-					refx = nil;
-					if(reffn == drawrefresh){
-						refx = mallocz(sizeof(Refx), 1);
-						if(refx == 0){
-							if(drawuninstall(client, dstid) < 0)
-								goto Enodrawimage;
-							goto Edrawmem;
-						}
-						refx->client = client;
-						refx->dimage = drawlookup(client, dstid, 1);
-					}
-					memlsetrefresh(l, reffn, refx);
-				}
-				continue;
-			}
-			i = allocmemimage(r, chan);
-			if(i == 0)
-				goto Edrawmem;
-			if(repl)
-				i->flags |= Frepl;
-			i->clipr = clipr;
-			if(!repl)
-				rectclip(&i->clipr, r);
-			if(drawinstall(client, dstid, i, 0) == 0){
-				freememimage(i);
-				goto Edrawmem;
-			}
-			memfillcolor(i, value);
-			continue;
-
-		/* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
-		case 'A':
-			m = 1+4+4+4+1;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			if(dstid == 0)
-				goto Ebadarg;
-			if(drawlookupdscreen(dstid))
-				goto Escreenexists;
-			ddst = drawlookup(client, BGLONG(a+5), 1);
-			dsrc = drawlookup(client, BGLONG(a+9), 1);
-			if(ddst==0 || dsrc==0)
-				goto Enodrawimage;
-			if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
-				goto Edrawmem;
-			continue;
-
-		/* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
-		case 'c':
-			m = 1+4+1+4*4;
-			if(n < m)
-				goto Eshortdraw;
-			ddst = drawlookup(client, BGLONG(a+1), 1);
-			if(ddst == nil)
-				goto Enodrawimage;
-			if(ddst->name){
-				err = "can't change repl/clipr of shared image";
-				goto error;
-			}
-			dst = ddst->image;
-			if(a[5])
-				dst->flags |= Frepl;
-			drawrectangle(&dst->clipr, a+6);
-			continue;
-
-		/* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
-		case 'd':
-			m = 1+4+4+4+4*4+2*4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-			dst = drawimage(client, a+1);
-			dstid = BGLONG(a+1);
-			src = drawimage(client, a+5);
-			mask = drawimage(client, a+9);
-			if(!dst || !src || !mask)
-				goto Enodrawimage;
-			drawrectangle(&r, a+13);
-			drawpoint(&p, a+29);
-			drawpoint(&q, a+37);
-			op = drawclientop(client);
-			memdraw(dst, r, src, p, mask, q, op);
-			dstflush(dstid, dst, r);
-			continue;
-
-		/* toggle debugging: 'D' val[1] */
-		case 'D':
-			m = 1+1;
-			if(n < m)
-				goto Eshortdraw;
-			drawdebug = a[1];
-			continue;
-
-		/* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
-		case 'e':
-		case 'E':
-			m = 1+4+4+2*4+4+4+4+2*4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-			dst = drawimage(client, a+1);
-			dstid = BGLONG(a+1);
-			src = drawimage(client, a+5);
-			if(!dst || !src)
-				goto Enodrawimage;
-			drawpoint(&p, a+9);
-			e0 = BGLONG(a+17);
-			e1 = BGLONG(a+21);
-			if(e0<0 || e1<0){
-				err = "invalid ellipse semidiameter";
-				goto error;
-			}
-			j = BGLONG(a+25);
-			if(j < 0){
-				err = "negative ellipse thickness";
-				goto error;
-			}
-			
-			drawpoint(&sp, a+29);
-			c = j;
-			if(*a == 'E')
-				c = -1;
-			ox = BGLONG(a+37);
-			oy = BGLONG(a+41);
-			op = drawclientop(client);
-			/* high bit indicates arc angles are present */
-			if(ox & ((ulong)1<<31)){
-				if((ox & ((ulong)1<<30)) == 0)
-					ox &= ~((ulong)1<<31);
-				memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
-			}else
-				memellipse(dst, p, e0, e1, c, src, sp, op);
-			dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
-			continue;
-
-		/* free: 'f' id[4] */
-		case 'f':
-			m = 1+4;
-			if(n < m)
-				goto Eshortdraw;
-			ll = drawlookup(client, BGLONG(a+1), 0);
-			if(ll && ll->dscreen && ll->dscreen->owner != client)
-				ll->dscreen->owner->refreshme = 1;
-			if(drawuninstall(client, BGLONG(a+1)) < 0)
-				goto Enodrawimage;
-			continue;
-
-		/* free screen: 'F' id[4] */
-		case 'F':
-			m = 1+4;
-			if(n < m)
-				goto Eshortdraw;
-			if(!drawlookupscreen(client, BGLONG(a+1), &cs))
-				goto Enodrawscreen;
-			drawuninstallscreen(client, cs);
-			continue;
-
-		/* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
-		case 'i':
-			m = 1+4+4+1;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			if(dstid == 0){
-				err = "can't use display as font";
-				goto error;
-			}
-			font = drawlookup(client, dstid, 1);
-			if(font == 0)
-				goto Enodrawimage;
-			if(font->image->layer){
-				err = "can't use window as font";
-				goto error;
-			}
-			ni = BGLONG(a+5);
-			if(ni<=0 || ni>4096){
-				err = "bad font size (4096 chars max)";
-				goto error;
-			}
-			free(font->fchar);	/* should we complain if non-zero? */
-			font->fchar = mallocz(ni*sizeof(FChar), 1);
-			if(font->fchar == 0){
-				err = "no memory for font";
-				goto error;
-			}
-			memset(font->fchar, 0, ni*sizeof(FChar));
-			font->nfchar = ni;
-			font->ascent = a[9];
-			continue;
-
-		/* set image 0 to screen image */
-		case 'J':
-			m = 1;
-			if(n < m)
-				goto Eshortdraw;
-			if(drawlookup(client, 0, 0))
-				goto Eimageexists;
-			drawinstall(client, 0, screenimage, 0);
-			client->infoid = 0;
-			continue;
-
-		/* get image info: 'I' */
-		case 'I':
-			m = 1;
-			if(n < m)
-				goto Eshortdraw;
-			if(client->infoid < 0)
-				goto Enodrawimage;
-			if(client->infoid == 0){
-				i = screenimage;
-				if(i == nil)
-					goto Enodrawimage;
-			}else{
-				di = drawlookup(client, client->infoid, 1);
-				if(di == nil)
-					goto Enodrawimage;
-				i = di->image;
-			}
-			ni = sprint(ibuf, "%11d %11d %11s %11d %11d %11d %11d %11d"
-					" %11d %11d %11d %11d ",
-					client->clientid,
-					client->infoid,	
-					chantostr(cbuf, i->chan),
-					(i->flags&Frepl)==Frepl,
-					i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
-					i->clipr.min.x, i->clipr.min.y, 
-					i->clipr.max.x, i->clipr.max.y);
-			free(client->readdata);
-			client->readdata = malloc(ni);
-			if(client->readdata == nil)
-				goto Enomem;
-			memmove(client->readdata, ibuf, ni);
-			client->nreaddata = ni;
-			client->infoid = -1;
-			continue;	
-
-		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
-		case 'l':
-			m = 1+4+4+2+4*4+2*4+1+1;
-			if(n < m)
-				goto Eshortdraw;
-			font = drawlookup(client, BGLONG(a+1), 1);
-			if(font == 0)
-				goto Enodrawimage;
-			if(font->nfchar == 0)
-				goto Enotfont;
-			src = drawimage(client, a+5);
-			if(!src)
-				goto Enodrawimage;
-			ci = BGSHORT(a+9);
-			if(ci >= font->nfchar)
-				goto Eindex;
-			drawrectangle(&r, a+11);
-			drawpoint(&p, a+27);
-			memdraw(font->image, r, src, p, memopaque, p, S);
-			fc = &font->fchar[ci];
-			fc->minx = r.min.x;
-			fc->maxx = r.max.x;
-			fc->miny = r.min.y;
-			fc->maxy = r.max.y;
-			fc->left = a[35];
-			fc->width = a[36];
-			continue;
-
-		/* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
-		case 'L':
-			m = 1+4+2*4+2*4+4+4+4+4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-			dst = drawimage(client, a+1);
-			dstid = BGLONG(a+1);
-			drawpoint(&p, a+5);
-			drawpoint(&q, a+13);
-			e0 = BGLONG(a+21);
-			e1 = BGLONG(a+25);
-			j = BGLONG(a+29);
-			if(j < 0){
-				err = "negative line width";
-				goto error;
-			}
-			src = drawimage(client, a+33);
-			if(!dst || !src)
-				goto Enodrawimage;
-			drawpoint(&sp, a+37);
-			op = drawclientop(client);
-			memline(dst, p, q, e0, e1, j, src, sp, op);
-			/* avoid memlinebbox if possible */
-			if(dstid==0 || dst->layer!=nil){
-				/* BUG: this is terribly inefficient: update maximal containing rect*/
-				r = memlinebbox(p, q, e0, e1, j);
-				dstflush(dstid, dst, insetrect(r, -(1+1+j)));
-			}
-			continue;
-
-		/* create image mask: 'm' newid[4] id[4] */
-/*
- *
-		case 'm':
-			m = 4+4;
-			if(n < m)
-				goto Eshortdraw;
-			break;
- *
- */
-
-		/* attach to a named image: 'n' dstid[4] j[1] name[j] */
-		case 'n':
-			m = 1+4+1;
-			if(n < m)
-				goto Eshortdraw;
-			j = a[5];
-			if(j == 0)	/* give me a non-empty name please */
-				goto Eshortdraw;
-			m += j;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			if(drawlookup(client, dstid, 0))
-				goto Eimageexists;
-			dn = drawlookupname(j, (char*)a+6);
-			if(dn == nil)
-				goto Enoname;
-			s = malloc(j+1);
-			if(s == nil)
-				goto Enomem;
-			if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
-				goto Edrawmem;
-			di = drawlookup(client, dstid, 0);
-			if(di == 0)
-				goto Eoldname;
-			di->vers = dn->vers;
-			di->name = s;
-			di->fromname = dn->dimage;
-			di->fromname->ref++;
-			memmove(di->name, a+6, j);
-			di->name[j] = 0;
-			client->infoid = dstid;
-			continue;
-
-		/* name an image: 'N' dstid[4] in[1] j[1] name[j] */
-		case 'N':
-			m = 1+4+1+1;
-			if(n < m)
-				goto Eshortdraw;
-			c = a[5];
-			j = a[6];
-			if(j == 0)	/* give me a non-empty name please */
-				goto Eshortdraw;
-			m += j;
-			if(n < m)
-				goto Eshortdraw;
-			di = drawlookup(client, BGLONG(a+1), 0);
-			if(di == 0)
-				goto Enodrawimage;
-			if(di->name)
-				goto Enamed;
-			if(c)
-				if(drawaddname(client, di, j, (char*)a+7, &err) < 0)
-					goto error;
-			else{
-				dn = drawlookupname(j, (char*)a+7);
-				if(dn == nil)
-					goto Enoname;
-				if(dn->dimage != di)
-					goto Ewrongname;
-				drawdelname(dn);
-			}
-			continue;
-
-		/* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
-		case 'o':
-			m = 1+4+2*4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-			dst = drawimage(client, a+1);
-			if(!dst)
-				goto Enodrawimage;
-			if(dst->layer){
-				drawpoint(&p, a+5);
-				drawpoint(&q, a+13);
-				r = dst->layer->screenr;
-				ni = memlorigin(dst, p, q);
-				if(ni < 0){
-					err = "image origin failed";
-					goto error;
-				}
-				if(ni > 0){
-					addflush(r);
-					addflush(dst->layer->screenr);
-					ll = drawlookup(client, BGLONG(a+1), 1);
-					drawrefreshscreen(ll, client);
-				}
-			}
-			continue;
-
-		/* set compositing operator for next draw operation: 'O' op */
-		case 'O':
-			m = 1+1;
-			if(n < m)
-				goto Eshortdraw;
-			client->op = a[1];
-			continue;
-
-		/* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
-		/* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
-		case 'p':
-		case 'P':
-			m = 1+4+2+4+4+4+4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			dst = drawimage(client, a+1);
-			ni = BGSHORT(a+5);
-			if(ni < 0){
-				err = "negative cout in polygon";
-				goto error;
-			}
-			e0 = BGLONG(a+7);
-			e1 = BGLONG(a+11);
-			j = 0;
-			if(*a == 'p'){
-				j = BGLONG(a+15);
-				if(j < 0){
-					err = "negative polygon line width";
-					goto error;
-				}
-			}
-			src = drawimage(client, a+19);
-			if(!dst || !src)
-				goto Enodrawimage;
-			drawpoint(&sp, a+23);
-			drawpoint(&p, a+31);
-			ni++;
-			pp = mallocz(ni*sizeof(Point), 1);
-			if(pp == nil)
-				goto Enomem;
-			doflush = 0;
-			if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
-				doflush = 1;	/* simplify test in loop */
-			ox = oy = 0;
-			esize = 0;
-			u = a+m;
-			for(y=0; y<ni; y++){
-				q = p;
-				oesize = esize;
-				u = drawcoord(u, a+n, ox, &p.x);
-				if(!u)
-					goto Eshortdraw;
-				u = drawcoord(u, a+n, oy, &p.y);
-				if(!u)
-					goto Eshortdraw;
-				ox = p.x;
-				oy = p.y;
-				if(doflush){
-					esize = j;
-					if(*a == 'p'){
-						if(y == 0){
-							c = memlineendsize(e0);
-							if(c > esize)
-								esize = c;
-						}
-						if(y == ni-1){
-							c = memlineendsize(e1);
-							if(c > esize)
-								esize = c;
-						}
-					}
-					if(*a=='P' && e0!=1 && e0 !=~0)
-						r = dst->clipr;
-					else if(y > 0){
-						r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
-						combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
-					}
-					if(rectclip(&r, dst->clipr))		/* should perhaps be an arg to dstflush */
-						dstflush(dstid, dst, r);
-				}
-				pp[y] = p;
-			}
-			if(y == 1)
-				dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
-			op = drawclientop(client);
-			if(*a == 'p')
-				mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
-			else
-				memfillpoly(dst, pp, ni, e0, src, sp, op);
-			free(pp);
-			m = u-a;
-			continue;
-
-		/* read: 'r' id[4] R[4*4] */
-		case 'r':
-			m = 1+4+4*4;
-			if(n < m)
-				goto Eshortdraw;
-			i = drawimage(client, a+1);
-			if(!i)
-				goto Enodrawimage;
-			drawrectangle(&r, a+5);
-			if(!rectinrect(r, i->r))
-				goto Ereadoutside;
-			c = bytesperline(r, i->depth);
-			c *= Dy(r);
-			free(client->readdata);
-			client->readdata = mallocz(c, 0);
-			if(client->readdata == nil){
-				err = "readimage malloc failed";
-				goto error;
-			}
-			client->nreaddata = memunload(i, r, client->readdata, c);
-			if(client->nreaddata < 0){
-				free(client->readdata);
-				client->readdata = nil;
-				err = "bad readimage call";
-				goto error;
-			}
-			continue;
-
-		/* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
-		/* 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]) */
-		case 's':
-		case 'x':
-			m = 1+4+4+4+2*4+4*4+2*4+2;
-			if(*a == 'x')
-				m += 4+2*4;
-			if(n < m)
-				goto Eshortdraw;
-
-			dst = drawimage(client, a+1);
-			dstid = BGLONG(a+1);
-			src = drawimage(client, a+5);
-			if(!dst || !src)
-				goto Enodrawimage;
-			font = drawlookup(client, BGLONG(a+9), 1);
-			if(font == 0)
-				goto Enodrawimage;
-			if(font->nfchar == 0)
-				goto Enotfont;
-			drawpoint(&p, a+13);
-			drawrectangle(&r, a+21);
-			drawpoint(&sp, a+37);
-			ni = BGSHORT(a+45);
-			u = a+m;
-			m += ni*2;
-			if(n < m)
-				goto Eshortdraw;
-			clipr = dst->clipr;
-			dst->clipr = r;
-			op = drawclientop(client);
-			if(*a == 'x'){
-				/* paint background */
-				l = drawimage(client, a+47);
-				if(!l)
-					goto Enodrawimage;
-				drawpoint(&q, a+51);
-				r.min.x = p.x;
-				r.min.y = p.y-font->ascent;
-				r.max.x = p.x;
-				r.max.y = r.min.y+Dy(font->image->r);
-				j = ni;
-				while(--j >= 0){
-					ci = BGSHORT(u);
-					if(ci<0 || ci>=font->nfchar){
-						dst->clipr = clipr;
-						goto Eindex;
-					}
-					r.max.x += font->fchar[ci].width;
-					u += 2;
-				}
-				memdraw(dst, r, l, q, memopaque, ZP, op);
-				u -= 2*ni;
-			}
-			q = p;
-			while(--ni >= 0){
-				ci = BGSHORT(u);
-				if(ci<0 || ci>=font->nfchar){
-					dst->clipr = clipr;
-					goto Eindex;
-				}
-				q = drawchar(dst, q, src, &sp, font, ci, op);
-				u += 2;
-			}
-			dst->clipr = clipr;
-			p.y -= font->ascent;
-			dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
-			continue;
-
-		/* use public screen: 'S' id[4] chan[4] */
-		case 'S':
-			m = 1+4+4;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			if(dstid == 0)
-				goto Ebadarg;
-			dscrn = drawlookupdscreen(dstid);
-			if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
-				goto Enodrawscreen;
-			if(dscrn->screen->image->chan != BGLONG(a+5)){
-				err = "inconsistent chan";
-				goto error;
-			}
-			if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
-				goto Edrawmem;
-			continue;
-
-		/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
-		case 't':
-			m = 1+1+2;
-			if(n < m)
-				goto Eshortdraw;
-			nw = BGSHORT(a+2);
-			if(nw < 0)
-				goto Ebadarg;
-			if(nw == 0)
-				continue;
-			m += nw*4;
-			if(n < m)
-				goto Eshortdraw;
-			lp = mallocz(nw*sizeof(Memimage*), 1);
-			if(lp == 0)
-				goto Enomem;
-			for(j=0; j<nw; j++){
-				lp[j] = drawimage(client, a+1+1+2+j*4);
-				if(lp[j] == nil){
-					free(lp);
-					goto Enodrawimage;
-				}
-			}
-			if(lp[0]->layer == 0){
-				err = "images are not windows";
-				free(lp);
-				goto error;
-			}
-			for(j=1; j<nw; j++)
-				if(lp[j]->layer->screen != lp[0]->layer->screen){
-					err = "images not on same screen";
-					free(lp);
-					goto error;
-				}
-			if(a[1])
-				memltofrontn(lp, nw);
-			else
-				memltorearn(lp, nw);
-			if(lp[0]->layer->screen->image->data == screenimage->data)
-				for(j=0; j<nw; j++)
-					addflush(lp[j]->layer->screenr);
-			free(lp);
-			ll = drawlookup(client, BGLONG(a+1+1+2), 1);
-			drawrefreshscreen(ll, client);
-			continue;
-
-		/* visible: 'v' */
-		case 'v':
-			m = 1;
-			drawflush();
-			continue;
-
-		/* write: 'y' id[4] R[4*4] data[x*1] */
-		/* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
-		case 'y':
-		case 'Y':
-			m = 1+4+4*4;
-			if(n < m)
-				goto Eshortdraw;
-			dstid = BGLONG(a+1);
-			dst = drawimage(client, a+1);
-			if(!dst)
-				goto Enodrawimage;
-			drawrectangle(&r, a+5);
-			if(!rectinrect(r, dst->r))
-				goto Ewriteoutside;
-			y = memload(dst, r, a+m, n-m, *a=='Y');
-			if(y < 0){
-				err = "bad writeimage call";
-				goto error;
-			}
-			dstflush(dstid, dst, r);
-			m += y;
-			continue;
-		}
-	}
-	qunlock(&sdraw.lk);
-	return oldn - n;
-
-Enodrawimage:
-	err = "unknown id for draw image";
-	goto error;
-Enodrawscreen:
-	err = "unknown id for draw screen";
-	goto error;
-Eshortdraw:
-	err = "short draw message";
-	goto error;
-/*
-Eshortread:
-	err = "draw read too short";
-	goto error;
-*/
-Eimageexists:
-	err = "image id in use";
-	goto error;
-Escreenexists:
-	err = "screen id in use";
-	goto error;
-Edrawmem:
-	err = "image memory allocation failed";
-	goto error;
-Ereadoutside:
-	err = "readimage outside image";
-	goto error;
-Ewriteoutside:
-	err = "writeimage outside image";
-	goto error;
-Enotfont:
-	err = "image not a font";
-	goto error;
-Eindex:
-	err = "character index out of range";
-	goto error;
-/*
-Enoclient:
-	err = "no such draw client";
-	goto error;
-Edepth:
-	err = "image has bad depth";
-	goto error;
-Enameused:
-	err = "image name in use";
-	goto error;
-*/
-Enoname:
-	err = "no image with that name";
-	goto error;
-Eoldname:
-	err = "named image no longer valid";
-	goto error;
-Enamed:
-	err = "image already has name";
-	goto error;
-Ewrongname:
-	err = "wrong name for image";
-	goto error;
-Enomem:
-	err = "out of memory";
-	goto error;
-Ebadarg:
-	err = "bad argument in draw message";
-	goto error;
-
-error:
-	werrstr("%s", err);
-	qunlock(&sdraw.lk);
-	return -1;
-}
-
-
blob - ae8719a9e618d7e69009d13cd28825f7d9ef795e
blob + 8fe1b79f24a5f2b1deaab1c1699134de334d4fb8
--- src/libdraw/drawclient.c
+++ src/libdraw/drawclient.c
@@ -1,6 +1,7 @@
 /* Copyright (c) 2006 Russ Cox */
 
 #include <u.h>
+#include <sys/select.h>
 #include <libc.h>
 #include <draw.h>
 #include <mouse.h>
@@ -12,8 +13,10 @@ int chattydrawclient;
 
 static int	drawgettag(Mux *mux, void *vmsg);
 static void*	drawrecv(Mux *mux);
+static void*	drawnbrecv(Mux *mux);
 static int	drawsend(Mux *mux, void *vmsg);
 static int	drawsettag(Mux *mux, void *vmsg, uint tag);
+static int canreadfd(int);
 
 int
 _displayconnect(Display *d)
@@ -35,8 +38,8 @@ _displayconnect(Display *d)
 		dup(p[1], 0);
 		dup(p[1], 1);
 		/* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
-		execl("drawsrv", "drawsrv", nil);
-		sysfatal("exec drawsrv: %r");
+		execl("devdraw", "devdraw", nil);
+		sysfatal("exec devdraw: %r");
 	}
 	close(p[1]);
 	d->srvfd = p[0];
@@ -53,6 +56,7 @@ _displaymux(Display *d)
 	d->mux->maxtag = 255;
 	d->mux->send = drawsend;
 	d->mux->recv = drawrecv;
+	d->mux->nbrecv = drawnbrecv;
 	d->mux->gettag = drawgettag;
 	d->mux->settag = drawsettag;
 	d->mux->aux = d;
@@ -61,9 +65,6 @@ _displaymux(Display *d)
 	return 0;
 }
 
-#define GET(p, x) \
-	((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3])))
-
 static int
 drawsend(Mux *mux, void *vmsg)
 {
@@ -78,17 +79,17 @@ drawsend(Mux *mux, void *vmsg)
 }
 
 static void*
-drawrecv(Mux *mux)
+_drawrecv(Mux *mux, int nb)
 {
 	int n;
 	uchar buf[4], *p;
 	Display *d;
-	
+
 	d = mux->aux;
-	if((n=readn(d->srvfd, buf, 4)) != 4){
-fprint(2, "readn 4 got %d: %r\n", n);
+	if(nb && !canreadfd(d->srvfd))
 		return nil;
-	}
+	if((n=readn(d->srvfd, buf, 4)) != 4)
+		return nil;
 	GET(buf, n);
 	p = malloc(n);
 	if(p == nil){
@@ -96,13 +97,23 @@ fprint(2, "readn 4 got %d: %r\n", n);
 		return nil;
 	}
 	memmove(p, buf, 4);
-	if(readn(d->srvfd, p+4, n-4) != n-4){
-fprint(2, "short readn\n");
+	if(readn(d->srvfd, p+4, n-4) != n-4)
 		return nil;
-	}
 	return p;
 }
 
+static void*
+drawrecv(Mux *mux)
+{
+	return _drawrecv(mux, 0);
+}
+
+static void*
+drawnbrecv(Mux *mux)
+{
+	return _drawrecv(mux, 1);
+}
+
 static int
 drawgettag(Mux *mux, void *vmsg)
 {
@@ -186,8 +197,8 @@ _displayinit(Display *d, char *label, char *winsize)
 	Wsysmsg tx, rx;
 
 	tx.type = Tinit;
-	tx.label = "";
-	tx.winsize = "";
+	tx.label = label;
+	tx.winsize = winsize;
 	return displayrpc(d, &tx, &rx, nil);
 }
 
@@ -334,3 +345,23 @@ _displayresize(Display *d, Rectangle r)
 	return displayrpc(d, &tx, &rx, nil);
 }
 
+static int
+canreadfd(int fd)
+{
+	fd_set rs, ws, xs;
+	struct timeval tv;
+	
+	FD_ZERO(&rs);
+	FD_ZERO(&ws);
+	FD_ZERO(&xs);
+	FD_SET(fd, &rs);
+	FD_SET(fd, &xs);
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
+		return 0;
+	if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
+		return 1;
+	return 0;
+}
+
blob - 09a54f91ef01081f809b06cc6022dfacae277438
blob + e2d3c642f629e4a373cd7e8ab912f04fc454d558
--- src/libdraw/drawfcall.c
+++ src/libdraw/drawfcall.c
@@ -4,26 +4,12 @@
 #include <mouse.h>
 #include <cursor.h>
 #include <drawfcall.h>
-
-#define PUT(p, x) \
-	(p)[0] = ((x) >> 24)&0xFF, \
-	(p)[1] = ((x) >> 16)&0xFF, \
-	(p)[2] = ((x) >> 8)&0xFF, \
-	(p)[3] = (x)&0xFF
-
-#define GET(p, x) \
-	((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3])))
-
-#define PUT2(p, x) \
-	(p)[0] = ((x) >> 8)&0xFF, \
-	(p)[1] = (x)&0xFF
-
-#define GET2(p, x) \
-	((x) = (((p)[0] << 8) | ((p)[1])))
 
 static int
 _stringsize(char *s)
 {
+	if(s == nil)
+		s = "";
 	return 4+strlen(s);
 }
 
blob - 6e4d7f5c3e5424fe8371deb521129783e2b63f19
blob + 1da3fb3987e90271dbb173b81b09e2051a462597
--- src/libdraw/event.c
+++ src/libdraw/event.c
@@ -4,42 +4,52 @@
 #include <draw.h>
 #include <cursor.h>
 #include <event.h>
+#include <mux.h>
+#include <drawfcall.h>
 
+typedef struct	Slave Slave;
+typedef struct	Ebuf Ebuf;
 
+struct Slave
+{
+	int	inuse;
+	Ebuf	*head;		/* queue of messages for this descriptor */
+	Ebuf	*tail;
+	int	(*fn)(int, Event*, uchar*, int);
+	Muxrpc *rpc;
+	vlong nexttick;
+	int fd;
+	int n;
+};
 
+struct Ebuf
+{
+	Ebuf	*next;
+	int	n;		/* number of bytes in buf */
+	union {
+		uchar	buf[EMAXMSG];
+		Rune	rune;
+		Mouse	mouse;
+	} u;
+};
+
+static	Slave	eslave[MAXSLAVE];
 static	int	Skeyboard = -1;
 static	int	Smouse = -1;
 static	int	Stimer = -1;
-static	int	logfid;
 
 static	int	nslave;
-static	int	parentpid;
-static	int	epipe[2];
-static	int	eforkslave(ulong);
-static	void	extract(void);
-static	void	ekill(void);
-static	int	enote(void *, char *);
-static	int	mousefd;
-static	int	cursorfd;
+static	int	newkey(ulong);
+static	int	extract(int canblock);
 
 static
 Ebuf*
 ebread(Slave *s)
 {
 	Ebuf *eb;
-	Dir *d;
-	ulong l;
 
-	for(;;){
-		d = dirfstat(epipe[0]);
-		if(d == nil)
-			drawerror(display, "events: eread stat error");
-		l = d->length;
-		free(d);
-		if(s->head && l==0)
-			break;
-		extract();
-	}
+	while(!s->head)
+		extract(1);
 	eb = s->head;
 	s->head = s->head->next;
 	if(s->head == 0)
@@ -75,14 +85,14 @@ eread(ulong keys, Event *e)
 					eb = ebread(&eslave[i]);
 					e->n = eb->n;
 					if(eslave[i].fn)
-						id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
+						id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n);
 					else
-						memmove(e->data, eb->buf, eb->n);
+						memmove(e->data, eb->u.buf, eb->n);
 					free(eb);
 				}
 				return id;
 			}
-		extract();
+		extract(0);
 	}
 	return 0;
 }
@@ -106,22 +116,14 @@ ecankbd(void)
 int
 ecanread(ulong keys)
 {
-	Dir *d;
 	int i;
-	ulong l;
 
 	for(;;){
 		for(i=0; i<nslave; i++)
 			if((keys & (1<<i)) && eslave[i].head)
 				return 1;
-		d = dirfstat(epipe[0]);
-		if(d == nil)
-			drawerror(display, "events: ecanread stat error");
-		l = d->length;
-		free(d);
-		if(l == 0)
+		if(!extract(0))
 			return 0;
-		extract();
 	}
 	return -1;
 }
@@ -129,26 +131,17 @@ ecanread(ulong keys)
 ulong
 estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
 {
-	char buf[EMAXMSG+1];
-	int i, r;
+	int i;
 
 	if(fd < 0)
 		drawerror(display, "events: bad file descriptor");
 	if(n <= 0 || n > EMAXMSG)
 		n = EMAXMSG;
-	i = eforkslave(key);
-	if(i < MAXSLAVE){
-		eslave[i].fn = fn;
-		return 1<<i;
-	}
-	buf[0] = i - MAXSLAVE;
-	while((r = read(fd, buf+1, n))>0)
-		if(write(epipe[1], buf, r+1)!=r+1)
-			break;
-	buf[0] = MAXSLAVE;
-	write(epipe[1], buf, 1);
-	_exits(0);
-	return 0;
+	i = newkey(key);
+	eslave[i].fn = fn;
+	eslave[i].fd = fd;
+	eslave[i].n = n;
+	return 1<<i;
 }
 
 ulong
@@ -160,110 +153,98 @@ estart(ulong key, int fd, int n)
 ulong
 etimer(ulong key, int n)
 {
-	char t[2];
-
 	if(Stimer != -1)
 		drawerror(display, "events: timer started twice");
-	Stimer = eforkslave(key);
-	if(Stimer < MAXSLAVE)
-		return 1<<Stimer;
+	Stimer = newkey(key);
 	if(n <= 0)
 		n = 1000;
-	t[0] = t[1] = Stimer - MAXSLAVE;
-	do
-		sleep(n);
-	while(write(epipe[1], t, 2) == 2);
-	t[0] = MAXSLAVE;
-	write(epipe[1], t, 1);
-	_exits(0);
-	return 0;
-}
-
-static void
-ekeyslave(int fd)
-{
-	Rune r;
-	char t[3], k[10];
-	int kr, kn, w;
-
-	if(eforkslave(Ekeyboard) < MAXSLAVE)
-		return;
-	kn = 0;
-	t[0] = Skeyboard;
-	for(;;){
-		while(!fullrune(k, kn)){
-			kr = read(fd, k+kn, sizeof k - kn);
-			if(kr <= 0)
-				goto breakout;
-			kn += kr;
-		}
-		w = chartorune(&r, k);
-		kn -= w;
-		memmove(k, &k[w], kn);
-		t[1] = r;
-		t[2] = r>>8;
-		if(write(epipe[1], t, 3) != 3)
-			break;
-	}
-breakout:;
-	t[0] = MAXSLAVE;
-	write(epipe[1], t, 1);
-	_exits(0);
+	eslave[Stimer].n = n;
+	eslave[Stimer].nexttick = nsec()+n*1000LL;
+	return 1<<Stimer;
 }
 
 void
 einit(ulong keys)
 {
-	int ctl, fd;
-	char buf[256];
-
-	parentpid = getpid();
-	if(pipe(epipe) < 0)
-		drawerror(display, "events: einit pipe");
-	atexit(ekill);
-	atnotify(enote, 1);
-	snprint(buf, sizeof buf, "%s/mouse", display->devdir);
-	mousefd = open(buf, ORDWR|OCEXEC);
-	if(mousefd < 0)
-		drawerror(display, "einit: can't open mouse\n");
-	snprint(buf, sizeof buf, "%s/cursor", display->devdir);
-	cursorfd = open(buf, ORDWR|OCEXEC);
-	if(cursorfd < 0)
-		drawerror(display, "einit: can't open cursor\n");
 	if(keys&Ekeyboard){
-		snprint(buf, sizeof buf, "%s/cons", display->devdir);
-		fd = open(buf, OREAD);
-		if(fd < 0)
-			drawerror(display, "events: can't open console");
-		snprint(buf, sizeof buf, "%s/consctl", display->devdir);
-		ctl = open("/dev/consctl", OWRITE|OCEXEC);
-		if(ctl < 0)
-			drawerror(display, "events: can't open consctl");
-		write(ctl, "rawon", 5);
 		for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
 			;
-		ekeyslave(fd);
+		eslave[Skeyboard].inuse = 1;
+		if(nslave <= Skeyboard)
+			nslave = Skeyboard+1;
 	}
 	if(keys&Emouse){
-		estart(Emouse, mousefd, 1+4*12);
 		for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
 			;
+		eslave[Smouse].inuse = 1;
+		if(nslave <= Smouse)
+			nslave = Smouse+1;
 	}
 }
 
-static void
-extract(void)
+static Ebuf*
+newebuf(Slave *s, int n)
 {
-	Slave *s;
 	Ebuf *eb;
-	int i, n;
-	uchar ebuf[EMAXMSG+1];
+	
+	eb = malloc(sizeof(*eb) - sizeof(eb->u.buf) + n);
+	if(eb == nil)
+		drawerror(display, "events: out of memory");
+	eb->n = n;
+	eb->next = 0;
+	if(s->head)
+		s->tail = s->tail->next = eb;
+	else
+		s->head = s->tail = eb;
+	return eb;
+}
 
-	/* avoid generating a message if there's nothing to show. */
-	/* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
-	/* also: make sure we don't interfere if we're multiprocessing the display */
+static Muxrpc*
+startrpc(int type)
+{
+	uchar buf[100];
+	Wsysmsg w;
+	
+	w.type = type;
+	convW2M(&w, buf, sizeof buf);
+	return muxrpcstart(display->mux, buf);
+}
+
+static int
+finishrpc(Muxrpc *r, Wsysmsg *w)
+{
+	uchar *p;
+	int n;
+	
+	if((p = muxrpccanfinish(r)) == nil)
+		return 0;
+	GET(p, n);
+	convM2W(p, n, w);
+	free(p);
+	return 1;
+}
+
+static int
+extract(int canblock)
+{
+	Ebuf *eb;
+	int i, n, max;
+	fd_set rset, wset, xset;
+	struct timeval tv, *timeout;
+	Wsysmsg w;
+	vlong t0;
+
+	/*
+	 * Flush draw buffer before waiting for responses.
+	 * Avoid doing so if buffer is empty.
+	 * Also make sure that we don't interfere with app-specific locking.
+	 */
 	if(display->locking){
-		/* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
+		/* 
+		 * if locking is being done by program, 
+		 * this means it can't depend on automatic 
+		 * flush in emouse() etc.
+		 */
 		if(canqlock(&display->qlock)){
 			if(display->bufp > display->buf)
 				flushimage(display, 1);
@@ -272,128 +253,130 @@ extract(void)
 	}else
 		if(display->bufp > display->buf)
 			flushimage(display, 1);
-loop:
-	if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
-	|| ebuf[0] >= MAXSLAVE)
-		drawerror(display, "eof on event pipe");
-	if(n == 0)
-		goto loop;
-	i = ebuf[0];
-	if(i >= nslave || n <= 1)
-		drawerror(display, "events: protocol error: short read");
-	s = &eslave[i];
-	if(i == Stimer){
-		s->head = (Ebuf *)1;
-		return;
+
+	/*
+	 * Set up for select.
+	 */
+	FD_ZERO(&rset);
+	FD_ZERO(&wset);
+	FD_ZERO(&xset);
+	max = -1;
+	timeout = nil;
+	for(i=0; i<nslave; i++){
+		if(!eslave[i].inuse)
+			continue;
+		if(i == Smouse){
+			if(eslave[i].rpc == nil)
+				eslave[i].rpc = startrpc(Trdmouse);
+			if(eslave[i].rpc){
+				FD_SET(display->srvfd, &rset);
+				FD_SET(display->srvfd, &xset);
+				if(display->srvfd > max)
+					max = display->srvfd;
+			}
+		}else if(i == Skeyboard){
+			if(eslave[i].rpc == nil)
+				eslave[i].rpc = startrpc(Trdkbd);
+			if(eslave[i].rpc){
+				FD_SET(display->srvfd, &rset);
+				FD_SET(display->srvfd, &xset);
+				if(display->srvfd > max)
+					max = display->srvfd;
+			}
+		}else if(i == Stimer){
+			t0 = nsec();
+			if(t0-eslave[i].nexttick <= 0){
+				tv.tv_sec = 0;
+				tv.tv_usec = 0;
+			}else{
+				tv.tv_sec = (t0-eslave[i].nexttick)/1000000000;
+				tv.tv_usec = (t0-eslave[i].nexttick)%1000000000 / 1000;
+			}
+			timeout = &tv;
+		}else{
+			FD_SET(eslave[i].fd, &rset);
+			FD_SET(eslave[i].fd, &xset);
+			if(eslave[i].fd > max)
+				max = eslave[i].fd;
+		}
 	}
-	if(i == Skeyboard && n != 3)
-		drawerror(display, "events: protocol error: keyboard");
-	if(i == Smouse){
-		if(n < 1+1+2*12)
-			drawerror(display, "events: protocol error: mouse");
-		if(ebuf[1] == 'r')
-			eresized(1);
-		/* squash extraneous mouse events */
-		if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){
-			memmove(eb->buf, &ebuf[1], n - 1);
-			return;
+	
+	if(!canblock){
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+		timeout = &tv;
+	}
+
+	if(select(max+1, &rset, &wset, &xset, timeout) < 0)
+		drawerror(display, "select failure");
+
+	/*
+	 * Look to see what can proceed.
+	 */
+	n = 0;
+	for(i=0; i<nslave; i++){
+		if(!eslave[i].inuse)
+			continue;
+		if(i == Smouse){
+			if(finishrpc(eslave[i].rpc, &w)){
+				eslave[i].rpc = nil;
+				eb = newebuf(&eslave[i], sizeof(Mouse));
+				eb->u.mouse = w.mouse;
+				if(w.resized)
+					eresized(1);
+				n++;
+			}
+		}else if(i == Skeyboard){
+			if(finishrpc(eslave[i].rpc, &w)){
+				eslave[i].rpc = nil;
+				eb = newebuf(&eslave[i], sizeof(Rune)+2);	/* +8: alignment */
+				eb->u.rune = w.rune;
+				n++;
+			}
+		}else if(i == Stimer){
+			t0 = nsec();
+			while(t0-eslave[i].nexttick > 0){
+				eslave[i].nexttick += eslave[i].n*1000LL;
+				eslave[i].head = (Ebuf*)1;
+				n++;
+			}
+		}else{
+			if(FD_ISSET(eslave[i].fd, &rset)){
+				eb = newebuf(&eslave[i], eslave[i].n);
+				eb->n = read(eslave[i].fd, eb->u.buf, eslave[i].n);
+				n++;
+			}
 		}
 	}
-	/* try to save space by only allocating as much buffer as we need */
-	eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1);
-	if(eb == 0)
-		drawerror(display, "events: protocol error 4");
-	eb->n = n - 1;
-	memmove(eb->buf, &ebuf[1], n - 1);
-	eb->next = 0;
-	if(s->head)
-		s->tail = s->tail->next = eb;
-	else
-		s->head = s->tail = eb;
+	return n;
 }
 
 static int
-eforkslave(ulong key)
+newkey(ulong key)
 {
-	int i, pid;
+	int i;
 
 	for(i=0; i<MAXSLAVE; i++)
-		if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){
+		if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){
 			if(nslave <= i)
 				nslave = i + 1;
-			/*
-			 * share the file descriptors so the last child
-			 * out closes all connections to the window server.
-			 */
-			switch(pid = rfork(RFPROC)){
-			case 0:
-				return MAXSLAVE+i;
-			case -1:
-				fprint(2, "events: fork error\n");
-				exits("fork");
-			}
-			eslave[i].pid = pid;
-			eslave[i].head = eslave[i].tail = 0;
+			eslave[i].inuse = 1;
 			return i;
 		}
 	drawerror(display, "events: bad slave assignment");
 	return 0;
 }
 
-static int
-enote(void *v, char *s)
-{
-	char t[1];
-	int i, pid;
-
-	USED(v, s);
-	pid = getpid();
-	if(pid != parentpid){
-		for(i=0; i<nslave; i++){
-			if(pid == eslave[i].pid){
-				t[0] = MAXSLAVE;
-				write(epipe[1], t, 1);
-				break;
-			}
-		}
-		return 0;
-	}
-	close(epipe[0]);
-	epipe[0] = -1;
-	close(epipe[1]);
-	epipe[1] = -1;
-	for(i=0; i<nslave; i++){
-		if(pid == eslave[i].pid)
-			continue;	/* don't kill myself */
-		postnote(PNPROC, eslave[i].pid, "die");
-	}
-	return 0;
-}
-
-static void
-ekill(void)
-{
-	enote(0, 0);
-}
-
 Mouse
 emouse(void)
 {
 	Mouse m;
 	Ebuf *eb;
-	static but[2];
-	int b;
 
 	if(Smouse < 0)
 		drawerror(display, "events: mouse not initialized");
 	eb = ebread(&eslave[Smouse]);
-	m.xy.x = atoi((char*)eb->buf+1+0*12);
-	m.xy.y = atoi((char*)eb->buf+1+1*12);
-	b = atoi((char*)eb->buf+1+2*12);
-	m.buttons = b&7;
-	m.msec = atoi((char*)eb->buf+1+3*12);
-	if (logfid)
-		fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy);
+	m = eb->u.mouse;
 	free(eb);
 	return m;
 }
@@ -407,7 +390,7 @@ ekbd(void)
 	if(Skeyboard < 0)
 		drawerror(display, "events: keyboard not initialzed");
 	eb = ebread(&eslave[Skeyboard]);
-	c = eb->buf[0] + (eb->buf[1]<<8);
+	c = eb->u.rune;
 	free(eb);
 	return c;
 }
@@ -415,56 +398,25 @@ ekbd(void)
 void
 emoveto(Point pt)
 {
-	char buf[2*12+2];
-	int n;
-
-	n = sprint(buf, "m%d %d", pt.x, pt.y);
-	write(mousefd, buf, n);
+	_displaymoveto(display, pt);
 }
 
 void
 esetcursor(Cursor *c)
 {
-	uchar curs[2*4+2*2*16];
-
-	if(c == 0)
-		write(cursorfd, curs, 0);
-	else{
-		BPLONG(curs+0*4, c->offset.x);
-		BPLONG(curs+1*4, c->offset.y);
-		memmove(curs+2*4, c->clr, 2*2*16);
-		write(cursorfd, curs, sizeof curs);
-	}
+	_displaycursor(display, c);
 }
 
 int
 ereadmouse(Mouse *m)
 {
-	int n;
-	char buf[128];
+	int resized;
 
-	do{
-		n = read(mousefd, buf, sizeof(buf));
-		if(n < 0)	/* probably interrupted */
-			return -1;
-		n = eatomouse(m, buf, n);
-	}while(n == 0);
-	return n;
-}
-
-int
-eatomouse(Mouse *m, char *buf, int n)
-{
-	if(n != 1+4*12){
-		werrstr("atomouse: bad count");
+	resized = 0;
+	if(_displayrdmouse(display, m, &resized) < 0)
 		return -1;
-	}
-
-	if(buf[0] == 'r')
+	if(resized)
 		eresized(1);
-	m->xy.x = atoi(buf+1+0*12);
-	m->xy.y = atoi(buf+1+1*12);
-	m->buttons = atoi(buf+1+2*12);
-	m->msec = atoi(buf+1+3*12);
-	return n;
+	return 1;
 }
+
blob - f1c981dbd0bf4ba060d1f4e4faf334642d308008
blob + a4b8100afc5145b46fc61d2689ccfe76b8b9eff9
--- src/libdraw/mkfile
+++ src/libdraw/mkfile
@@ -23,6 +23,7 @@ OFILES=\
 	egetrect.$O\
 	ellipse.$O\
 	emenuhit.$O\
+	event.$O\
 	font.$O\
 	freesubfont.$O\
 	getdefont.$O\
blob - e8136177a0c574f4696660e484fbfafb71b1581e
blob + d9632503dc848773843c31b8acb6d03ce7f96128
--- src/libdraw/wsys.c
+++ src/libdraw/wsys.c
@@ -22,3 +22,9 @@ bouncemouse(Mouse *m)
 	_displaybouncemouse(display, m);
 }
 
+void
+drawresizewindow(Rectangle r)
+{
+	_displayresize(display, r);
+}
+