aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-06-25 21:04:07 +0000
committerrsc <devnull@localhost>2006-06-25 21:04:07 +0000
commit150f88023b1fd3aa82fd5213367bc1f091715be6 (patch)
tree342833355368e2527d79d3b24164e3174311cbfc /src/libdraw
parente0ef95dce18a85730c5d9d596a26271ac43f9958 (diff)
downloadplan9port-150f88023b1fd3aa82fd5213367bc1f091715be6.tar.gz
plan9port-150f88023b1fd3aa82fd5213367bc1f091715be6.tar.bz2
plan9port-150f88023b1fd3aa82fd5213367bc1f091715be6.zip
event
Diffstat (limited to 'src/libdraw')
-rw-r--r--src/libdraw/devdraw.c1608
-rw-r--r--src/libdraw/drawclient.c61
-rw-r--r--src/libdraw/drawfcall.c18
-rw-r--r--src/libdraw/event.c482
-rw-r--r--src/libdraw/mkfile1
-rw-r--r--src/libdraw/wsys.c6
6 files changed, 272 insertions, 1904 deletions
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 <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;
-}
-
-
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 <u.h>
+#include <sys/select.h>
#include <libc.h>
#include <draw.h>
#include <mouse.h>
@@ -12,8 +13,10 @@ int chattydrawclient;
static int drawgettag(Mux *mux, void *vmsg);
static void* drawrecv(Mux *mux);
+static void* drawnbrecv(Mux *mux);
static int drawsend(Mux *mux, void *vmsg);
static int drawsettag(Mux *mux, void *vmsg, uint tag);
+static int canreadfd(int);
int
_displayconnect(Display *d)
@@ -35,8 +38,8 @@ _displayconnect(Display *d)
dup(p[1], 0);
dup(p[1], 1);
/* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
- execl("drawsrv", "drawsrv", nil);
- sysfatal("exec drawsrv: %r");
+ execl("devdraw", "devdraw", nil);
+ sysfatal("exec devdraw: %r");
}
close(p[1]);
d->srvfd = p[0];
@@ -53,6 +56,7 @@ _displaymux(Display *d)
d->mux->maxtag = 255;
d->mux->send = drawsend;
d->mux->recv = drawrecv;
+ d->mux->nbrecv = drawnbrecv;
d->mux->gettag = drawgettag;
d->mux->settag = drawsettag;
d->mux->aux = d;
@@ -61,9 +65,6 @@ _displaymux(Display *d)
return 0;
}
-#define GET(p, x) \
- ((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3])))
-
static int
drawsend(Mux *mux, void *vmsg)
{
@@ -78,17 +79,17 @@ drawsend(Mux *mux, void *vmsg)
}
static void*
-drawrecv(Mux *mux)
+_drawrecv(Mux *mux, int nb)
{
int n;
uchar buf[4], *p;
Display *d;
-
+
d = mux->aux;
- if((n=readn(d->srvfd, buf, 4)) != 4){
-fprint(2, "readn 4 got %d: %r\n", n);
+ if(nb && !canreadfd(d->srvfd))
+ return nil;
+ if((n=readn(d->srvfd, buf, 4)) != 4)
return nil;
- }
GET(buf, n);
p = malloc(n);
if(p == nil){
@@ -96,13 +97,23 @@ fprint(2, "readn 4 got %d: %r\n", n);
return nil;
}
memmove(p, buf, 4);
- if(readn(d->srvfd, p+4, n-4) != n-4){
-fprint(2, "short readn\n");
+ if(readn(d->srvfd, p+4, n-4) != n-4)
return nil;
- }
return p;
}
+static void*
+drawrecv(Mux *mux)
+{
+ return _drawrecv(mux, 0);
+}
+
+static void*
+drawnbrecv(Mux *mux)
+{
+ return _drawrecv(mux, 1);
+}
+
static int
drawgettag(Mux *mux, void *vmsg)
{
@@ -186,8 +197,8 @@ _displayinit(Display *d, char *label, char *winsize)
Wsysmsg tx, rx;
tx.type = Tinit;
- tx.label = "";
- tx.winsize = "";
+ tx.label = label;
+ tx.winsize = winsize;
return displayrpc(d, &tx, &rx, nil);
}
@@ -334,3 +345,23 @@ _displayresize(Display *d, Rectangle r)
return displayrpc(d, &tx, &rx, nil);
}
+static int
+canreadfd(int fd)
+{
+ fd_set rs, ws, xs;
+ struct timeval tv;
+
+ FD_ZERO(&rs);
+ FD_ZERO(&ws);
+ FD_ZERO(&xs);
+ FD_SET(fd, &rs);
+ FD_SET(fd, &xs);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
+ return 0;
+ if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
+ return 1;
+ return 0;
+}
+
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 <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);
}
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 <draw.h>
#include <cursor.h>
#include <event.h>
+#include <mux.h>
+#include <drawfcall.h>
+typedef struct Slave Slave;
+typedef struct Ebuf Ebuf;
+struct Slave
+{
+ int inuse;
+ Ebuf *head; /* queue of messages for this descriptor */
+ Ebuf *tail;
+ int (*fn)(int, Event*, uchar*, int);
+ Muxrpc *rpc;
+ vlong nexttick;
+ int fd;
+ int n;
+};
+struct Ebuf
+{
+ Ebuf *next;
+ int n; /* number of bytes in buf */
+ union {
+ uchar buf[EMAXMSG];
+ Rune rune;
+ Mouse mouse;
+ } u;
+};
+
+static Slave eslave[MAXSLAVE];
static int Skeyboard = -1;
static int Smouse = -1;
static int Stimer = -1;
-static int logfid;
static int nslave;
-static int parentpid;
-static int epipe[2];
-static int eforkslave(ulong);
-static void extract(void);
-static void ekill(void);
-static int enote(void *, char *);
-static int mousefd;
-static int cursorfd;
+static int newkey(ulong);
+static int extract(int canblock);
static
Ebuf*
ebread(Slave *s)
{
Ebuf *eb;
- Dir *d;
- ulong l;
- for(;;){
- d = dirfstat(epipe[0]);
- if(d == nil)
- drawerror(display, "events: eread stat error");
- l = d->length;
- free(d);
- if(s->head && l==0)
- break;
- extract();
- }
+ while(!s->head)
+ extract(1);
eb = s->head;
s->head = s->head->next;
if(s->head == 0)
@@ -75,14 +85,14 @@ eread(ulong keys, Event *e)
eb = ebread(&eslave[i]);
e->n = eb->n;
if(eslave[i].fn)
- id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
+ id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n);
else
- memmove(e->data, eb->buf, eb->n);
+ memmove(e->data, eb->u.buf, eb->n);
free(eb);
}
return id;
}
- extract();
+ extract(0);
}
return 0;
}
@@ -106,22 +116,14 @@ ecankbd(void)
int
ecanread(ulong keys)
{
- Dir *d;
int i;
- ulong l;
for(;;){
for(i=0; i<nslave; i++)
if((keys & (1<<i)) && eslave[i].head)
return 1;
- d = dirfstat(epipe[0]);
- if(d == nil)
- drawerror(display, "events: ecanread stat error");
- l = d->length;
- free(d);
- if(l == 0)
+ if(!extract(0))
return 0;
- extract();
}
return -1;
}
@@ -129,26 +131,17 @@ ecanread(ulong keys)
ulong
estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
{
- char buf[EMAXMSG+1];
- int i, r;
+ int i;
if(fd < 0)
drawerror(display, "events: bad file descriptor");
if(n <= 0 || n > EMAXMSG)
n = EMAXMSG;
- i = eforkslave(key);
- if(i < MAXSLAVE){
- eslave[i].fn = fn;
- return 1<<i;
- }
- buf[0] = i - MAXSLAVE;
- while((r = read(fd, buf+1, n))>0)
- if(write(epipe[1], buf, r+1)!=r+1)
- break;
- buf[0] = MAXSLAVE;
- write(epipe[1], buf, 1);
- _exits(0);
- return 0;
+ i = newkey(key);
+ eslave[i].fn = fn;
+ eslave[i].fd = fd;
+ eslave[i].n = n;
+ return 1<<i;
}
ulong
@@ -160,110 +153,98 @@ estart(ulong key, int fd, int n)
ulong
etimer(ulong key, int n)
{
- char t[2];
-
if(Stimer != -1)
drawerror(display, "events: timer started twice");
- Stimer = eforkslave(key);
- if(Stimer < MAXSLAVE)
- return 1<<Stimer;
+ Stimer = newkey(key);
if(n <= 0)
n = 1000;
- t[0] = t[1] = Stimer - MAXSLAVE;
- do
- sleep(n);
- while(write(epipe[1], t, 2) == 2);
- t[0] = MAXSLAVE;
- write(epipe[1], t, 1);
- _exits(0);
- return 0;
-}
-
-static void
-ekeyslave(int fd)
-{
- Rune r;
- char t[3], k[10];
- int kr, kn, w;
-
- if(eforkslave(Ekeyboard) < MAXSLAVE)
- return;
- kn = 0;
- t[0] = Skeyboard;
- for(;;){
- while(!fullrune(k, kn)){
- kr = read(fd, k+kn, sizeof k - kn);
- if(kr <= 0)
- goto breakout;
- kn += kr;
- }
- w = chartorune(&r, k);
- kn -= w;
- memmove(k, &k[w], kn);
- t[1] = r;
- t[2] = r>>8;
- if(write(epipe[1], t, 3) != 3)
- break;
- }
-breakout:;
- t[0] = MAXSLAVE;
- write(epipe[1], t, 1);
- _exits(0);
+ eslave[Stimer].n = n;
+ eslave[Stimer].nexttick = nsec()+n*1000LL;
+ return 1<<Stimer;
}
void
einit(ulong keys)
{
- int ctl, fd;
- char buf[256];
-
- parentpid = getpid();
- if(pipe(epipe) < 0)
- drawerror(display, "events: einit pipe");
- atexit(ekill);
- atnotify(enote, 1);
- snprint(buf, sizeof buf, "%s/mouse", display->devdir);
- mousefd = open(buf, ORDWR|OCEXEC);
- if(mousefd < 0)
- drawerror(display, "einit: can't open mouse\n");
- snprint(buf, sizeof buf, "%s/cursor", display->devdir);
- cursorfd = open(buf, ORDWR|OCEXEC);
- if(cursorfd < 0)
- drawerror(display, "einit: can't open cursor\n");
if(keys&Ekeyboard){
- snprint(buf, sizeof buf, "%s/cons", display->devdir);
- fd = open(buf, OREAD);
- if(fd < 0)
- drawerror(display, "events: can't open console");
- snprint(buf, sizeof buf, "%s/consctl", display->devdir);
- ctl = open("/dev/consctl", OWRITE|OCEXEC);
- if(ctl < 0)
- drawerror(display, "events: can't open consctl");
- write(ctl, "rawon", 5);
for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
;
- ekeyslave(fd);
+ eslave[Skeyboard].inuse = 1;
+ if(nslave <= Skeyboard)
+ nslave = Skeyboard+1;
}
if(keys&Emouse){
- estart(Emouse, mousefd, 1+4*12);
for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
;
+ eslave[Smouse].inuse = 1;
+ if(nslave <= Smouse)
+ nslave = Smouse+1;
}
}
-static void
-extract(void)
+static Ebuf*
+newebuf(Slave *s, int n)
{
- Slave *s;
Ebuf *eb;
- int i, n;
- uchar ebuf[EMAXMSG+1];
+
+ eb = malloc(sizeof(*eb) - sizeof(eb->u.buf) + n);
+ if(eb == nil)
+ drawerror(display, "events: out of memory");
+ eb->n = n;
+ eb->next = 0;
+ if(s->head)
+ s->tail = s->tail->next = eb;
+ else
+ s->head = s->tail = eb;
+ return eb;
+}
+
+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; 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;
}
@@ -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);
+}
+