Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/octopus/port/lib/panel.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].