Charles.Forsyth20060303a828770d19 years agoHistory
453 lines · 9.6 KB · Brainfuck
RawDownload
implement Ninewin;include "sys.m";	sys: Sys;include "draw.m";	draw: Draw;	Image, Display, Pointer: import draw;include "arg.m";include "keyboard.m";include "tk.m";include "wmclient.m";	wmclient: Wmclient;	Window: import wmclient;include "sh.m";	sh: Sh; # run a p9 graphics program (default rio) under inferno wm,# making available to it:# /dev/winname - naming the current inferno window (changing on resize)# /dev/mouse - pointer file + resize events; write to change position# /dev/cursor - change appearance of cursor.# /dev/draw - inferno draw device# /dev/cons - read keyboard events, write to 9win stdout. Ninewin: module {	init: fn(ctxt: ref Draw->Context, argv: list of string);};winname: string; init(ctxt: ref Draw->Context, argv: list of string){	size := Draw->Point(500, 500);	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH;	wmclient = load Wmclient Wmclient->PATH;	wmclient->init();	sh = load Sh Sh->PATH; 	buts := Wmclient->Resize;	if(ctxt == nil){		ctxt = wmclient->makedrawcontext();		buts = Wmclient->Plain;	}	arg := load Arg Arg->PATH;	arg->init(argv);	arg->setusage("9win [-s] [-x width] [-y height]");	exportonly := 0;	while(((opt := arg->opt())) != 0){		case opt {		's' =>			exportonly = 1;		'x' =>			size.x = int arg->earg();		'y' =>			size.y = int arg->earg();		* =>			arg->usage();		}	}	if(size.x < 1 || size.y < 1)		arg->usage();	argv = arg->argv();	if(argv != nil && hd argv == "-s"){		exportonly = 1;		argv = tl argv;	}	if(argv == nil && !exportonly)		argv = "rio" :: nil;	if(argv != nil && exportonly){		sys->fprint(sys->fildes(2), "9win: no command allowed with -s flag\n");		raise "fail:usage";	}	title := "9win";	if(!exportonly)		title += " " + hd argv;	w := wmclient->window(ctxt, title, buts);	w.reshape(((0, 0), size));	w.onscreen(nil);	if(w.image == nil){		sys->fprint(sys->fildes(2), "9win: cannot get image to draw on\n");		raise "fail:no window";	} 	sys->pctl(Sys->FORKNS|Sys->NEWPGRP, nil);	ld := "/n/9win";	if(sys->bind("#s", ld, Sys->MREPL) == -1 &&			sys->bind("#s", ld = "/n/local", Sys->MREPL) == -1){		sys->fprint(sys->fildes(2), "9win: cannot bind files: %r\n");		raise "fail:error";	}	w.startinput("kbd" :: "ptr" :: nil);	spawn ptrproc(rq := chan of Sys->Rread, ptr := chan[10] of ref Pointer, reshape := chan[1] of int); 			fwinname := sys->file2chan(ld, "winname");	fconsctl := sys->file2chan(ld, "consctl");	fcons := sys->file2chan(ld, "cons");	fmouse := sys->file2chan(ld, "mouse");	fcursor := sys->file2chan(ld, "cursor");	if(!exportonly){		spawn run(sync := chan of string, w.ctl, ld, argv);		if((e := <-sync) != nil){			sys->fprint(sys->fildes(2), "9win: %s", e);			raise "fail:error";		}	}	spawn serveproc(w, rq, fwinname, fconsctl, fcons, fmouse, fcursor);	if(!exportonly){		# handle events synchronously so that we don't get a "killed" message		# from the shell.		handleevents(w, ptr, reshape);	}else{		spawn handleevents(w, ptr, reshape);		sys->bind(ld, "/dev", Sys->MBEFORE);		export(sys->fildes(0), w.ctl);	}} handleevents(w: ref Window, ptr: chan of ref Pointer, reshape: chan of int){	for(;;)alt{	c := <-w.ctxt.ctl or	c = <-w.ctl =>		e := w.wmctl(c);		if(e != nil)			sys->fprint(sys->fildes(2), "9win: ctl error: %s\n", e);		if(e == nil && c != nil && c[0] == '!'){			alt{			reshape <-= 1 =>				;			* =>				;			}			winname = nil;		}	p := <-w.ctxt.ptr =>		if(w.pointer(*p) == 0){			# XXX would block here if client isn't reading mouse... but we do want to			# extert back-pressure, which conflicts.			alt{			ptr <-= p =>				;			* =>				; # sys->fprint(sys->fildes(2), "9win: discarding mouse event\n");			}		}	}} serveproc(w: ref Window, mouserq: chan of Sys->Rread, fwinname, fconsctl, fcons, fmouse, fcursor: ref Sys->FileIO){	winid := 0;	krc: list of Sys->Rread;	ks: string; 	for(;;)alt {	c := <-w.ctxt.kbd =>		ks[len ks] = inf2p9key(c);		if(krc != nil){			hd krc <-= (array of byte ks, nil);			ks = nil;			krc = tl krc;		}	(nil, d, nil, wc) := <-fcons.write =>		if(wc != nil){			sys->write(sys->fildes(1), d, len d);			wc <-= (len d, nil);		}	(nil, nil, nil, rc) := <-fcons.read =>		if(rc != nil){			if(ks != nil){				rc <-= (array of byte ks, nil);				ks = nil;			}else				krc = rc :: krc;		}	(offset, nil, nil, rc) := <-fwinname.read =>		if(rc != nil){			if(winname == nil){				winname = sys->sprint("noborder.9win.%d", winid++);				if(w.image.name(winname, 1) == -1){					sys->fprint(sys->fildes(2), "9win: namewin %q failed: %r", winname);					rc <-= (nil, "namewin failure");					break;				}			}			d := array of byte winname;			if(offset < len d)				d = d[offset:];			else				d = nil;			rc <-= (d, nil);		}	(nil, nil, nil, wc) := <-fwinname.write =>		if(wc != nil)			wc <-= (-1, "permission denied");	(nil, nil, nil, rc) := <-fconsctl.read =>		if(rc != nil)			rc <-= (nil, "permission denied");	(nil, d, nil, wc) := <-fconsctl.write =>		if(wc != nil){			if(string d != "rawon")				wc <-= (-1, "cannot change console mode");			else				wc <-= (len d, nil);		}	(nil, nil, nil, rc) := <-fmouse.read =>		if(rc != nil)			mouserq <-= rc;	(nil, d, nil, wc) := <-fmouse.write =>		if(wc != nil){			e := cursorset(w, string d);			if(e == nil)				wc <-= (len d, nil);			else				wc <-= (-1, e);		}	(nil, nil, nil, rc) := <-fcursor.read =>		if(rc != nil)			rc <-= (nil, "permission denied");	(nil, d, nil, wc) := <-fcursor.write =>		if(wc != nil){			e := cursorswitch(w, d);			if(e == nil)				wc <-= (len d, nil);			else				wc <-= (-1, e);		}	}} ptrproc(rq: chan of Sys->Rread, ptr: chan of ref Pointer, reshape: chan of int){	rl: list of Sys->Rread;	c := ref Pointer(0, (0, 0), 0);	for(;;){		ch: int;		alt{		p := <-ptr =>			ch = 'm';			c = p;		<-reshape =>			ch = 'r';		rc := <-rq =>			rl  = rc :: rl;			continue;		}		if(rl == nil)			rl = <-rq :: rl;		hd rl <-= (sys->aprint("%c%11d %11d %11d %11d ", ch, c.xy.x, c.xy.y, c.buttons, c.msec), nil);		rl = tl rl;	}} cursorset(w: ref Window, m: string): string{	if(m == nil || m[0] != 'm')		return "invalid mouse message";	x := int m[1:];	for(i := 1; i < len m; i++)		if(m[i] == ' '){			while(m[i] == ' ')				i++;			break;		}	if(i == len m)		return "invalid mouse message";	y := int m[i:];	return w.wmctl(sys->sprint("ptr %d %d", x, y));} cursorswitch(w: ref Window, d: array of byte): string{	Hex: con "0123456789abcdef";	if(len d != 2*4+64)		return w.wmctl("cursor");	hot := Draw->Point(bglong(d, 0*4), bglong(d, 1*4));	s := sys->sprint("cursor %d %d 16 32 ", hot.x, hot.y);	for(i := 2*4; i < len d; i++){		c := int d[i];		s[len s] = Hex[c >> 4];		s[len s] = Hex[c & 16rf];	}	return w.wmctl(s);} run(sync, ctl: chan of string, ld: string, argv: list of string){	Rcmeta: con "|<>&^*[]?();";	sys->pctl(Sys->FORKNS, nil);	if(sys->bind("#₪", "/srv", Sys->MCREATE) == -1){		sync <-= sys->sprint("cannot bind srv device: %r");		exit;	}	srvname := "/srv/9win."+string sys->pctl(0, nil);	# XXX do better.	fd := sys->create(srvname, Sys->ORDWR, 8r600);	if(fd == nil){		sync <-= sys->sprint("cannot create %s: %r", srvname);		exit;	}	sync <-= nil;	spawn export(fd, ctl);	sh->run(nil, "os" ::		"rc" :: "-c" ::			"mount "+srvname+" /mnt/term;"+			"rm "+srvname+";"+			"bind -b /mnt/term"+ld+" /dev;"+			"bind /mnt/term/dev/draw /dev/draw ||"+				"bind -a /mnt/term/dev /dev;"+			quotedc("cd"::"/mnt/term"+cwd()::nil, Rcmeta)+";"+			quotedc(argv, Rcmeta)+";"::			nil		);} export(fd: ref Sys->FD, ctl: chan of string){	sys->export(fd, "/", Sys->EXPWAIT);	ctl <-= "exit";} inf2p9key(c: int): int{	KF: import Keyboard; 	P9KF: con	16rF000;	Spec: con	16rF800;	Khome: con	P9KF|16r0D;	Kup: con	P9KF|16r0E;	Kpgup: con	P9KF|16r0F;	Kprint: con	P9KF|16r10;	Kleft: con	P9KF|16r11;	Kright: con	P9KF|16r12;	Kdown: con	Spec|16r00;	Kview: con	Spec|16r00;	Kpgdown: con	P9KF|16r13;	Kins: con	P9KF|16r14;	Kend: con	P9KF|16r18;	Kalt: con		P9KF|16r15;	Kshift: con	P9KF|16r16;	Kctl: con		P9KF|16r17; 	case c {	Keyboard->LShift =>		return Kshift;	Keyboard->LCtrl =>		return Kctl;	Keyboard->LAlt =>		return Kalt;	Keyboard->Home =>		return Khome;	Keyboard->End =>		return Kend;	Keyboard->Up =>		return Kup;	Keyboard->Down =>		return Kdown;	Keyboard->Left =>		return Kleft;	Keyboard->Right =>		return Kright;	Keyboard->Pgup =>		return Kpgup;	Keyboard->Pgdown =>		return Kpgdown;	Keyboard->Ins =>		return Kins; 	# function keys	KF|1 or	KF|2 or	KF|3 or	KF|4 or	KF|5 or	KF|6 or	KF|7 or	KF|8 or	KF|9 or	KF|10 or	KF|11 or	KF|12 =>		return (c - KF) + P9KF;	}	return c;} cwd(): string{	return sys->fd2path(sys->open(".", Sys->OREAD));} # from string.b, waiting for declaration to be uncommented.quotedc(argv: list of string, cl: string): string{	s := "";	while (argv != nil) {		arg := hd argv;		for (i := 0; i < len arg; i++) {			c := arg[i];			if (c == ' ' || c == '\t' || c == '\n' || c == '\'' || in(c, cl))				break;		}		if (i < len arg || arg == nil) {			s += "'" + arg[0:i];			for (; i < len arg; i++) {				if (arg[i] == '\'')					s[len s] = '\'';				s[len s] = arg[i];			}			s[len s] = '\'';		} else			s += arg;		if (tl argv != nil)			s[len s] = ' ';		argv = tl argv;	}	return s;} in(c: int, s: string): int{	n := len s;	if(n == 0)		return 0;	ans := 0;	negate := 0;	if(s[0] == '^') {		negate = 1;		s = s[1:];		n--;	}	for(i := 0; i < n; i++) {		if(s[i] == '-' && i > 0 && i < n-1)  {			if(c >= s[i-1] && c <= s[i+1]) {				ans = 1;				break;			}			i++;		}		else		if(c == s[i]) {			ans = 1;			break;		}	}	if(negate)		ans = !ans;	return ans;} bglong(d: array of byte, i: int): int{	return int d[i] | (int d[i+1]<<8) | (int d[i+2]<<16) | (int d[i+3]<<24);}