ref: 6ac9d2d939ba0a61aacc3c7772ee512c3b2d6b6a
parent: 1e84383ea66d572e979e1add131a2e5ed3cc757a
author: sirjofri <sirjofri@sirjofri.de>
date: Sun Jan 5 19:02:57 EST 2025
some working filesystem (rio "works", blocks all input, -D reports proper writes)
--- a/drawfs/fs.c
+++ b/drawfs/fs.c
@@ -11,6 +11,12 @@
/* see: /sys/src/9/port/devdraw.c */
+jmp_buf errjmp;
+#define waserror() setjmp(errjmp)
+#define error(MSG) { fprint(2, MSG); longjmp(errjmp, 1); }
+#define nexterror()
+#define poperror()
+
enum {
Qroot,
/* potential files like cons and mouse */
@@ -205,6 +211,8 @@
static char Ebadarg[] = "bad arguments";
static char Enodev[] = "no device";
static char Einuse[] = "device in use";
+static char Eisdir[] = "is directory";
+static char Ebadusefd[] = "inappropriate use of fd";
static void
dlock(void)
@@ -239,6 +247,13 @@
USED(p, pr, pg, pb);
}
+void
+setcolor(ulong p, ulong r, ulong g, ulong b)
+{
+ /* empty stub: only used for colormap */
+ USED(p, r, g, b);
+}
+
DImage*
allocdimage(Memimage *i)
{
@@ -259,6 +274,100 @@
}
void
+drawwakeall(void)
+{
+ Client *cl;
+ int i;
+
+ for (i = 0; i < sdraw.nclient; i++) {
+ cl = sdraw.client[i];
+ if (cl && (cl->refreshme || cl->refresh)) {
+ // TODO: wakeup?
+ //wakeup(&cl->refrend);
+ }
+ }
+}
+
+static void
+drawrefreshscreen(DImage *l, Client *client)
+{
+ while (l && l->dscreen)
+ l = l->fromname;
+ if (l && l->dscreen->owner != client)
+ l->dscreen->owner->refreshme = 1;
+}
+
+static void
+drawrefresh(Memimage*, Rectangle r, void *v)
+{
+ Refx *x;
+ DImage *d;
+ Client *c;
+ Refresh *ref;
+
+ if (!v)
+ 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 = malloc(sizeof(Refresh));
+ if (ref) {
+ ref->dimage = d;
+ ref->r = r;
+ ref->next = c->refresh;
+ c->refresh = ref;
+ }
+}
+
+void
+flushmemscreen(Rectangle)
+{
+ // stub
+ // TODO: send update message?
+}
+
+static void
+addflush(Rectangle r)
+{
+ /* comments see: /sys/src/9/port/devdraw.c:/^addflush */
+ int abb, ar, anbb;
+ Rectangle nbb;
+
+ if (!sdraw.softscreen || !screenimage || !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);
+
+ waste += anbb-abb - ar;
+ if (waste < 0)
+ waste = 0;
+
+ if (anbb <= 1024 || waste*2 < anbb || rectXrect(flushrect, r)) {
+ flushrect = nbb;
+ return;
+ }
+
+ if (flushrect.min.x < flushrect.max.x)
+ flushmemscreen(flushrect);
+ flushrect = r;
+ waste = 0;
+}
+
+void
drawaddname(Client *client, DImage *di, int n, char *str)
{
DName *name, *ename, *new, *t;
@@ -283,6 +392,16 @@
new->vers = ++sdraw.vers;
}
+void
+drawdelname(DName *name)
+{
+ int i;
+ free(name->name);
+ i = name-sdraw.name;
+ memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
+ sdraw.nname--;
+}
+
static DImage*
makescreenimage(void)
{
@@ -292,7 +411,7 @@
Rectangle r;
r = Rect(0, 0, 300, 200);
- chan = RGB24;
+ chan = XRGB32;
i = allocmemimage(r, chan);
if (!i)
@@ -339,6 +458,70 @@
return 1;
}
+DScreen*
+drawlookupdscreen(int id)
+{
+ DScreen *s;
+
+ s = dscreen;
+ while (s) {
+ if (s->id == id)
+ return s;
+ s = s->next;
+ }
+ return nil;
+}
+
+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;
+ }
+ werrstr(Enodrawscreen);
+ return nil;
+}
+
+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) {
+ if (next == this) {
+ ds->next = this->next;
+ goto Found;
+ }
+ ds = next;
+ }
+ sysfatal(Enodrawimage);
+
+Found:
+ if (this->dimage)
+ drawfreedimage(this->dimage);
+ if (this->dfill)
+ drawfreedimage(this->dfill);
+ free(this->screen);
+ free(this);
+}
+
DImage*
drawlookup(Client *client, int id, int checkname)
{
@@ -370,6 +553,16 @@
return cl;
}
+static int
+drawclientop(Client *cl)
+{
+ int op;
+
+ op = cl->op;
+ cl->op = SoverD;
+ return op;
+}
+
Client*
drawclientofpath(ulong path)
{
@@ -400,6 +593,175 @@
return i;
}
+Memscreen*
+drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
+{
+ Memscreen *s;
+ CScreen *c;
+
+ c = malloc(sizeof(CScreen));
+ if(dimage && dimage->image && dimage->image->chan == 0)
+ sysfatal("bad image %p in drawinstallscreen", dimage->image);
+
+ if(c == 0)
+ return 0;
+ if(d == 0){
+ d = malloc(sizeof(DScreen));
+ if(d == 0){
+ free(c);
+ return 0;
+ }
+ s = malloc(sizeof(Memscreen));
+ 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;
+}
+
+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) {
+ if (next == this) {
+ cs->next = this->next;
+ drawfreedscreen(this->dscreen);
+ free(this);
+ return;
+ }
+ cs = next;
+ }
+}
+
+void
+drawuninstall(Client *client, int id)
+{
+ DImage *d, *next;
+
+ d = client->dimage[id&HASHMASK];
+ if(d == 0)
+ error(Enodrawimage);
+ if(d->id == id){
+ client->dimage[id&HASHMASK] = d->next;
+ drawfreedimage(d);
+ return;
+ }
+ while((next = d->next) != nil){
+ if(next->id == id){
+ d->next = next->next;
+ drawfreedimage(next);
+ return;
+ }
+ d = next;
+ }
+ error(Enodrawimage);
+}
+
+void
+drawfreedimage(DImage *dimage)
+{
+ int i;
+ Memimage *l;
+ DScreen *ds;
+
+ dimage->ref--;
+ if (dimage->ref < 0)
+ fprint(2, "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;
+ if (ds) {
+ l = dimage->image;
+ if (screenimage && 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
+ freememimage(dimage->image);
+Return:
+ free(dimage->fchar);
+ free(dimage);
+}
+
+static void
+dstflush(int dstid, Memimage *dst, Rectangle r)
+{
+ Memlayer *l;
+
+ if (dstid == 0) {
+ combinerect(&flushrect, r);
+ return;
+ }
+ if (!screenimage || !dst || (l = dst->layer) == 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);
+}
+
+void
+drawflush(void)
+{
+ if (screenimage && flushrect.min.x < flushrect.max.x)
+ flushmemscreen(flushrect);
+ flushrect = Rect(10000, 10000, -10000, -10000);
+}
+
Client*
drawnewclient(void)
{
@@ -424,6 +786,7 @@
cl = mallocz(sizeof(Client), 1);
if (!cl)
return nil;
+ fprint(2, "new client: %d\n", i);
cl->slot = i;
cl->clientid = ++sdraw.clientid;
cl->op = SoverD;
@@ -612,6 +975,51 @@
}
static void
+fsclose(Fid *fid)
+{
+ Client *cl;
+ Refresh *r;
+ int i;
+ DImage *d, **dp;
+
+ if (QID(fid->qid) < Qcolormap)
+ return;
+
+ dlock();
+
+ cl = drawclient(fid->qid);
+ if (QID(fid->qid) == Qctl)
+ cl->busy = 0;
+ if (decref(&cl->r) == 0) {
+ while (r = cl->refresh) {
+ cl->refresh = r->next;
+ free(r);
+ }
+ /* free names */
+ for (i = 0; i < sdraw.nname; )
+ if (sdraw.name[i].client == cl)
+ drawdelname(sdraw.name+i);
+ else
+ i++;
+ while (cl->cscreen)
+ drawuninstallscreen(cl, cl->cscreen);
+ /* all screens are freed, so now we can free images */
+ dp = cl->dimage;
+ for (i = 0; i < NHASH; i++) {
+ while (d = *dp) {
+ *dp = d->next;
+ drawfreedimage(d);
+ }
+ dp++;
+ }
+ sdraw.client[cl->slot] = nil;
+ drawflush(); /* to erase visible, now dead windows */
+ free(cl);
+ }
+ dunlock();
+}
+
+static void
fsread(Req *r)
{
Qid q;
@@ -670,7 +1078,9 @@
} else {
di = drawlookup(cl, cl->infoid, 1);
if (!di) {
- respond(r, Enodrawimage);
+ //respond(r, Enodrawimage);
+ werrstr("!di : %s", Enodrawimage);
+ responderror(r);
goto Out;
}
i = di->image;
@@ -758,6 +1168,90 @@
dunlock();
}
+static void
+fswrite(Req *r)
+{
+ Client *cl;
+ char buf[128], *fields[4], *q;
+ int i, m, n, red, green, blue, x;
+ char *a;
+
+ if (r->fid->qid.type & QTDIR) {
+ respond(r, Eisdir);
+ return;
+ }
+ cl = drawclient(r->fid->qid);
+ dlock();
+
+ switch (QID(r->fid->qid)) {
+ case Qctl:
+ if (r->ifcall.count != 4) {
+ respond(r, "unknown draw control request");
+ return;
+ }
+ cl->infoid = BGLONG((uchar*)r->ifcall.data);
+ fprint(2, "new client: infoid = %d\n", cl->infoid);
+ break;
+
+ case Qcolormap:
+ a = r->ifcall.data;
+ m = n = r->ifcall.count;
+ r->ofcall.count = 0;
+ while (m > 0) {
+ x = m;
+ if (x > sizeof(buf) - 1)
+ x = sizeof(buf) - 1;
+ q = memccpy(buf, a, '\n', x);
+ if (q == 0)
+ break;
+ i = q-buf;
+ n += i;
+ a = (char*)a + i;
+ m -= i;
+ *q = 0;
+ if (tokenize(buf, fields, nelem(fields)) != 4) {
+ respond(r, Ebadarg);
+ goto Out;
+ }
+ i = strtoul(fields[0], 0, 0);
+ red = strtoul(fields[1], 0, 0);
+ green = strtoul(fields[2], 0, 0);
+ blue = strtoul(fields[3], 0, 0);
+ if (fields[3] == q) {
+ respond(r, Ebadarg);
+ goto Out;
+ }
+ if (red > 255 || green > 255 || blue > 255 || i < 0 || i > 255) {
+ respond(r, Ebadarg);
+ goto Out;
+ }
+ red |= red<<8;
+ red |= red<<16;
+ green |= green<<8;
+ green |= green<<16;
+ blue |= blue<<8;
+ blue |= blue<<16;
+ setcolor(i, red, green, blue);
+ }
+ respond(r, nil);
+ break;
+
+ case Qdata:
+ drawmesg(cl, r->ifcall.data, r->ifcall.count);
+ drawwakeall();
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+ break;
+
+ default:
+ respond(r, Ebadusefd);
+ }
+Out:
+ dunlock();
+ if (!r->responded)
+ respond(r, nil);
+}
+
static char*
fswalk(Fid *fid, char *name, Qid *qid)
{
@@ -847,7 +1341,9 @@
.walk1 = fswalk,
.stat = fsstat,
.open = fsopen,
+ .destroyfid = fsclose,
.read = fsread,
+ .write = fswrite,
};
static int
@@ -864,9 +1360,821 @@
return 1;
}
+Memimage*
+drawimage(Client *client, uchar *a)
+{
+ DImage *d;
+
+ d = drawlookup(client, BGLONG(a), 1);
+ if (!d) {
+ werrstr(Enodrawimage);
+ return nil;
+ }
+ return d->image;
+}
+
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);
+}
+
+void
+drawpoint(Point *p, uchar *a)
+{
+ p->x = BGLONG(a+0*4);
+ p->y = BGLONG(a+1*4);
+}
+
+Point
+drawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
+{
+ FChar *fc;
+ Rectangle r;
+ Point sp1;
+ static Memimage *tmp;
+
+ USED(rdst); // TODO: needed?
+
+ 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;
+
+ /* assume we have no hw images. /sys/src/9/port/devdraw.c:ishwimage */
+ memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
+
+ p.x += fc->width;
+ sp->x += fc->width;
+ return p;
+}
+
+uchar*
+drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
+{
+ int b, x;
+
+ if(p >= maxp)
+ error(Eshortdraw);
+ b = *p++;
+ x = b & 0x7F;
+ if(b & 0x80){
+ if(p+1 >= maxp)
+ error(Eshortdraw);
+ 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;
+}
+
+static void
+printmesg(char *fmt, uchar *a, int plsprnt)
+{
+ char buf[256];
+ char *p, *q;
+ int s;
+
+ if(1|| plsprnt==0){
+ SET(s,q,p);
+ USED(fmt, a, buf, p, q, s);
+ return;
+ }
+ q = buf;
+ *q++ = *a++;
+ for(p=fmt; *p; p++){
+ switch(*p){
+ case 'l':
+ q += sprint(q, " %ld", (long)BGLONG(a));
+ a += 4;
+ break;
+ case 'L':
+ q += sprint(q, " %.8lux", (ulong)BGLONG(a));
+ a += 4;
+ break;
+ case 'R':
+ q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
+ a += 16;
+ break;
+ case 'P':
+ q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
+ a += 8;
+ break;
+ case 'b':
+ q += sprint(q, " %d", *a++);
+ break;
+ case 's':
+ q += sprint(q, " %d", BGSHORT(a));
+ a += 2;
+ break;
+ case 'S':
+ q += sprint(q, " %.4ux", BGSHORT(a));
+ a += 2;
+ break;
+ case 'z':
+ q += sprint(q, " %.*q", (int)*a, (char*)(a+1));
+ a += 1 + *a;
+ break;
+ }
+ }
+ *q++ = '\n';
+ *q = 0;
+ fprint(2, "%.*s", (int)(q-buf), buf);
+}
+
+void
+drawmesg(Client *client, void *av, int n)
+{
+ int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
+ uchar *u, *a, refresh;
+ char *fmt;
+ ulong value, chan;
+ Rectangle r, clipr;
+ Point p, q, *pp, sp;
+ Memimage *i, *bg, *dst, *src, *mask;
+ Memimage *l, **lp;
+ Memscreen *scrn;
+ DImage *font, *ll, *di, *ddst, *dsrc;
+ DName *dn;
+ DScreen *dscrn;
+ FChar *fc;
+ Refx *refx;
+ CScreen *cs;
+ Refreshfn reffn;
+
+ a = av;
+ m = 0;
+ fmt = nil;
+ if(waserror()){
+ if(fmt) printmesg(fmt, a, 1);
+ /* iprint("error: %s\n", up->errstr); */
+ nexterror();
+ }
+ while((n-=m) > 0){
+ USED(fmt);
+ a += m;
+ switch(*a){
+ default:
+ error("bad draw command");
+ /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
+ case 'b':
+ printmesg(fmt="LLbLbRRL", a, 0);
+ m = 1+4+4+1+4+1+4*4+4*4+4;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ scrnid = BGLONG(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))
+ error(Eimageexists);
+ if(scrnid){
+ dscrn = drawlookupscreen(client, scrnid, &cs);
+ scrn = dscrn->screen;
+ if(repl || chan!=scrn->image->chan)
+ error("image parameters incompatible with screen");
+ reffn = nil;
+ switch(refresh){
+ case Refbackup:
+ break;
+ case Refnone:
+ reffn = memlnorefresh;
+ break;
+ case Refmesg:
+ reffn = drawrefresh;
+ break;
+ default:
+ error("unknown refresh method");
+ }
+ l = memlalloc(scrn, r, reffn, 0, value);
+ if(l == 0)
+ error(Edrawmem);
+ addflush(l->layer->screenr);
+ l->clipr = clipr;
+ rectclip(&l->clipr, r);
+ if(drawinstall(client, dstid, l, dscrn) == 0){
+ memldelete(l);
+ error(Edrawmem);
+ }
+ dscrn->ref++;
+ if(reffn){
+ refx = nil;
+ if(reffn == drawrefresh){
+ refx = malloc(sizeof(Refx));
+ if(refx == 0){
+ drawuninstall(client, dstid);
+ error(Edrawmem);
+ }
+ refx->client = client;
+ refx->dimage = drawlookup(client, dstid, 1);
+ }
+ memlsetrefresh(l, reffn, refx);
+ }
+ continue;
+ }
+ i = allocmemimage(r, chan);
+ if(i == 0)
+ error(Edrawmem);
+ if(repl)
+ i->flags |= Frepl;
+ i->clipr = clipr;
+ if(!repl)
+ rectclip(&i->clipr, r);
+ if(drawinstall(client, dstid, i, 0) == 0){
+ freememimage(i);
+ error(Edrawmem);
+ }
+ memfillcolor(i, value);
+ continue;
+
+ /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
+ case 'A':
+ printmesg(fmt="LLLb", a, 1);
+ m = 1+4+4+4+1;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ if(dstid == 0)
+ error(Ebadarg);
+ if(drawlookupdscreen(dstid))
+ error(Escreenexists);
+ ddst = drawlookup(client, BGLONG(a+5), 1);
+ dsrc = drawlookup(client, BGLONG(a+9), 1);
+ if(ddst==0 || dsrc==0)
+ error(Enodrawimage);
+ if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
+ error(Edrawmem);
+ continue;
+
+ /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
+ case 'c':
+ printmesg(fmt="LbR", a, 0);
+ m = 1+4+1+4*4;
+ if(n < m)
+ error(Eshortdraw);
+ ddst = drawlookup(client, BGLONG(a+1), 1);
+ if(ddst == nil)
+ error(Enodrawimage);
+ if(ddst->name)
+ error("cannot change repl/clipr of shared image");
+ 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':
+ printmesg(fmt="LLLRPP", a, 0);
+ m = 1+4+4+4+4*4+2*4+2*4;
+ if(n < m)
+ error(Eshortdraw);
+ dst = drawimage(client, a+1);
+ dstid = BGLONG(a+1);
+ src = drawimage(client, a+5);
+ mask = drawimage(client, a+9);
+ 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':
+ printmesg(fmt="b", a, 0);
+ m = 1+1;
+ if(n < m)
+ error(Eshortdraw);
+ 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':
+ printmesg(fmt="LLPlllPll", a, 0);
+ m = 1+4+4+2*4+4+4+4+2*4+2*4;
+ if(n < m)
+ error(Eshortdraw);
+ dst = drawimage(client, a+1);
+ dstid = BGLONG(a+1);
+ src = drawimage(client, a+5);
+ drawpoint(&p, a+9);
+ e0 = BGLONG(a+17);
+ e1 = BGLONG(a+21);
+ if(e0<0 || e1<0)
+ error("invalid ellipse semidiameter");
+ j = BGLONG(a+25);
+ if(j < 0)
+ error("negative ellipse thickness");
+ 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 & (1<<31)){
+ if((ox & (1<<30)) == 0)
+ ox &= ~(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':
+ printmesg(fmt="L", a, 1);
+ m = 1+4;
+ if(n < m)
+ error(Eshortdraw);
+ ll = drawlookup(client, BGLONG(a+1), 0);
+ if(ll && ll->dscreen && ll->dscreen->owner != client)
+ ll->dscreen->owner->refreshme = 1;
+ drawuninstall(client, BGLONG(a+1));
+ continue;
+
+ /* free screen: 'F' id[4] */
+ case 'F':
+ printmesg(fmt="L", a, 1);
+ m = 1+4;
+ if(n < m)
+ error(Eshortdraw);
+ drawlookupscreen(client, BGLONG(a+1), &cs);
+ drawuninstallscreen(client, cs);
+ continue;
+
+ /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
+ case 'i':
+ printmesg(fmt="Llb", a, 1);
+ m = 1+4+4+1;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ if(dstid == 0)
+ error("cannot use display as font");
+ font = drawlookup(client, dstid, 1);
+ if(font == 0)
+ error(Enodrawimage);
+ if(font->image->layer)
+ error("cannot use window as font");
+ ni = BGLONG(a+5);
+ if(ni<=0 || ni>4096)
+ error("bad font size (4096 chars max)");
+ free(font->fchar); /* should we complain if non-zero? */
+ font->fchar = malloc(ni*sizeof(FChar));
+ if(font->fchar == 0)
+ error("no memory for font");
+ memset(font->fchar, 0, ni*sizeof(FChar));
+ font->nfchar = ni;
+ font->ascent = a[9];
+ continue;
+
+ /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
+ case 'l':
+ printmesg(fmt="LLSRPbb", a, 0);
+ m = 1+4+4+2+4*4+2*4+1+1;
+ if(n < m)
+ error(Eshortdraw);
+ font = drawlookup(client, BGLONG(a+1), 1);
+ if(font == 0)
+ error(Enodrawimage);
+ if(font->nfchar == 0)
+ error(Enotfont);
+ src = drawimage(client, a+5);
+ ci = BGSHORT(a+9);
+ if(ci >= font->nfchar)
+ error(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':
+ printmesg(fmt="LPPlllLP", a, 0);
+ m = 1+4+2*4+2*4+4+4+4+4+2*4;
+ if(n < m)
+ error(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)
+ error("negative line width");
+ src = drawimage(client, a+33);
+ 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':
+ printmesg("LL", a, 0);
+ m = 4+4;
+ if(n < m)
+ error(Eshortdraw);
+ break;
+ *
+ */
+
+ /* attach to a named image: 'n' dstid[4] j[1] name[j] */
+ case 'n':
+ printmesg(fmt="Lz", a, 0);
+ m = 1+4+1;
+ if(n < m)
+ error(Eshortdraw);
+ j = a[5];
+ if(j == 0) /* give me a non-empty name please */
+ error(Eshortdraw);
+ m += j;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ if(drawlookup(client, dstid, 0))
+ error(Eimageexists);
+ dn = drawlookupname(j, (char*)a+6);
+ if(dn == nil)
+ error(Enoname);
+ if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
+ error(Edrawmem);
+ di = drawlookup(client, dstid, 0);
+ if(di == 0)
+ error("draw: cannot happen");
+ di->vers = dn->vers;
+ di->name = mallocz(j+1, 1);
+ 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':
+ printmesg(fmt="Lbz", a, 0);
+ m = 1+4+1+1;
+ if(n < m)
+ error(Eshortdraw);
+ c = a[5];
+ j = a[6];
+ if(j == 0) /* give me a non-empty name please */
+ error(Eshortdraw);
+ m += j;
+ if(n < m)
+ error(Eshortdraw);
+ di = drawlookup(client, BGLONG(a+1), 0);
+ if(di == 0)
+ error(Enodrawimage);
+ if(di->name)
+ error(Enamed);
+ if(c)
+ drawaddname(client, di, j, (char*)a+7);
+ else{
+ dn = drawlookupname(j, (char*)a+7);
+ if(dn == nil)
+ error(Enoname);
+ if(dn->dimage != di)
+ error(Ewrongname);
+ drawdelname(dn);
+ }
+ continue;
+
+ /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
+ case 'o':
+ printmesg(fmt="LPP", a, 0);
+ m = 1+4+2*4+2*4;
+ if(n < m)
+ error(Eshortdraw);
+ dst = drawimage(client, a+1);
+ if(dst->layer){
+ drawpoint(&p, a+5);
+ drawpoint(&q, a+13);
+ r = dst->layer->screenr;
+ ni = memlorigin(dst, p, q);
+ if(ni < 0)
+ error("image origin failed");
+ 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':
+ printmesg(fmt="b", a, 0);
+ m = 1+1;
+ if(n < m)
+ error(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':
+ printmesg(fmt="LslllLPP", a, 0);
+ m = 1+4+2+4+4+4+4+2*4;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ dst = drawimage(client, a+1);
+ ni = BGSHORT(a+5);
+ if(ni < 0)
+ error("negative count in polygon");
+ e0 = BGLONG(a+7);
+ e1 = BGLONG(a+11);
+ j = 0;
+ if(*a == 'p'){
+ j = BGLONG(a+15);
+ if(j < 0)
+ error("negative polygon line width");
+ }
+ src = drawimage(client, a+19);
+ drawpoint(&sp, a+23);
+ drawpoint(&p, a+31);
+ ni++;
+ pp = malloc(ni*sizeof(Point));
+ if(pp == nil)
+ error(Enomem);
+ doflush = 0;
+ if(dstid==0 || (screenimage && 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);
+ u = drawcoord(u, a+n, oy, &p.y);
+ 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':
+ printmesg(fmt="LR", a, 0);
+ m = 1+4+4*4;
+ if(n < m)
+ error(Eshortdraw);
+ i = drawimage(client, a+1);
+ drawrectangle(&r, a+5);
+ if(!rectinrect(r, i->r))
+ error(Ereadoutside);
+ c = bytesperline(r, i->depth);
+ c *= Dy(r);
+ free(client->readdata);
+ client->readdata = mallocz(c, 0);
+ if(client->readdata == nil)
+ error("readimage malloc failed");
+ client->nreaddata = memunload(i, r, client->readdata, c);
+ if(client->nreaddata < 0){
+ free(client->readdata);
+ client->readdata = nil;
+ error("bad readimage call");
+ }
+ 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':
+ printmesg(fmt="LLLPRPs", a, 0);
+ m = 1+4+4+4+2*4+4*4+2*4+2;
+ if(*a == 'x')
+ m += 4+2*4;
+ if(n < m)
+ error(Eshortdraw);
+
+ dst = drawimage(client, a+1);
+ dstid = BGLONG(a+1);
+ src = drawimage(client, a+5);
+ font = drawlookup(client, BGLONG(a+9), 1);
+ if(font == 0)
+ error(Enodrawimage);
+ if(font->nfchar == 0)
+ error(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)
+ error(Eshortdraw);
+ clipr = dst->clipr;
+ dst->clipr = r;
+ op = drawclientop(client);
+ bg = dst;
+ if(*a == 'x'){
+ /* paint background */
+ bg = drawimage(client, a+47);
+ 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;
+ error(Eindex);
+ }
+ r.max.x += font->fchar[ci].width;
+ u += 2;
+ }
+ memdraw(dst, r, bg, q, memopaque, ZP, op);
+ u -= 2*ni;
+ }
+ q = p;
+ while(--ni >= 0){
+ ci = BGSHORT(u);
+ if(ci<0 || ci>=font->nfchar){
+ dst->clipr = clipr;
+ error(Eindex);
+ }
+ q = drawchar(dst, bg, 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':
+ printmesg(fmt="Ll", a, 0);
+ m = 1+4+4;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ if(dstid == 0)
+ error(Ebadarg);
+ dscrn = drawlookupdscreen(dstid);
+ if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
+ error(Enodrawscreen);
+ if(dscrn->screen->image->chan != BGLONG(a+5))
+ error("inconsistent chan");
+ if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
+ error(Edrawmem);
+ continue;
+
+ /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
+ case 't':
+ printmesg(fmt="bsL", a, 0);
+ m = 1+1+2;
+ if(n < m)
+ error(Eshortdraw);
+ nw = BGSHORT(a+2);
+ if(nw < 0)
+ error(Ebadarg);
+ if(nw == 0)
+ continue;
+ m += nw*4;
+ if(n < m)
+ error(Eshortdraw);
+ lp = malloc(nw*sizeof(Memimage*));
+ if(lp == 0)
+ error(Enomem);
+ if(waserror()){
+ free(lp);
+ nexterror();
+ }
+ for(j=0; j<nw; j++){
+ lp[j] = drawimage(client, a+1+1+2+j*4);
+ if(lp[j]->layer == 0)
+ error("images are not windows");
+ if(lp[j]->layer->screen != lp[0]->layer->screen)
+ error("images not on same screen");
+ }
+ if(a[1])
+ memltofrontn(lp, nw);
+ else
+ memltorearn(lp, nw);
+ if(screenimage && lp[0]->layer->screen->image->data == screenimage->data)
+ for(j=0; j<nw; j++)
+ addflush(lp[j]->layer->screenr);
+ ll = drawlookup(client, BGLONG(a+1+1+2), 1);
+ drawrefreshscreen(ll, client);
+ poperror();
+ free(lp);
+ continue;
+
+ /* visible: 'v' */
+ case 'v':
+ printmesg(fmt="", a, 0);
+ 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':
+ printmesg(fmt="LR", a, 0);
+ // iprint("load %c\n", *a);
+ m = 1+4+4*4;
+ if(n < m)
+ error(Eshortdraw);
+ dstid = BGLONG(a+1);
+ dst = drawimage(client, a+1);
+ drawrectangle(&r, a+5);
+ if(!rectinrect(r, dst->r))
+ error(Ewriteoutside);
+ y = memload(dst, r, a+m, n-m, *a=='Y');
+ if(y < 0)
+ error("bad writeimage call");
+ dstflush(dstid, dst, r);
+ m += y;
+ continue;
+ }
+ }
+ poperror();
+}
+
+void
initfs(char *srvname)
{
+ if (memimageinit() != 0) {
+ werrstr("memimageinit: %r");
+ return;
+ }
+
dlock();
if (!initscreenimage()) {
dunlock();
--
⑨