#include <time.h>#include <lib9.h>#include <draw.h>#include <cursor.h>#include <ninep.h>#include <ninepserver.h>#include "dat.h"#include "fns.h"#include "fsys.h" /* Error messages */char Edeleted[] = "window deleted", Einterrupted[] = "interrupted", Einuse[] = "file in use", Enofile[] = "file not found", Enodrawimage[] = "unknown id for draw image", Enoperm[] = "permission denied", Eshortread[] = "draw read too short", Eshortwrite[] = "draw write too short"; /* Global Vars */static char *snarfbuf;static Pending *killp; voidfsinit(Ninepserver *s){ ninepaddfile(s, Qroot, Qkill, "kill", 0444, eve); ninepaddfile(s, Qroot, Qsnarf, "snarf", 0666, eve); ninepadddir(s, Qroot, Qdraw, "draw", 0555, eve); ninepadddir(s, Qroot, Qwsys, "wsys", 0555, eve);} staticvoiddrawaddfiles(Ninepserver *s, DClient *c){ int i; char name[12]; Path p, cp; Window *w; i = drawpath(c); w= drawwindow(c); p = PATH(i, 0); cp = p|Qdrawn; i = sprint(name, "%d", i); name[i] = 0; ninepadddir(s, Qdraw, cp, name, 0555, eve)->u = w; ninepaddfile(s, cp, p|Qctl, "ctl", 0666, eve); ninepaddfile(s, cp, p|Qdata, "data", 0666, eve); ninepaddfile(s, cp, p|Qcolormap, "colormap", 0444, eve); ninepaddfile(s, cp, p|Qrefresh, "refresh", 0444, eve); ninepadddir(s, cp, p|Qwindow, "window", 0555, eve); ninepbind(s, p|Qwindow, PATH(w->id, 0));} staticPathwsysaddfiles(Ninepserver *s, Window *w){ int i; char name[12]; Path p; i = sprint(name, "%d", w->id); name[i] = 0; p = PATH(w->id, 0); ninepadddir(s, Qwsys, p, name, 0555, eve)->u = w; ninepaddfile(s, p, p|Qcons, "cons", 0666, eve); ninepaddfile(s, p, p|Qconsctl, "consctl", 0222, eve); ninepaddfile(s, p, p|Qkeyboard, "keyboard", 0666, eve); ninepaddfile(s, p, p|Qcursor, "cursor", 0666, eve); ninepaddfile(s, p, p|Qmouse, "mouse", 0666, eve); ninepaddfile(s, p, p|Qpointer, "pointer", 0666, eve); ninepaddfile(s, p, p|Qsnarf, "snarf", 0666, eve); ninepaddfile(s, p, p|Qlabel, "label", 0666, eve); ninepaddfile(s, p, p|Qwctl, "wctl", 0666, eve); ninepaddfile(s, p, p|Qwinid, "winid", 0666, eve); ninepaddfile(s, p, p|Qwinname, "winname", 0666, eve); ninepadddir(s, p, p|Qwsys, "wsys", 0555, eve); ninepadddir(s, p, p|Qdraw, "draw", 0555, eve); ninepaddfile(s, p|Qdraw, p|Qnew, "new", 0666, eve); ninepbind(s, p|Qwsys, Qwsys); ninepbind(s, p|Qdraw, Qdraw); return p;} /* Service Functions */char*wsysattach(Qid *qid, char *uname, char *aname){ Window *w; if(strcmp(aname, "/") == 0) return nil; w = newwin(); if(w == nil) return Enomem; qid->path = wsysaddfiles(server, w); if(!drawattach(w,aname)) { if(w){ assert(w == window[nwindow-1]); free(w); nwindow--; } return Enomem; } return nil;} char*wsysopen(Qid *qid, int mode){ int type; Window *w; DClient *cl; w = qwindow(qid); if(w != nil && w->deleted) return Edeleted; type = QTYPE(qid->path); if(type == Qnew){ cl = drawnewclient(w->draw); if(cl == 0) return Enodev; drawaddfiles(server, cl); type = Qctl; qid->path = PATH(drawpath(cl), type); } switch(type){ case Qmouse: case Qpointer: if(w->mouse.open) return Einuse; w->mouse.open = 1; server->fcall.iounit = 49; return nil; case Qsnarf: /* one at a time please */ if((mode&3) == ORDWR) return Enoperm; return nil; /* Draw client */ case Qctl: case Qdata: case Qcolormap: case Qrefresh: return drawopen(qid, type); } return nil;} char*wsysread(Qid qid, char *buf, ulong *n, vlong offset){ int type; char *s; Window *w; Pending *p; w = qwindow(&qid); type = QTYPE(qid.path); if(w != nil && w->deleted) return Edeleted; switch(type){ case Qkill: killp = ninepreplylater(server); return nil; case Qsnarf: s = xgetsnarf(); *n = ninepreadstr(offset, buf, strlen(s), s); return nil; /* Window */ case Qcons: case Qkeyboard: p = ninepreplylater(server); readkbd(w, p); return nil; case Qlabel: if(w->label) *n = ninepreadstr(offset, buf, strlen(w->label), w->label); return nil; case Qmouse: case Qpointer: p = ninepreplylater(server); readmouse(w, p); return nil; case Qwctl: s = w->visible ? "visible" : "hidden"; *n = sprint(buf, "%11d %11d %11d %11d %s %s ", w->orig.x + w->screenr.min.x, w->orig.y + w->screenr.min.y, w->screenr.max.x, w->screenr.max.y, s, w->current ? "current" : "notcurrent"); *n = ninepreadstr(offset, buf, *n, buf); return nil; case Qwinid: *n = sprint(buf, "%11d ", w->id); *n = ninepreadstr(offset, buf, *n, buf); return nil; case Qwinname: *n = ninepreadstr(offset, buf, strlen(w->name), w->name); return nil; /* Draw client */ case Qctl: case Qdata: case Qcolormap: case Qrefresh: return drawread(qid, buf, n, offset); } // unreachable return "Read called on an unreadable file";} char*wsyswrite(Qid qid, char *buf, ulong *n, vlong offset){ int type; ulong count; char *label, *p; Window *w; Point pt; w = qwindow(&qid); type = QTYPE(qid.path); if((w == nil || w->deleted) && type != Qsnarf) return Edeleted; count = *n; switch(type){ case Qsnarf: if(offset+count >= SnarfSize) return "too much snarf"; if(count == 0) break; if(snarfbuf == nil) *n = 0; else *n = strlen(snarfbuf); if(offset+count > *n){ *n = offset+count; if((p = malloc(*n+1)) == nil) if(p == nil) return Enomem; if(snarfbuf){ strcpy(p, snarfbuf); free(snarfbuf); } snarfbuf = p; } memmove(snarfbuf+offset, buf, count); snarfbuf[offset+count] = '\0'; return nil; case Qconsctl: return nil; case Qcursor: if(cursorwrite(w, buf, *n) < 0){ *n = 0; return "error"; // XXX TODO } return nil; case Qlabel: if((label = malloc(count + 1)) == nil) { *n = 0; return Enomem; } memcpy(label, buf, *n); label[count] = 0; setlabel(w, label); return nil; case Qmouse: case Qpointer: if(count == 0) return Eshortwrite; p = &buf[1]; pt.x = strtoul(p, &p, 0); if(p == 0) return Eshortwrite; pt.y = strtoul(p, 0, 0); xsetmouse(w, pt); return nil; case Qwctl: return wctlmesg(w, buf, count); /* Draw client */ case Qctl: case Qdata: case Qcolormap: case Qrefresh: return drawwrite(qid, buf, n, offset); } // unreachable return "Write called on an unwritable file";} char*wsysclose(Qid qid, int mode) { int type; Window *w; w = qwindow(&qid); type = QTYPE(qid.path); if(w == nil && type != Qsnarf) return nil; switch(type){ case Qsnarf: if(mode == OWRITE){ if(snarfbuf) xputsnarf(snarfbuf); else xputsnarf(""); } free(snarfbuf); snarfbuf = nil; return nil; case Qcons: case Qkeyboard: w->kbd.wi = w->kbd.ri; w->kbdreqs.wi = w->kbdreqs.ri; return nil; case Qmouse: case Qpointer: w->mouse.open = 0; w->mouse.wi = w->mouse.ri; w->mousereqs.wi = w->mousereqs.ri; return nil; /* * If it is a draw file, drawclose will be called * by updateref. If it were called now it could * free the client and qwindow (called from * updateref) would not find a window. */; } return nil;} Window*qwindow(Qid *qid){ Ninepfile *f; f = ninepfindfile(server, qid->path); if(f != nil) return f->u; /* should never happen */ return nil;} intkillreply(Window *w){ Client *c; Fcall *f; if(killp == nil) return 0; c = killp->c; f = &killp->fcall; f->count = sprint(c->data, "%d\n", w->pid); f->data = c->data; ninepcompleted(killp); killp = nil; w->pid = 0; return 1;} voidreadreply(void *v, char *buf){ Pending *p; p = v; p->fcall.data = buf; p->fcall.count = strlen(buf); ninepcompleted(p);} Ninepops ops = { nil, /* newclient */ nil, /* freeclient */ wsysattach, /* attach */ nil, /* walk */ wsysopen, /* open */ nil, /* create */ wsysread, /* read */ wsyswrite, /* write */ wsysclose, /* close */ nil, /* remove */ nil, /* stat */ nil, /* wstat */};
#include <time.h>
#include <lib9.h>
#include <draw.h>
#include <cursor.h>
#include <ninep.h>
#include <ninepserver.h>
#include "dat.h"
#include "fns.h"
#include "fsys.h"
/* Error messages */
char
Edeleted[] = "window deleted",
Einterrupted[] = "interrupted",
Einuse[] = "file in use",
Enofile[] = "file not found",
Enodrawimage[] = "unknown id for draw image",
Enoperm[] = "permission denied",
Eshortread[] = "draw read too short",
Eshortwrite[] = "draw write too short";
/* Global Vars */
static char *snarfbuf;
static Pending *killp;
void
fsinit(Ninepserver *s)
{
ninepaddfile(s, Qroot, Qkill, "kill", 0444, eve);
ninepaddfile(s, Qroot, Qsnarf, "snarf", 0666, eve);
ninepadddir(s, Qroot, Qdraw, "draw", 0555, eve);
ninepadddir(s, Qroot, Qwsys, "wsys", 0555, eve);
}
static
void
drawaddfiles(Ninepserver *s, DClient *c)
{
int i;
char name[12];
Path p, cp;
Window *w;
i = drawpath(c);
w= drawwindow(c);
p = PATH(i, 0);
cp = p|Qdrawn;
i = sprint(name, "%d", i);
name[i] = 0;
ninepadddir(s, Qdraw, cp, name, 0555, eve)->u = w;
ninepaddfile(s, cp, p|Qctl, "ctl", 0666, eve);
ninepaddfile(s, cp, p|Qdata, "data", 0666, eve);
ninepaddfile(s, cp, p|Qcolormap, "colormap", 0444, eve);
ninepaddfile(s, cp, p|Qrefresh, "refresh", 0444, eve);
ninepadddir(s, cp, p|Qwindow, "window", 0555, eve);
ninepbind(s, p|Qwindow, PATH(w->id, 0));
}
static
Path
wsysaddfiles(Ninepserver *s, Window *w)
{
int i;
char name[12];
Path p;
i = sprint(name, "%d", w->id);
name[i] = 0;
p = PATH(w->id, 0);
ninepadddir(s, Qwsys, p, name, 0555, eve)->u = w;
ninepaddfile(s, p, p|Qcons, "cons", 0666, eve);
ninepaddfile(s, p, p|Qconsctl, "consctl", 0222, eve);
ninepaddfile(s, p, p|Qkeyboard, "keyboard", 0666, eve);
ninepaddfile(s, p, p|Qcursor, "cursor", 0666, eve);
ninepaddfile(s, p, p|Qmouse, "mouse", 0666, eve);
ninepaddfile(s, p, p|Qpointer, "pointer", 0666, eve);
ninepaddfile(s, p, p|Qsnarf, "snarf", 0666, eve);
ninepaddfile(s, p, p|Qlabel, "label", 0666, eve);
ninepaddfile(s, p, p|Qwctl, "wctl", 0666, eve);
ninepaddfile(s, p, p|Qwinid, "winid", 0666, eve);
ninepaddfile(s, p, p|Qwinname, "winname", 0666, eve);
ninepadddir(s, p, p|Qwsys, "wsys", 0555, eve);
ninepadddir(s, p, p|Qdraw, "draw", 0555, eve);
ninepaddfile(s, p|Qdraw, p|Qnew, "new", 0666, eve);
ninepbind(s, p|Qwsys, Qwsys);
ninepbind(s, p|Qdraw, Qdraw);
return p;
}
/* Service Functions */
char*
wsysattach(Qid *qid, char *uname, char *aname)
{
Window *w;
if(strcmp(aname, "/") == 0)
return nil;
w = newwin();
if(w == nil)
return Enomem;
qid->path = wsysaddfiles(server, w);
if(!drawattach(w,aname)) {
if(w){
assert(w == window[nwindow-1]);
free(w);
nwindow--;
}
return Enomem;
}
return nil;
}
char*
wsysopen(Qid *qid, int mode)
{
int type;
Window *w;
DClient *cl;
w = qwindow(qid);
if(w != nil && w->deleted)
return Edeleted;
type = QTYPE(qid->path);
if(type == Qnew){
cl = drawnewclient(w->draw);
if(cl == 0)
return Enodev;
drawaddfiles(server, cl);
type = Qctl;
qid->path = PATH(drawpath(cl), type);
}
switch(type){
case Qmouse:
case Qpointer:
if(w->mouse.open)
return Einuse;
w->mouse.open = 1;
server->fcall.iounit = 49;
return nil;
case Qsnarf:
/* one at a time please */
if((mode&3) == ORDWR)
return Enoperm;
return nil;
/* Draw client */
case Qctl:
case Qdata:
case Qcolormap:
case Qrefresh:
return drawopen(qid, type);
}
return nil;
}
char*
wsysread(Qid qid, char *buf, ulong *n, vlong offset)
{
int type;
char *s;
Window *w;
Pending *p;
w = qwindow(&qid);
type = QTYPE(qid.path);
if(w != nil && w->deleted)
return Edeleted;
switch(type){
case Qkill:
killp = ninepreplylater(server);
return nil;
case Qsnarf:
s = xgetsnarf();
*n = ninepreadstr(offset, buf, strlen(s), s);
return nil;
/* Window */
case Qcons:
case Qkeyboard:
p = ninepreplylater(server);
readkbd(w, p);
return nil;
case Qlabel:
if(w->label)
*n = ninepreadstr(offset, buf, strlen(w->label), w->label);
return nil;
case Qmouse:
case Qpointer:
p = ninepreplylater(server);
readmouse(w, p);
return nil;
case Qwctl:
s = w->visible ? "visible" : "hidden";
*n = sprint(buf, "%11d %11d %11d %11d %s %s ", w->orig.x + w->screenr.min.x, w->orig.y + w->screenr.min.y, w->screenr.max.x, w->screenr.max.y, s, w->current ? "current" : "notcurrent");
*n = ninepreadstr(offset, buf, *n, buf);
return nil;
case Qwinid:
*n = sprint(buf, "%11d ", w->id);
*n = ninepreadstr(offset, buf, *n, buf);
return nil;
case Qwinname:
*n = ninepreadstr(offset, buf, strlen(w->name), w->name);
return nil;
/* Draw client */
case Qctl:
case Qdata:
case Qcolormap:
case Qrefresh:
return drawread(qid, buf, n, offset);
}
// unreachable
return "Read called on an unreadable file";
}
char*
wsyswrite(Qid qid, char *buf, ulong *n, vlong offset)
{
int type;
ulong count;
char *label, *p;
Window *w;
Point pt;
w = qwindow(&qid);
type = QTYPE(qid.path);
if((w == nil || w->deleted) && type != Qsnarf)
return Edeleted;
count = *n;
switch(type){
case Qsnarf:
if(offset+count >= SnarfSize)
return "too much snarf";
if(count == 0)
break;
if(snarfbuf == nil)
*n = 0;
else
*n = strlen(snarfbuf);
if(offset+count > *n){
*n = offset+count;
if((p = malloc(*n+1)) == nil)
if(p == nil)
return Enomem;
if(snarfbuf){
strcpy(p, snarfbuf);
free(snarfbuf);
}
snarfbuf = p;
}
memmove(snarfbuf+offset, buf, count);
snarfbuf[offset+count] = '\0';
return nil;
case Qconsctl:
return nil;
case Qcursor:
if(cursorwrite(w, buf, *n) < 0){
*n = 0;
return "error"; // XXX TODO
}
return nil;
case Qlabel:
if((label = malloc(count + 1)) == nil) {
*n = 0;
return Enomem;
}
memcpy(label, buf, *n);
label[count] = 0;
setlabel(w, label);
return nil;
case Qmouse:
case Qpointer:
if(count == 0)
return Eshortwrite;
p = &buf[1];
pt.x = strtoul(p, &p, 0);
if(p == 0)
return Eshortwrite;
pt.y = strtoul(p, 0, 0);
xsetmouse(w, pt);
return nil;
case Qwctl:
return wctlmesg(w, buf, count);
/* Draw client */
case Qctl:
case Qdata:
case Qcolormap:
case Qrefresh:
return drawwrite(qid, buf, n, offset);
}
// unreachable
return "Write called on an unwritable file";
}
char*
wsysclose(Qid qid, int mode) {
int type;
Window *w;
w = qwindow(&qid);
type = QTYPE(qid.path);
if(w == nil && type != Qsnarf)
return nil;
switch(type){
case Qsnarf:
if(mode == OWRITE){
if(snarfbuf)
xputsnarf(snarfbuf);
else
xputsnarf("");
}
free(snarfbuf);
snarfbuf = nil;
return nil;
case Qcons:
case Qkeyboard:
w->kbd.wi = w->kbd.ri;
w->kbdreqs.wi = w->kbdreqs.ri;
return nil;
case Qmouse:
case Qpointer:
w->mouse.open = 0;
w->mouse.wi = w->mouse.ri;
w->mousereqs.wi = w->mousereqs.ri;
return nil;
/*
* If it is a draw file, drawclose will be called
* by updateref. If it were called now it could
* free the client and qwindow (called from
* updateref) would not find a window.
*/;
}
return nil;
}
Window*
qwindow(Qid *qid)
{
Ninepfile *f;
f = ninepfindfile(server, qid->path);
if(f != nil)
return f->u;
/* should never happen */
return nil;
}
int
killreply(Window *w)
{
Client *c;
Fcall *f;
if(killp == nil)
return 0;
c = killp->c;
f = &killp->fcall;
f->count = sprint(c->data, "%d\n", w->pid);
f->data = c->data;
ninepcompleted(killp);
killp = nil;
w->pid = 0;
return 1;
}
void
readreply(void *v, char *buf)
{
Pending *p;
p = v;
p->fcall.data = buf;
p->fcall.count = strlen(buf);
ninepcompleted(p);
}
Ninepops ops = {
nil, /* newclient */
nil, /* freeclient */
wsysattach, /* attach */
nil, /* walk */
wsysopen, /* open */
nil, /* create */
wsysread, /* read */
wsyswrite, /* write */
wsysclose, /* close */
nil, /* remove */
nil, /* stat */
nil, /* wstat */
};