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; } }