implement Panels;
include "sys.m";
sys: Sys;
Qid, FD, sleep, create, ORCLOSE, remove,
DMDIR, OREAD, OWRITE, OTRUNC, werrstr,
open, fprint, read, ORDWR, write, pctl, sprint: import sys;
include "env.m";
env: Env;
getenv, setenv: import env;
include "readdir.m";
readdir: Readdir;
MTIME, DESCENDING: import readdir;
include "keyring.m";
include "security.m";
random: Random;
randomint, ReallyRandom: import random;
include "error.m";
err: Error;
checkload, stderr, error, kill: import err;
include "string.m";
str: String;
splitl: import str;
include "panel.m";
init()
{
sys = load Sys Sys->PATH;
err = load Error Error->PATH;
err->init();
env = checkload(load Env Env->PATH, Env->PATH);
readdir = checkload(load Readdir Readdir->PATH, Readdir->PATH);
str = checkload(load String String->PATH, String->PATH);
random = checkload(load Random Random->PATH, Random->PATH);
omero = getenv("omero");
if (omero == nil)
error("$omero is not set");
}
Panel.init(nm: string): ref Panel
{
name := sprint("col:%s.%d", nm, pctl(0, nil));
path := sprint("%s/appl/%s", omero, name);
fd := create(path, OREAD, DMDIR|8r775);
if (fd == nil)
return nil;
cfd := open(path + "/ctl", OWRITE|ORCLOSE);
if (cfd == nil){
remove(path);
return nil;
}
p := ref Panel(0, name, path, cfd, nil, -1);
p.ctl(sprint("appl 0 %d", pctl(0,nil)));
return p;
}
eparsearg(s: string): (string, string)
{
arg: string;
if (s == nil)
return (nil, nil);
(arg, s) = splitl(s, " ");
if (arg == nil || s == nil || len s < 1)
return (arg, nil);
s = s[1:]; # skip ' '
return (arg, s);
}
eparse(s: string): list of string
{
Pref: con "o/mero: ";
path, id, ev, arg: string;
# Must match events sent by o/mero. See
# big comment near the start of ../mero/mero.b
# Also, don't use tokenize, look/exec/apply carry strings
# as arguments.
l := len s;
if (l > 0 && s[l-1] == '\n')
s = s[:l-1];
# o/mero:
if (len s <= len Pref)
return nil;
s = s[len Pref:];
(path, s) = eparsearg(s);
(id, s) = eparsearg(s);
(ev, arg) = eparsearg(s);
if (path == nil || id == nil || ev == nil)
return nil;
case ev {
"look" or "exec" or "apply" or "click" or "keys" =>
if (arg == nil)
return nil;
"close" or "interrupt" or "clean" or "dirty" =>
if (arg != nil)
return nil;
* =>
return nil;
}
return list of {id, path, ev, arg};
}
reader(fd: ref FD, ec: chan of list of string, pc: chan of int)
{
pc <-= pctl(0, nil);
buf := array[4096] of byte; # enough for application events
for(;;){
nr := read(fd, buf, len buf);
if (nr <= 0){
ec <-= nil;
break;
}
args := eparse(string buf[0:nr]);
if (args == nil)
fprint(stderr, "panel: reader: bad event: %s\n", string buf[0:nr]);
else
ec <-= args;
}
}
Panel.eventc(p: self ref Panel): chan of list of string
{
fd := create("/mnt/ports/" + p.name, ORDWR|ORCLOSE, 8r664);
if (fd == nil)
return nil;
expr := array of byte sprint("o/mero: %s.*", p.path[len omero:]);
write(fd, expr, len expr);
pc := chan of int;
ec := chan of list of string;
spawn reader(fd, ec, pc);
p.rpid = <-pc;
return ec;
}
Panel.new(p: self ref Panel, nm: string, id: int): ref Panel
{
name := sprint("%s.%4.4ux", nm, randomint(ReallyRandom)%16rFFFF);
path := sprint("%s/%s", p.path, name);
fd := create(path, OREAD, DMDIR|8r775);
if (fd != nil){
pn := ref Panel(id, name, path, nil, nil, -1);
if (id != 0){
pn.cfd = open(path+"/ctl", OWRITE);
ctl := array of byte sprint("appl %d %d\n", id, pctl(0,nil));
if (write(pn.cfd, ctl, len ctl) != len ctl)
fprint(stderr, "panel: new: appl: %r\n");
}
return pn;
}
return nil;
}
Panel.close(p: self ref Panel)
{
if (p.rpid >= 0)
kill(p.rpid, "kill");
remove(p.path);
p.cfd = nil;
p.dfd = nil;
p.path = p.name = nil; # poison
p.rpid = -1;
}
Panel.ctl(p: self ref Panel, ctl: string): int
{
fd := p.cfd;
if (fd == nil)
fd = open(p.path+"/ctl", OWRITE);
if (fd == nil)
return -1;
data := array of byte ctl;
return write(fd, data, len data);
}
screens(): list of string
{
(dirs, n) := readdir->init(omero, MTIME|DESCENDING);
res : list of string;
res = nil;
for (i := 0; i < n; i++)
if (dirs[i].name != "appl")
res = dirs[i].name :: res;
return res;
}
cols(scr: string): list of string
{
path := scr + "/" + "row:wins";
(dirs, nd) := readdir->init(omero+"/"+path, MTIME|DESCENDING);
res: list of string;
res = nil;
for (i := 0; i < nd; i++){
n := dirs[i].name;
if (n != "data" && n != "ctl" && n != "image")
res = (path + "/" + dirs[i].name) :: res;
}
return res;
}
copy(dfd, sfd: ref FD): int
{
buf := array[16*1024] of byte;
for(tot := nr := 0;; tot += nr){
nr = read(sfd, buf, len buf);
if (nr < 0)
return -1;
if (nr == 0)
return tot;
if (write(dfd, buf, nr) != nr)
return -1;
}
}
|