ref: 1e84383ea66d572e979e1add131a2e5ed3cc757a
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Jan 3 15:30:58 EST 2025
adds files
--- /dev/null
+++ b/drawfs/fns.h
@@ -1,0 +1,1 @@
+void initfs(char *srvname);
--- /dev/null
+++ b/drawfs/fs.c
@@ -1,0 +1,878 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+#include "dat.h"
+#include "fns.h"
+
+/* see: /sys/src/9/port/devdraw.c */
+
+enum {
+ Qroot,
+ /* potential files like cons and mouse */
+ Qwinname,
+ Qdevdraw,
+ Qnew,
+ Qclient,
+ Q2nd,
+ Qcolormap,
+ Qctl,
+ Qdata,
+ Qrefresh,
+ Qmax
+};
+
+typedef struct Qfile Qfile;
+struct Qfile {
+ char *name; /* filename, or nil if generated */
+ int type; /* type: QTDIR or QTFILE */
+ int clientref; /* needs client reference in Qpath */
+};
+
+static Qfile qfiles[] = {
+ [Qroot] { ".", QTDIR, 0 },
+ [Qwinname] { "winname", QTFILE, 0 },
+ [Qdevdraw] { "draw", QTDIR, 0 },
+ [Qnew] { "new", QTFILE, 0 },
+ [Qclient] { nil, QTDIR, 1 },
+ [Q2nd] { "2nd", QTDIR, 0 },
+ [Qcolormap] { "colormap", QTFILE, 1 },
+ [Qctl] { "ctl", QTFILE, 1 },
+ [Qdata] { "data", QTFILE, 1 },
+ [Qrefresh] { "refresh", QTFILE, 1 },
+};
+
+#define QSHIFT 4 /* location in qid of client # */
+
+#define QIDTYPE(q) (((q)&0x0000000F)>>0)
+#define QID(q) ((((ulong)(q).path)&0x0000000F)>>0)
+#define CLIENTPATH(q) ((((ulong)q)&0x7ffffff0)>>QSHIFT)
+#define CLIENT(q) CLIENTPATH((q).path)
+
+#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
+{
+ int clientid;
+ int nclient;
+ Client** client;
+ int nname;
+ DName* name;
+ int vers;
+ int softscreen;
+};
+
+struct Client
+{
+ Ref r;
+ DImage* dimage[NHASH];
+ CScreen* cscreen;
+ Refresh* refresh;
+ Rendez refrend;
+ QLock refq;
+ 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;
+ QLock drawlock;
+
+static Memimage *screenimage;
+static DImage* screendimage;
+static char screenname[40];
+static int screennameid;
+
+static Rectangle flushrect;
+static int waste;
+static DScreen* dscreen;
+extern void flushmemscreen(Rectangle);
+ void drawmesg(Client*, void*, int);
+ void drawuninstall(Client*, int);
+ void drawfreedimage(DImage*);
+ Client* drawclientofpath(ulong);
+ DImage* allocdimage(Memimage*);
+
+static char Enodrawimage[] = "unknown id for draw image";
+static char Enodrawscreen[] = "unknown id for draw screen";
+static char Eshortdraw[] = "short draw message";
+static char Eshortread[] = "draw read too short";
+static char Eimageexists[] = "image id in use";
+static char Escreenexists[] = "screen id in use";
+static char Edrawmem[] = "image memory allocation failed";
+static char Ereadoutside[] = "readimage outside image";
+static char Ewriteoutside[] = "writeimage outside image";
+static char Enotfont[] = "image not a font";
+static char Eindex[] = "character index out of range";
+static char Enoclient[] = "no such draw client";
+static char Enameused[] = "image name in use";
+static char Enoname[] = "no image with that name";
+static char Eoldname[] = "named image no longer valid";
+static char Enamed[] = "image already has name";
+static char Ewrongname[] = "wrong name for image";
+
+static char Enomem[] = "no memory";
+static char Ebadarg[] = "bad arguments";
+static char Enodev[] = "no device";
+static char Einuse[] = "device in use";
+
+static void
+dlock(void)
+{
+ qlock(&drawlock);
+}
+
+static int
+candlock(void)
+{
+ return canqlock(&drawlock);
+}
+
+static void
+dunlock(void)
+{
+ qunlock(&drawlock);
+}
+
+static int
+drawcmp(char *a, char *b, int n)
+{
+ if (strlen(a) != n)
+ return 1;
+ return memcmp(a, b, n);
+}
+
+void
+getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
+{
+ /* empty stub: only used for colormap */
+ USED(p, pr, pg, pb);
+}
+
+DImage*
+allocdimage(Memimage *i)
+{
+ DImage *d;
+
+ d = malloc(sizeof(DImage));
+ if (!d)
+ return nil;
+ d->ref = 1;
+ d->name = 0;
+ d->vers = 0;
+ d->image = i;
+ d->dscreen = 0;
+ d->nfchar = 0;
+ d->fchar = 0;
+ d->fromname = 0;
+ return d;
+}
+
+void
+drawaddname(Client *client, DImage *di, int n, char *str)
+{
+ DName *name, *ename, *new, *t;
+
+ name = sdraw.name;
+ ename = &name[sdraw.nname];
+ for (; name < ename; name++)
+ if (drawcmp(name->name, str, n) == 0) {
+ werrstr("name used");
+ return;
+ }
+ t = malloc((sdraw.nname+1)*sizeof(DName));
+ memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
+ free(sdraw.name);
+ sdraw.name = t;
+ new = &sdraw.name[sdraw.nname++];
+ new->name = malloc(n+1);
+ memmove(new->name, str, n);
+ new->name[n] = 0;
+ new->dimage = di;
+ new->client = client;
+ new->vers = ++sdraw.vers;
+}
+
+static DImage*
+makescreenimage(void)
+{
+ ulong chan;
+ DImage *di;
+ Memimage *i;
+ Rectangle r;
+
+ r = Rect(0, 0, 300, 200);
+ chan = RGB24;
+
+ i = allocmemimage(r, chan);
+ if (!i)
+ return nil;
+
+ di = allocdimage(i);
+ if (!di) {
+ freememimage(i);
+ return nil;
+ }
+ snprint(screenname, sizeof screenname, "noborder.screen.%d", ++screennameid);
+ drawaddname(nil, di, strlen(screenname), screenname);
+ return di;
+}
+
+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;
+}
+
+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 || n->vers != d->vers)
+ return 0;
+ return 1;
+}
+
+DImage*
+drawlookup(Client *client, int id, int checkname)
+{
+ DImage *d;
+
+ d = client->dimage[id&HASHMASK];
+ while (d) {
+ if (d->id == id) {
+ if (checkname && !drawgoodname(d))
+ werrstr(Eoldname);
+ return d;
+ }
+ d = d->next;
+ }
+ return nil;
+}
+
+Client*
+drawclientofslot(int slot)
+{
+ Client *cl;
+ if (slot <= 0)
+ return nil;
+ if (slot > sdraw.nclient)
+ return nil;
+ cl = sdraw.client[slot-1];
+ if (!cl || cl->clientid == 0)
+ return nil;
+ return cl;
+}
+
+Client*
+drawclientofpath(ulong path)
+{
+ Client *cl;
+ int slot;
+
+ slot = CLIENTPATH(path);
+ if (slot == 0)
+ return nil;
+ cl = sdraw.client[slot-1];
+ if (!cl || cl->clientid == 0)
+ return nil;
+ return cl;
+}
+
+Memimage*
+drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
+{
+ DImage *d;
+
+ d = allocdimage(i);
+ if (!d)
+ return nil;
+ d->id = id;
+ d->dscreen = dscreen;
+ d->next = client->dimage[id&HASHMASK];
+ client->dimage[id&HASHMASK] = d;
+ return i;
+}
+
+Client*
+drawnewclient(void)
+{
+ Client *cl, **cp;
+ int i;
+
+ for (i = 0; i < sdraw.nclient; i++) {
+ cl = sdraw.client[i];
+ if (!cl)
+ break;
+ }
+ if (i == sdraw.nclient) {
+ cp = malloc((sdraw.nclient+1)*sizeof(Client*));
+ if (!cp)
+ return nil;
+ memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
+ free(sdraw.client);
+ sdraw.client = cp;
+ sdraw.nclient++;
+ cp[i] = 0;
+ }
+ cl = mallocz(sizeof(Client), 1);
+ if (!cl)
+ return nil;
+ cl->slot = i;
+ cl->clientid = ++sdraw.clientid;
+ cl->op = SoverD;
+ sdraw.client[i] = cl;
+ return cl;
+}
+
+Client*
+drawclient(Qid q)
+{
+ return drawclientofpath(q.path);
+}
+
+static void
+mkqid(Qid *qid, vlong path, int type, int vers)
+{
+ qid->path = path;
+ qid->vers = vers;
+ qid->type = type;
+}
+
+static void
+gendir(Dir *d, ulong q, int vers)
+{
+ char *s;
+ int type;
+ char buf[10];
+ Client *cl;
+
+ switch (QIDTYPE(q)) {
+ case Qroot:
+ case Qdevdraw:
+ case Qclient:
+ case Q2nd:
+ type = QTDIR;
+ d->mode = 0666 | DMDIR;
+ break;
+ default:
+ type = QTFILE;
+ d->mode = 0666;
+ }
+
+ d->name = nil;
+ switch (QIDTYPE(q)) {
+ case Qclient:
+ cl = drawclientofpath(q);
+ if (!cl)
+ return; // TODO: error: invalid client
+ snprint(buf, sizeof buf, "%d", cl->clientid);
+ d->name = estrdup9p(buf);
+ }
+
+ mkqid(&d->qid, q, type, vers);
+
+ if (!d->name) {
+ s = qfiles[QIDTYPE(q)].name;
+ if (!s)
+ sysfatal("programming error! QIDTYPE=%uld", QIDTYPE(q));
+ d->name = estrdup9p(s);
+ }
+
+ d->uid = estrdup9p(getuser());
+ d->gid = estrdup9p(d->uid);
+ d->muid = estrdup9p(d->uid);
+ d->atime = d->mtime = time(0);
+ d->length = 0;
+}
+
+static int
+rootgen(int n, Dir *dir, void*)
+{
+ switch (n) {
+ case 0:
+ gendir(dir, Qwinname, 0);
+ return 0;
+ case 1:
+ gendir(dir, Qdevdraw, 0);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+drawgen(int n, Dir *dir, void*)
+{
+ Client *cl;
+
+ if (n == 0) {
+ gendir(dir, Qnew, 0);
+ return 0;
+ }
+
+ /* n is index for client, starting at 1 */
+ if (n <= sdraw.nclient) {
+ cl = sdraw.client[n-1];
+ if (!cl)
+ return -1;
+ gendir(dir, (n<<QSHIFT)|Qclient, 0);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+clgen(int n, Dir *dir, void *aux)
+{
+ Qid *q = aux;
+
+ n += Qcolormap; /* first entry in enum */
+ if (n > Qrefresh) /* last entry in enum */
+ return -1;
+
+ gendir(dir, q->path|n, q->vers);
+ return 0;
+}
+
+static void
+fsopen(Req *r)
+{
+ Client *cl;
+ DName *dn;
+ DImage *di;
+
+ dlock();
+
+ cl = nil;
+ if (QID(r->fid->qid) == Qnew) {
+ cl = drawnewclient();
+ if (!cl) {
+ respond(r, Enodev);
+ goto Out;
+ }
+ r->ofcall.qid.path = Qctl|((cl->slot+1)<<QSHIFT);
+ r->fid->qid.path = r->ofcall.qid.path;
+ }
+
+ switch (QID(r->ofcall.qid)) {
+ case Qwinname:
+ case Qnew:
+ break;
+ case Qctl:
+ if (!cl)
+ cl = drawclient(r->fid->qid);
+ if (cl->busy) {
+ respond(r, Einuse);
+ goto Out;
+ }
+ cl->busy = 1;
+ flushrect = Rect(10000, 10000, -10000, -10000);
+ dn = drawlookupname(strlen(screenname), screenname);
+ if (!dn) {
+ respond(r, "draw: cannot happen 2");
+ goto Out;
+ }
+ if (drawinstall(cl, 0, dn->dimage->image, 0) == 0) {
+ respond(r, Edrawmem);
+ goto Out;
+ }
+ di = drawlookup(cl, 0, 0);
+ if (!di) {
+ respond(r, "draw: cannot happen 1");
+ goto Out;
+ }
+ di->vers = dn->vers;
+ di->name = strdup(screenname);
+ di->fromname = dn->dimage;
+ di->fromname->ref++;
+ incref(&cl->r);
+ break;
+ case Qcolormap:
+ case Qdata:
+ case Qrefresh:
+ cl = drawclient(r->fid->qid);
+ if (!cl) {
+ fprint(2, "client not valid: %uld\n", CLIENT(r->fid->qid));
+ }
+ incref(&cl->r);
+ break;
+ }
+
+Out:
+ dunlock();
+ if (!r->responded)
+ respond(r, nil);
+}
+
+static void
+fsread(Req *r)
+{
+ Qid q;
+ Client *cl;
+ Memimage *i;
+ DImage *di;
+ Refresh *rf;
+ int index, m;
+ long n;
+ uchar *p;
+ ulong red, green, blue;
+ char obuf[12*12+2];
+ char buf[16];
+
+ switch (QID(r->fid->qid)) {
+ case Qroot:
+ dirread9p(r, rootgen, nil);
+ respond(r, nil);
+ break;
+ case Qwinname:
+ readstr(r, screenname);
+ respond(r, nil);
+ break;
+ case Qdevdraw:
+ dirread9p(r, drawgen, nil);
+ respond(r, nil);
+ break;
+ case Qclient:
+ q.path = r->fid->qid.path&~((1<<QSHIFT)-1); /* slot component */
+ q.vers = r->fid->qid.vers;
+ q.type = QTFILE;
+ dirread9p(r, clgen, &q);
+ respond(r, nil);
+ break;
+ }
+
+ cl = drawclientofpath(r->fid->qid.path);
+ dlock();
+
+ switch (QID(r->fid->qid)) {
+ case Qctl:
+ if (r->ifcall.count < 12*12) {
+ respond(r, Eshortread);
+ goto Out;
+ }
+ if (cl->infoid < 0) {
+ respond(r, Enodrawimage);
+ goto Out;
+ }
+ if (cl->infoid == 0) {
+ i = screenimage;
+ if (!i) {
+ respond(r, Enodrawimage);
+ goto Out;
+ }
+ } else {
+ di = drawlookup(cl, cl->infoid, 1);
+ if (!di) {
+ respond(r, Enodrawimage);
+ goto Out;
+ }
+ i = di->image;
+ }
+ sprint(obuf, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
+ cl->clientid,
+ cl->infoid,
+ chantostr(buf, 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);
+ cl->infoid = -1;
+ readstr(r, obuf);
+ //r->ofcall.count--;
+ respond(r, nil);
+ dunlock();
+ return;
+
+ case Qcolormap:
+ p = malloc(4*12*256+1);
+ if (!p) {
+ dunlock();
+ respond(r, Enomem);
+ return;
+ }
+ m = 0;
+ for (index = 0; index < 256; index++) {
+ getcolor(index, &red, &green, &blue);
+ m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n",
+ index, red>>24, green>>24, blue>>24);
+ }
+ readstr(r, (char*)p);
+ free(p);
+ break;
+
+ case Qdata:
+ if (!cl->readdata) {
+ respond(r, "no draw data");
+ goto Out;
+ }
+ if (r->ifcall.count < cl->nreaddata) {
+ respond(r, Eshortread);
+ goto Out;
+ }
+ readbuf(r, cl->readdata, cl->nreaddata);
+ free(cl->readdata);
+ cl->readdata = nil;
+ break;
+
+ case Qrefresh:
+ if (r->ifcall.count < 5*4) {
+ respond(r, Ebadarg);
+ goto Out;
+ }
+ for (;;) {
+ if (cl->refreshme || cl->refresh)
+ break;
+ dunlock();
+ qlock(&cl->refq);
+ // TODO:
+ // implement sleep(9) function: /sys/src/9/port/proc.c:/^sleep
+ qunlock(&cl->refq);
+ dlock();
+ }
+ p = (uchar*)r->ifcall.data;
+ n = r->ifcall.count;
+ while (cl->refresh && n >= 5*4) {
+ rf = cl->refresh;
+ BPLONG(p+0*4, rf->dimage->id);
+ BPLONG(p+1*4, rf->r.min.x);
+ BPLONG(p+2*4, rf->r.min.y);
+ BPLONG(p+3*4, rf->r.max.x);
+ BPLONG(p+4*4, rf->r.max.y);
+ cl->refresh = rf->next;
+ free(rf);
+ p += 5*4;
+ n -= 5*4;
+ }
+ cl->refreshme = 0;
+ break;
+ }
+Out:
+ if (!r->responded)
+ respond(r, nil);
+ dunlock();
+}
+
+static char*
+fswalk(Fid *fid, char *name, Qid *qid)
+{
+ Client *cl;
+ int clslot;
+
+ if (strcmp(name, "..") == 0) {
+ switch (QID(fid->qid)) {
+ case Qroot:
+ *qid = fid->qid;
+ return nil;
+ case Qdevdraw:
+ mkqid(qid, Qroot, QTDIR, 0);
+ fid->qid = *qid;
+ return nil;
+ case Qclient:
+ mkqid(qid, Qdevdraw, QTDIR, 0);
+ fid->qid = *qid;
+ return nil;
+ }
+ return nil;
+ }
+
+ switch (QID(fid->qid)) {
+ case Qroot:
+ for (int q = Qwinname; q <= Qdevdraw; q++) {
+ if (qfiles[q].name && strcmp(qfiles[q].name, name) == 0) {
+ mkqid(qid, q, qfiles[q].type, 0);
+ fid->qid = *qid;
+ return nil;
+ }
+ }
+ return "root file not found";
+ case Qdevdraw:
+ if (qfiles[Qnew].name && strcmp(qfiles[Qnew].name, name) == 0) {
+ mkqid(qid, Qnew, qfiles[Qnew].type, 0);
+ fid->qid = *qid;
+ return nil;
+ }
+ clslot = atoi(name);
+ cl = drawclientofslot(clslot);
+ if (!cl)
+ return "client not found";
+ mkqid(qid, Qclient|((cl->slot+1)<<QSHIFT), qfiles[Qclient].type, 0);
+ fid->qid = *qid;
+ return nil;
+ case Qclient:
+ cl = drawclient(fid->qid);
+ if (!cl)
+ return "no client for this file";
+ for (int q = Qcolormap; q <= Qrefresh; q++) {
+ if (qfiles[q].name && strcmp(qfiles[q].name, name) == 0) {
+ mkqid(qid, q|((cl->slot+1)<<QSHIFT), qfiles[q].type, 0);
+ fid->qid = *qid;
+ return nil;
+ }
+ }
+ return "client file not found";
+ }
+
+ return "file does not exist (walk)";
+}
+
+static void
+fsstat(Req *r)
+{
+ int q = QID(r->fid->qid);
+
+ if (q >= 0 && q < Qmax) {
+ gendir(&r->d, r->fid->qid.path, r->fid->qid.vers);
+ respond(r, nil);
+ return;
+ }
+ respond(r, "not found");
+}
+
+static void
+fsattach(Req *r)
+{
+ mkqid(&r->fid->qid, Qroot, QTDIR, 0);
+ r->ofcall.qid = r->fid->qid;
+ respond(r, nil);
+}
+
+Srv fs = {
+ .attach = fsattach,
+ .walk1 = fswalk,
+ .stat = fsstat,
+ .open = fsopen,
+ .read = fsread,
+};
+
+static int
+initscreenimage(void)
+{
+ if (screenimage)
+ return 1;
+
+ screendimage = makescreenimage();
+ if (!screendimage)
+ return 0;
+ screenimage = screendimage->image;
+ //TODO: mouseresize();
+ return 1;
+}
+
+void
+initfs(char *srvname)
+{
+ dlock();
+ if (!initscreenimage()) {
+ dunlock();
+ sysfatal("initscreenimage error");
+ }
+ dunlock();
+
+ postsrv(&fs, srvname);
+}
--- /dev/null
+++ b/drawfs/main.c
@@ -1,0 +1,64 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include "dat.h"
+#include "fns.h"
+
+extern int chatty9p;
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s -n name\n", argv0);
+ exits("usage");
+}
+
+int fscmdfd;
+int fsdispfd;
+
+void
+main(int argc, char **argv)
+{
+ char file[256];
+ char *name = nil;
+ int p[2];
+ int fd;
+
+ ARGBEGIN{
+ case 'n':
+ name = EARGF(usage());
+ break;
+ case 'D':
+ chatty9p++;
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND;
+
+ if (!name || !name[0]) {
+ name = smprint("%d", getpid());
+ }
+
+ snprint(file, sizeof file, "drawfs.%s", name);
+ initfs(file);
+
+ exits(0);
+
+ pipe(p);
+ snprint(file, sizeof file, "/srv/drawfs.%s.cmd", name);
+ fd = create(file, OWRITE|ORCLOSE, 0666);
+ fprint(fd, "%d", p[0]);
+ fscmdfd = p[1];
+ close(fd);
+ close(p[0]);
+
+ pipe(p);
+ snprint(file, sizeof file, "/srv/drawfs.%s.display", name);
+ fd = create(file, OWRITE|ORCLOSE, 0666);
+ fprint(fd, "%d", p[0]);
+ fsdispfd = p[1];
+ close(fd);
+ close(p[0]);
+}
--- /dev/null
+++ b/drawfs/mkfile
@@ -1,0 +1,13 @@
+</$objtype/mkfile
+
+TARG=drawfs
+OFILES=\
+ main.$O\
+ fs.$O\
+ draw.$O\
+
+HFILES=\
+ fns.h\
+ dat.h\
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/drawmgr/drawmgr.c
@@ -1,0 +1,76 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ exits("usage");
+}
+
+int drawdispfd;
+int drawcmdfd;
+
+void
+eresized(int new)
+{
+ Image *tmpimg;
+ Point size;
+ uchar buf[1+4+4];
+
+ if (new && getwindow(display, Refnone) < 0)
+ sysfatal("can't reattach to window: %r");
+
+ size.x = Dx(screen->r);
+ size.y = Dy(screen->r);
+
+ buf[0] = 'r';
+ BPLONG(buf+1, size.x);
+ BPLONG(buf+5, size.y);
+ write(drawcmdfd, buf, 1+4+4);
+
+ seek(drawdispfd, 0, 0);
+ tmpimg = readimage(display, drawdispfd, 0);
+ if (!tmpimg)
+ sysfatal("%r");
+ draw(screen, screen->r, tmpimg, nil, ZP);
+ freeimage(tmpimg);
+}
+
+void
+main(int argc, char **argv)
+{
+ char file[256];
+ char *name = nil;
+
+ ARGBEGIN{
+ case 'n':
+ name = EARGF(usage());
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND;
+
+ if (!name || !name[0])
+ usage();
+
+ if (strlen(name) + strlen("/srv/drawfs..display") + 2 > 256)
+ sysfatal("error: name too long: %s\n", name);
+
+ snprint(file, sizeof file, "/srv/drawfs.%s.display", name);
+ drawdispfd = open(file, OREAD);
+ if (drawdispfd < 0)
+ sysfatal("%r");
+
+ snprint(file, sizeof file, "/srv/drawfs.%s.cmd", name);
+ drawcmdfd = open(file, ORDWR);
+ if (drawcmdfd < 0)
+ sysfatal("%r");
+
+ if (initdraw(nil, nil, "drawmgr") < 0)
+ sysfatal("initdraw: %r");
+
+ eresized(0);
+}
--- /dev/null
+++ b/drawmgr/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TARG=drawmgr
+OFILES=drawmgr.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+all:V:
+ @{ cd drawfs && mk $MKFLAGS }
+ @{ cd drawmgr && mk $MKFLAGS }
+
+install:V:
+ @{ cd drawfs && mk $MKFLAGS install }
+ @{ cd drawmgr && mk $MKFLAGS install }
--- /dev/null
+++ b/words
@@ -1,0 +1,41 @@
+FUNCTIONALITY
+
+always (in drawfs):
+- draw to internal image data (like memdraw)
+
+offline:
+- NOP
+- ignore cons+mouse
+
+connect (drawmgr):
+- open /dev/draw/new to create new connection
+- initial draw internal display to /dev/draw/n
+- open /dev/cons+mouse stuff
+
+online (drawmgr):
+- after each internal draw/flush, draw internal display to /dev/draw/n
+- forward cons+mouse
+
+disconnect (drawmgr):
+- close /dev/draw/n stuff
+- close /dev/cons+mouse stuff
+
+FILESYSTEM
+
+- default /dev/draw layout (basically copy devdraw.c code)
+- (additional cons+mouse stuff)
+- post fs to /srv/drawfs.NAME
+
+THREADS
+
+- filesystem thread (/srv/drawfs.NAME+mount)
+- display image (/srv/drawfs.NAME.display)
+- console access (/srv/drawfs.NAME.cmd)
+ - note when display changes (refresh)
+ - resize events
+ - how to syncronize pipe? when to read/write? poll?
+
+RESIZE
+
+mgr -----> fs.cmd
+r x[4] y[4] (resize x, y)