Charles.Forsyth20060303a828770d19 years agoHistory
620 lines · 14.1 KB · Brainfuck
RawDownload
implement Rioimport;include "sys.m";	sys: Sys;include "draw.m";	draw: Draw;	Image, Point, Rect, Display, Screen: import draw;include "wmsrv.m";	wmsrv: Wmsrv;include "sh.m";	sh: Sh;include "string.m";	str: String; Rioimport: module{	init: fn(nil: ref Draw->Context, argv: list of string);}; Client: adt{	ptrstarted:	int;	kbdstarted:	int;	state:		int;		# Hidden|Current	req:		chan of (array of byte, Sys->Rwrite);	resize:	chan of ref Riowin;	ptr:		chan of ref Draw->Pointer;	riowctl:	chan of (ref Riowin, int);	wins:	list of ref Riowin;	winfd:	ref Sys->FD;	sc: 		ref Wmsrv->Client;}; Riowin: adt {	tag:		string;	img:		ref Image;	dir:		string;	state:	int;	ptrpid:	int;	kbdpid:	int;	ctlpid:	int;	ptrfd:	ref Sys->FD;	ctlfd:		ref Sys->FD;}; Hidden, Current: con 1<<iota;Ptrsize: con 1+4*12;		# 'm' plus 4 12-byte decimal integersP9PATH: con "/n/local";Borderwidth: con 4;		# defined in /sys/include/draw.h display: ref Display;wsysseq := 0;screenr := Rect((0, 0), (640, 480));	# no way of getting this reliably from rio Minwinsize: con Point(100, 42); init(nil: ref Draw->Context, argv: list of string){	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH;	sh = load Sh Sh->PATH;	sh->initialise();	str = load String String->PATH;	wmsrv = load Wmsrv Wmsrv->PATH; 	wc := chan of (ref Draw->Context, string);	spawn rioproxy(wc);	(ctxt, err) := <-wc;	if(err != nil){		sys->fprint(sys->fildes(2), "rioimport: %s\n", err);		raise "fail:no display";	}	sh->run(ctxt, tl argv);} ebind(a, b: string, flag: int){	if(sys->bind(a, b, flag) == -1){		sys->fprint(sys->fildes(2), "rioimport: cannot bind %q onto %q: %r\n", a, b);		raise "fail:error";	}} rioproxy(wc: chan of (ref Draw->Context, string)){	{		rioproxy1(wc);	} exception e {	"fail:*" =>		wc <-= (nil, e[5:]);	}} rioproxy1(wc: chan of (ref Draw->Context, string)){	sys->pctl(Sys->NEWFD, 0 :: 1 :: 2 :: nil); 	ebind("#U*", P9PATH, Sys->MREPL);	display = Display.allocate(P9PATH + "/dev");	if(display == nil)		raise sys->sprint("fail:cannot allocate display: %r");  	(wm, join, req) := wmsrv->init();	if(wm == nil){		wc <-= (nil, sys->sprint("%r"));		return;	}	readscreenr();	wc <-= (ref Draw->Context(display, nil, wm), nil); 	sys->pctl(Sys->FORKNS, nil);	ebind("#₪", "/srv", Sys->MREPL|Sys->MCREATE);	if(sys->bind(P9PATH+"/dev/draw", "/dev/draw", Sys->MREPL) == -1)		ebind(P9PATH+"/dev", "/dev", Sys->MAFTER);	sh->run(nil, "mount" :: "{mntgen}" :: "/mnt" :: nil); 	clients: array of ref Client;	nc := 0;	for(;;) alt{	(sc, rc) := <-join =>		if(nc != 0)			rc <-= "only one client available";		sync := chan of (ref Client, string);		spawn clientproc(sc,sync);		(c, err) := <-sync;		rc <-= err;		if(c != nil){			if(sc.id >= len clients)				clients = (array[sc.id + 1] of ref Client)[0:] = clients;			clients[sc.id] = c;		}	(sc, data, rc) := <-req =>		clients[sc.id].req <-= (data, rc);		if(rc == nil)			clients[sc.id] = nil;	}}zclient: Client;clientproc(sc: ref Wmsrv->Client, rc: chan of (ref Client, string)){	c := ref zclient;	c.req = chan of (array of byte, Sys->Rwrite);	c.resize = chan of ref Riowin;	c.ptr = chan of ref Draw->Pointer;	c.riowctl = chan of (ref Riowin, int);	c.sc = sc;	rc <-= (c, nil); loop:	for(;;) alt{	(data, drc) := <-c.req =>		if(drc == nil)			break loop;		err := handlerequest(c, data);		n := len data;		if(err != nil)			n = -1;		alt{		drc <-= (n, err) =>;		* =>;		}	p := <-c.ptr =>		sc.ptr <-= p;	w := <-c.resize =>		if((c.state & Hidden) == 0)			sc.ctl <-= sys->sprint("!reshape %q -1 0 0 0 0 getwin", w.tag);	(w, state) := <-c.riowctl =>		if((c.state^state)&Current)			sc.ctl <-= "haskbdfocus " + string ((state & Current)!=0);		if((c.state^state)&Hidden){			s := "unhide";			if(state&Hidden)				s = "hide";			for(wl := c.wins; wl != nil; wl = tl wl){				if(hd wl != w)					rioctl(hd wl, s);				if(c.state&Hidden)					sc.ctl <-= sys->sprint("!reshape %q -1 0 0 0 0 getwin", (hd wl).tag);			}		}		c.state = state;		w.state = state;	}	sc.stop <-= 1;	for(wl := c.wins; wl != nil; wl = tl wl)		delwin(hd wl);} handlerequest(c: ref Client, data: array of byte): string{	req := string data;#sys->print("%d: %s\n", c.sc.id, req);	if(req == nil)		return "no request";	args := str->unquoted(req);	n := len args;	case hd args {	"key" =>		return "permission denied";	"ptr" =>		# ptr x y		if(n != 3)			return "bad arg count";		if(c.ptrstarted == 0)			return "pointer not active";		for(w := c.wins; w != nil; w = tl w){			if((hd w).ptrfd != nil){				sys->fprint((hd w).ptrfd, "m%11d %11d", int hd tl args, int hd tl tl args);				return nil;			}		}		return "no windows";	"start" =>		if(n != 2)			return "bad arg count";		case hd tl args {		"ptr" or		"mouse" =>			if(c.ptrstarted == -1)				return "already started";			sync := chan of int;			for(w := c.wins; w != nil; w = tl w){				spawn ptrproc(hd w, c.ptr, c.resize, sync);				(hd w).ptrpid = <-sync;			}			c.ptrstarted = 1;			return nil;		"kbd" =>			if(c.kbdstarted == -1)				return "already started";			sync := chan of int;			for(w := c.wins; w != nil; w = tl w){				spawn kbdproc(hd w, c.sc.kbd, sync);				(hd w).kbdpid = <-sync;			}			return nil;		* =>			return "unknown input source";		}	"!reshape" =>		# reshape tag reqid rect [how]		# XXX allow "how" to specify that the origin of the window is never		# changed - a new window will be created instead.		if(n < 7)			return "bad arg count";		args = tl args;		tag := hd args; args = tl args;		args = tl args;		# skip reqid		r: Rect;		r.min.x = int hd args; args = tl args;		r.min.y = int hd args; args = tl args;		r.max.x = int hd args; args = tl args;		r.max.y = int hd args; args = tl args;		if(r.dx() < Minwinsize.x)			r.max.x = r.min.x + Minwinsize.x;		if(r.dy() < Minwinsize.y)			r.max.y = r.min.y + Minwinsize.y; 		spec := "";		if(args != nil){			case hd args{			"onscreen" =>				r = fitrect(r, screenr).inset(-Borderwidth);				spec = "-r " + r2s(r);			"place" =>				r = fitrect(r, screenr).inset(-Borderwidth);				spec = "-dx " + string r.dx() + " -dy " + string r.dy();			"exact" =>				spec = "-r " + r2s(r.inset(-Borderwidth));			"max" =>				r = screenr;			# XXX don't obscure toolbar?				spec = "-r " + r2s(r.inset(Borderwidth));			"getwin" =>				;						# just get the new image			* =>				return "unkown placement method";			}		}else			spec = "-r " + r2s(r.inset(-Borderwidth));		return reshape(c, tag, spec);	"delete" =>		# delete tag		if(tl args == nil)			return "tag required";		tag := hd tl args;		nw: list of ref Riowin;		for(w := c.wins; w != nil; w = tl w){			if((hd w).tag == tag){				delwin(hd w);				wmsrv->c.sc.setimage(tag, nil);			}else				nw = hd w :: nw;		}		c.wins = nil;		for(; nw != nil; nw = tl nw)			c.wins = hd nw :: c.wins;	"label" =>		if(n != 2)			return "bad arg count";		for(w := c.wins; w != nil; w = tl w)			setlabel(hd w, hd tl args);	"raise" =>		for(w := c.wins; w != nil; w = tl w){			rioctl(hd w, "top");			if(tl w == nil)				rioctl(hd w, "current");		}	"lower" =>		for(w := c.wins; w != nil; w = tl w)			rioctl(hd w, "bottom");	"task" =>		if(n != 2)			return "bad arg count";		c.state |= Hidden;		for(w := c.wins; w != nil; w = tl w){			setlabel(hd w, hd tl args);			rioctl(hd w, "hide");		}	"untask" =>		wins: list of ref Riowin;		for(w := c.wins; w != nil; w = tl w)			wins = hd w :: wins;		for(; wins != nil; wins = tl wins)			rioctl(hd wins, "unhide");	"!move" =>		# !move tag reqid startx starty		if(n != 5)			return "bad arg count";		args = tl args;		tag := hd args; args = tl args;		args = tl args;		w := wmsrv->c.sc.window(tag);		if(w == nil)			return "no such tag";		return dragwin(c.ptr, c, w, Point(int hd args, int hd tl args));	"!size" =>		return "nope";	"kbdfocus" =>		if(n != 2)			return "bad arg count";		if(int hd tl args){			if(c.wins != nil)				return rioctl(hd c.wins, "current");		}		return nil;	* =>		return "unknown request";	}	return nil;} dragwin(ptr: chan of ref Draw->Pointer, c: ref Client, w: ref Wmsrv->Window, click: Point): string{#	if(buttons == 0)#		return "too late";	p: ref Draw->Pointer;	img := w.img.screen.image;	r := img.r;	off := click.sub(r.min);	do{		p = <-ptr;		img.origin(r.min, p.xy.sub(off));	} while (p.buttons != 0);	c.sc.ptr <-= p;#	buttons = 0;	nr: Rect;	nr.min = p.xy.sub(off);	nr.max = nr.min.add(r.size());	if(nr.eq(r))		return "not moved";	reshape(c, w.tag, "-r " + r2s(nr));	return nil;} rioctl(w: ref Riowin, req: string): string{	if(sys->fprint(w.ctlfd, "%s", req) == -1){#sys->print("rioctl fail %s: %s: %r\n", w.dir, req);		return sys->sprint("%r");}#sys->print("rioctl %s: %s\n", w.dir, req);	return nil;} reshape(c: ref Client, tag: string, spec: string): string{	for(wl := c.wins; wl != nil; wl = tl wl)		if((hd wl).tag == tag)			break;	if(wl == nil){		(w, e) := newwin(c, tag, spec);		if(w == nil){sys->print("can't make new win (spec %q): %s\n", spec, e);			return e;		}		c.wins = w :: c.wins;		wmsrv->c.sc.setimage(tag, w.img);		sync := chan of int;		if(c.kbdstarted){			spawn kbdproc(w, c.sc.kbd, sync);			w.kbdpid = <-sync;		}		if(c.ptrstarted){			spawn ptrproc(w, c.ptr, c.resize, sync);			w.ptrpid = <-sync;		}		return nil;	}	w := hd wl;	if(spec != nil){		e := rioctl(w, "resize " + spec);		if(e != nil)			return e;	}	getwin(w);	if(w.img == nil)		return "getwin failed";	wmsrv->c.sc.setimage(tag, w.img);	return nil;} zriowin: Riowin;newwin(c: ref Client, tag, spec: string): (ref Riowin, string){	wsys := readfile(P9PATH + "/env/wsys");	if(wsys == nil)		return (nil, "no $wsys");		d := "/mnt/"+string wsysseq++;	fd := sys->open(wsys, Sys->ORDWR);	if(fd == nil)		return (nil, sys->sprint("cannot open %q: %r\n", wsys));	# XXX this won't multiplex properly - srv9 should export attach files (actually that's what plan 9 should do)	if(sys->mount(fd, nil, d, Sys->MREPL, "new "+spec) == -1)		return (nil, sys->sprint("mount %q failed: %r", wsys));	(ok, nil) := sys->stat(d + "/winname");	if(ok == -1)		return (nil, "could not make window");	w := ref zriowin;	w.tag = tag;	w.dir = d;	getwin(w);	w.ctlfd = sys->open(d + "/wctl", Sys->ORDWR);	setlabel(w, "inferno "+string sys->pctl(0, nil)+"."+tag);	sync := chan of int;	spawn ctlproc(w, c.riowctl, sync);	w.ctlpid = <-sync;	return (w, nil);} setlabel(w: ref Riowin, s: string){	fd := sys->open(w.dir + "/label", Sys->OWRITE);	if(fd != nil)		sys->fprint(fd, "%s", s);} ctlproc(w: ref Riowin, wctl: chan of (ref Riowin, int), sync: chan of int){	sync <-= sys->pctl(0, nil);	buf := array[1024] of byte;	for(;;){		n := sys->read(w.ctlfd, buf, len buf);		if(n <= 0)			break;		if(n > 4*12){			state := 0;			(nil, toks) := sys->tokenize(string buf[4*12:], " ");			if(hd toks == "current")				state |= Current;			if(hd tl toks == "hidden")				state |= Hidden;			wctl <-= (w, state);		}	}#sys->print("riowctl eof\n");} delwin(w: ref Riowin){	sys->unmount(nil, w.dir);	kill(w.ptrpid, "kill");	kill(w.kbdpid, "kill");	kill(w.ctlpid, "kill");} getwin(w: ref Riowin): int{	s := readfile(w.dir + "/winname");#sys->print("getwin %s\n", s);	i := display.namedimage(s);	if(i == nil)		return -1;	scr := Screen.allocate(i, display.white, 0);	if(scr == nil)		return -1;	wi := scr.newwindow(i.r.inset(Borderwidth), Draw->Refnone, Draw->Nofill);	if(wi == nil)		return -1;	w.img = wi;	return 0;}

Lines 1–500 of 620.