tevent - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 150f88023b1fd3aa82fd5213367bc1f091715be6
 (DIR) parent e0ef95dce18a85730c5d9d596a26271ac43f9958
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sun, 25 Jun 2006 21:04:07 +0000
       
       event
       
       Diffstat:
         D src/libdraw/devdraw.c               |    1608 ------------------------------
         M src/libdraw/drawclient.c            |      61 +++++++++++++++++++++++--------
         M src/libdraw/drawfcall.c             |      18 ++----------------
         M src/libdraw/event.c                 |     482 ++++++++++++++-----------------
         M src/libdraw/mkfile                  |       1 +
         M src/libdraw/wsys.c                  |       6 ++++++
       
       6 files changed, 272 insertions(+), 1904 deletions(-)
       ---
 (DIR) diff --git a/src/libdraw/devdraw.c b/src/libdraw/devdraw.c
       t@@ -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;
       -}
       -
       -
 (DIR) diff --git a/src/libdraw/drawclient.c b/src/libdraw/drawclient.c
       t@@ -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>
       t@@ -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)
       t@@ -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];
       t@@ -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;
       t@@ -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)
        {
       t@@ -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){
       t@@ -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)
        {
       t@@ -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);
        }
        
       t@@ -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;
       +}
       +
 (DIR) diff --git a/src/libdraw/drawfcall.c b/src/libdraw/drawfcall.c
       t@@ -5,25 +5,11 @@
        #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);
        }
        
 (DIR) diff --git a/src/libdraw/event.c b/src/libdraw/event.c
       t@@ -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)
       t@@ -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;
        }
       t@@ -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;
        }
       t@@ -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
       t@@ -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;
       +}
       +
       +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;
       +}
        
       -        /* 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 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);
       t@@ -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(!canblock){
       +                tv.tv_sec = 0;
       +                tv.tv_usec = 0;
       +                timeout = &tv;
                }
       -        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(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;
        }
       t@@ -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;
        }
       t@@ -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];
       -
       -        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 resized;
        
       -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;
        }
       +
 (DIR) diff --git a/src/libdraw/mkfile b/src/libdraw/mkfile
       t@@ -23,6 +23,7 @@ OFILES=\
                egetrect.$O\
                ellipse.$O\
                emenuhit.$O\
       +        event.$O\
                font.$O\
                freesubfont.$O\
                getdefont.$O\
 (DIR) diff --git a/src/libdraw/wsys.c b/src/libdraw/wsys.c
       t@@ -22,3 +22,9 @@ bouncemouse(Mouse *m)
                _displaybouncemouse(display, m);
        }
        
       +void
       +drawresizewindow(Rectangle r)
       +{
       +        _displayresize(display, r);
       +}
       +