From 150f88023b1fd3aa82fd5213367bc1f091715be6 Mon Sep 17 00:00:00 2001 From: rsc Date: Sun, 25 Jun 2006 21:04:07 +0000 Subject: event --- src/libdraw/devdraw.c | 1608 ---------------------------------------------- src/libdraw/drawclient.c | 61 +- src/libdraw/drawfcall.c | 18 +- src/libdraw/event.c | 482 +++++++------- src/libdraw/mkfile | 1 + src/libdraw/wsys.c | 6 + 6 files changed, 272 insertions(+), 1904 deletions(-) delete mode 100644 src/libdraw/devdraw.c (limited to 'src/libdraw') diff --git a/src/libdraw/devdraw.c b/src/libdraw/devdraw.c deleted file mode 100644 index f4a3fd96..00000000 --- a/src/libdraw/devdraw.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* - * /dev/draw simulator -- handles the messages prepared by the draw library. - * Includes all the memlayer code even though most programs don't use it. - * This whole approach is overkill, but cpu is cheap and it keeps things simple. - */ - -#include -#include -#include -#include -#include - -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*2layer; - 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(; namename, 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; ifromname){ /* 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(; namename, 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 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; jlayer == 0){ - err = "images are not windows"; - free(lp); - goto error; - } - for(j=1; jlayer->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; jlayer->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; -} - - diff --git a/src/libdraw/drawclient.c b/src/libdraw/drawclient.c index ae8719a9..8fe1b79f 100644 --- a/src/libdraw/drawclient.c +++ b/src/libdraw/drawclient.c @@ -1,6 +1,7 @@ /* Copyright (c) 2006 Russ Cox */ #include +#include #include #include #include @@ -12,8 +13,10 @@ int chattydrawclient; static int drawgettag(Mux *mux, void *vmsg); static void* drawrecv(Mux *mux); +static void* drawnbrecv(Mux *mux); static int drawsend(Mux *mux, void *vmsg); static int drawsettag(Mux *mux, void *vmsg, uint tag); +static int canreadfd(int); int _displayconnect(Display *d) @@ -35,8 +38,8 @@ _displayconnect(Display *d) dup(p[1], 0); dup(p[1], 1); /* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */ - execl("drawsrv", "drawsrv", nil); - sysfatal("exec drawsrv: %r"); + execl("devdraw", "devdraw", nil); + sysfatal("exec devdraw: %r"); } close(p[1]); d->srvfd = p[0]; @@ -53,6 +56,7 @@ _displaymux(Display *d) d->mux->maxtag = 255; d->mux->send = drawsend; d->mux->recv = drawrecv; + d->mux->nbrecv = drawnbrecv; d->mux->gettag = drawgettag; d->mux->settag = drawsettag; d->mux->aux = d; @@ -61,9 +65,6 @@ _displaymux(Display *d) return 0; } -#define GET(p, x) \ - ((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3]))) - static int drawsend(Mux *mux, void *vmsg) { @@ -78,17 +79,17 @@ drawsend(Mux *mux, void *vmsg) } static void* -drawrecv(Mux *mux) +_drawrecv(Mux *mux, int nb) { int n; uchar buf[4], *p; Display *d; - + d = mux->aux; - if((n=readn(d->srvfd, buf, 4)) != 4){ -fprint(2, "readn 4 got %d: %r\n", n); + if(nb && !canreadfd(d->srvfd)) + return nil; + if((n=readn(d->srvfd, buf, 4)) != 4) return nil; - } GET(buf, n); p = malloc(n); if(p == nil){ @@ -96,13 +97,23 @@ fprint(2, "readn 4 got %d: %r\n", n); return nil; } memmove(p, buf, 4); - if(readn(d->srvfd, p+4, n-4) != n-4){ -fprint(2, "short readn\n"); + if(readn(d->srvfd, p+4, n-4) != n-4) return nil; - } return p; } +static void* +drawrecv(Mux *mux) +{ + return _drawrecv(mux, 0); +} + +static void* +drawnbrecv(Mux *mux) +{ + return _drawrecv(mux, 1); +} + static int drawgettag(Mux *mux, void *vmsg) { @@ -186,8 +197,8 @@ _displayinit(Display *d, char *label, char *winsize) Wsysmsg tx, rx; tx.type = Tinit; - tx.label = ""; - tx.winsize = ""; + tx.label = label; + tx.winsize = winsize; return displayrpc(d, &tx, &rx, nil); } @@ -334,3 +345,23 @@ _displayresize(Display *d, Rectangle r) return displayrpc(d, &tx, &rx, nil); } +static int +canreadfd(int fd) +{ + fd_set rs, ws, xs; + struct timeval tv; + + FD_ZERO(&rs); + FD_ZERO(&ws); + FD_ZERO(&xs); + FD_SET(fd, &rs); + FD_SET(fd, &xs); + tv.tv_sec = 0; + tv.tv_usec = 0; + if(select(fd+1, &rs, &ws, &xs, &tv) < 0) + return 0; + if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs)) + return 1; + return 0; +} + diff --git a/src/libdraw/drawfcall.c b/src/libdraw/drawfcall.c index 09a54f91..e2d3c642 100644 --- a/src/libdraw/drawfcall.c +++ b/src/libdraw/drawfcall.c @@ -5,25 +5,11 @@ #include #include -#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); } diff --git a/src/libdraw/event.c b/src/libdraw/event.c index 6e4d7f5c..1da3fb39 100644 --- a/src/libdraw/event.c +++ b/src/libdraw/event.c @@ -4,42 +4,52 @@ #include #include #include +#include +#include +typedef struct Slave Slave; +typedef struct Ebuf Ebuf; +struct Slave +{ + int inuse; + Ebuf *head; /* queue of messages for this descriptor */ + Ebuf *tail; + int (*fn)(int, Event*, uchar*, int); + Muxrpc *rpc; + vlong nexttick; + int fd; + int n; +}; +struct Ebuf +{ + Ebuf *next; + int n; /* number of bytes in buf */ + union { + uchar buf[EMAXMSG]; + Rune rune; + Mouse mouse; + } u; +}; + +static Slave eslave[MAXSLAVE]; static int Skeyboard = -1; static int Smouse = -1; static int Stimer = -1; -static int logfid; static int nslave; -static int parentpid; -static int epipe[2]; -static int eforkslave(ulong); -static void extract(void); -static void ekill(void); -static int enote(void *, char *); -static int mousefd; -static int cursorfd; +static int newkey(ulong); +static int extract(int canblock); static Ebuf* ebread(Slave *s) { Ebuf *eb; - Dir *d; - ulong l; - for(;;){ - d = dirfstat(epipe[0]); - if(d == nil) - drawerror(display, "events: eread stat error"); - l = d->length; - free(d); - if(s->head && l==0) - break; - extract(); - } + while(!s->head) + extract(1); eb = s->head; s->head = s->head->next; if(s->head == 0) @@ -75,14 +85,14 @@ eread(ulong keys, Event *e) eb = ebread(&eslave[i]); e->n = eb->n; if(eslave[i].fn) - id = (*eslave[i].fn)(id, e, eb->buf, eb->n); + id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n); else - memmove(e->data, eb->buf, eb->n); + memmove(e->data, eb->u.buf, eb->n); free(eb); } return id; } - extract(); + extract(0); } return 0; } @@ -106,22 +116,14 @@ ecankbd(void) int ecanread(ulong keys) { - Dir *d; int i; - ulong l; for(;;){ for(i=0; ilength; - free(d); - if(l == 0) + if(!extract(0)) return 0; - extract(); } return -1; } @@ -129,26 +131,17 @@ ecanread(ulong keys) ulong estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) { - char buf[EMAXMSG+1]; - int i, r; + int i; if(fd < 0) drawerror(display, "events: bad file descriptor"); if(n <= 0 || n > EMAXMSG) n = EMAXMSG; - i = eforkslave(key); - if(i < MAXSLAVE){ - eslave[i].fn = fn; - return 1<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<>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<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<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); @@ -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; isrvfd, &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; iu.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; ibuf+1+0*12); - m.xy.y = atoi((char*)eb->buf+1+1*12); - b = atoi((char*)eb->buf+1+2*12); - m.buttons = b&7; - m.msec = atoi((char*)eb->buf+1+3*12); - if (logfid) - fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy); + m = eb->u.mouse; free(eb); return m; } @@ -407,7 +390,7 @@ ekbd(void) if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); eb = ebread(&eslave[Skeyboard]); - c = eb->buf[0] + (eb->buf[1]<<8); + c = eb->u.rune; free(eb); return c; } @@ -415,56 +398,25 @@ ekbd(void) void emoveto(Point pt) { - char buf[2*12+2]; - int n; - - n = sprint(buf, "m%d %d", pt.x, pt.y); - write(mousefd, buf, n); + _displaymoveto(display, pt); } void esetcursor(Cursor *c) { - uchar curs[2*4+2*2*16]; - - if(c == 0) - write(cursorfd, curs, 0); - else{ - BPLONG(curs+0*4, c->offset.x); - BPLONG(curs+1*4, c->offset.y); - memmove(curs+2*4, c->clr, 2*2*16); - write(cursorfd, curs, sizeof curs); - } + _displaycursor(display, c); } int ereadmouse(Mouse *m) { - int n; - char buf[128]; - - 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; } + diff --git a/src/libdraw/mkfile b/src/libdraw/mkfile index f1c981db..a4b8100a 100644 --- a/src/libdraw/mkfile +++ b/src/libdraw/mkfile @@ -23,6 +23,7 @@ OFILES=\ egetrect.$O\ ellipse.$O\ emenuhit.$O\ + event.$O\ font.$O\ freesubfont.$O\ getdefont.$O\ diff --git a/src/libdraw/wsys.c b/src/libdraw/wsys.c index e8136177..d9632503 100644 --- a/src/libdraw/wsys.c +++ b/src/libdraw/wsys.c @@ -22,3 +22,9 @@ bouncemouse(Mouse *m) _displaybouncemouse(display, m); } +void +drawresizewindow(Rectangle r) +{ + _displayresize(display, r); +} + -- cgit v1.2.3