Charles.Forsyth20060303a828770d19 years agoHistory
2171 lines · 48.5 KB · Brainfuck
RawDownload
implement Charon; include "common.m";include "debug.m"; sys: Sys;CU: CharonUtils;	ByteSource, MaskedImage, CImage, ImageCache, ReqInfo, Header, 	ResourceState, config, max, min, X: import CU; D: Draw;	Point, Rect, Font, Image, Display, Screen: import D; S: String;U: Url;	Parsedurl: import U;L: Layout;	Frame, Loc, Control: import L;I: Img;	ImageSource: import I; B: Build;	Item, Dimen: import B; E: Events;	Event: import E; J: Script; G: Gui; C : Ctype; include "sh.m";  # package up info related to a navigation commandGoSpec: adt {	kind: int;				# GoNormal, etc.	url: ref Parsedurl;		# destination (absolute)	meth: int;				# HGet or HPost	body: string;			# used if HPost	target: string;			# name of target frame	auth: string;			# optional auth info	histnode: ref HistNode;	# if kind is GoHistnode 	newget: fn(kind: int, url: ref Parsedurl, target: string) : ref GoSpec;	newpost: fn(url: ref Parsedurl, body, target: string) : ref GoSpec;	newspecial: fn(kind: int, histnode: ref HistNode) : ref GoSpec;	equal: fn(a: self ref GoSpec, b: ref GoSpec) : int;}; GoNormal, GoReplace, GoLink, GoHistnode, GoSettext: con iota; # Information about a set of frames making up the screenDocConfig: adt {	framename: string;		# nonempty, except possibly for topconfig	title: string;	initconfig: int;			# true unless this is a frameset and some subframe changed	gospec: cyclic ref GoSpec;	# TODO: add current y pos and form field values 	equal: fn(a: self ref DocConfig, b: ref DocConfig) : int;	equalarray: fn(a1: array of ref DocConfig, a2: array of ref DocConfig) : int;}; # Information about a particular screen configurationHistNode: adt {	topconfig: cyclic ref DocConfig;			# config of top (whole doc, or frameset root)	kidconfigs: cyclic array of ref DocConfig;	# configs for kid frames (if a frameset)	preds: cyclic list of ref HistNode;	# edges in (via normal navigation)	succs: cyclic list of ref HistNode;	# edges out (via normal navigation)	findid : int;	findchain : cyclic list of ref HistNode; 	addedge: fn(a: self ref HistNode, b: ref HistNode, atob: int);	copy: fn(a: self ref HistNode) : ref HistNode;}; History: adt {	h: array of ref HistNode;	# all visited HistNodes, in LRU order	n: int;				# h[0:n] is valid part of h	findid : int; 	add: fn(h: self ref History, f: ref Frame, g: ref GoSpec, navkind: int);	update: fn(h: self ref History, f: ref Frame);	find: fn(h: self ref History, k: int) : ref HistNode;	print: fn(h: self ref History);	histinfo: fn(h: self ref History) : (int, string, string, string);	findurl: fn(h: self ref History, s: string) : ref HistNode;}; # Authentication stringsAuthInfo: adt {	realm: string;	credentials: string;}; auths: list of ref AuthInfo = nil; history : ref History;keyfocus: ref Control;mouseover: ref B->Anchor;mouseoverfr: ref Frame;grabctl: ref Control;popupctl: ref Control; SP : con 8;			# a spacer for between controlsSP2 : con 4;			# half of SPSP3 : con 2;pgrp := 0;gopgrp := 0;dbg := 0;warn := 0;dbgres := 0;doscripts := 0; top, curframe: ref Frame;mainwin: ref Image;p0 := Point(0,0); context: ref Draw->Context;opener: chan of string; sendopener(s: string){	if(opener != nil){		alt{			opener <- = s =>				;			* =>				;		}	}} hasopener(): int{	return opener != nil;} init(ctxt: ref Draw->Context, argl: list of string){	chctxt := ref Context(ctxt, argl, nil, nil, nil);	initc(chctxt);} initc(ctxt: ref Context){	sys = load Sys Sys->PATH;	if (ctxt == nil)		fatalerror("bad args\n");	opener = ctxt.c;	argl := ctxt.args;	context = ctxt.ctxt; 	(retval, nil) := sys->stat("/net/tcp");	if(retval < 0)		sys->bind("#I", "/net", sys->MREPL);	(retval, nil) = sys->stat("/net/cs");	if(retval < 0)		startcs(); 	pgrp = sys->pctl(sys->NEWPGRP, nil);	CU = load CharonUtils CharonUtils->PATH;	if(CU == nil)		fatalerror(sys->sprint("Couldn't load %s\n", CharonUtils->PATH)); 	ech := chan of ref Event;	errpath := CU->init(load Charon SELF, CU, argl, ech, ctxt.cksrv, ctxt.ckclient);	if(errpath != "")		fatalerror(sys->sprint("Couldn't load %s\n", errpath));	ctxt = nil; 	sys = load Sys Sys->PATH;	D = load Draw Draw->PATH;	S = load String String->PATH;	U = load Url Url->PATH;	if (U != nil)		U->init();	E = CU->E;	L = CU->L;	I = CU->I;	B = CU->B;	J = CU->J;	G = CU->G;	C = CU->C; 	dbg = int (CU->config).dbg['d'];	warn = dbg ||  int (CU->config).dbg['w'];	dbgres = int (CU->config).dbg['r'];	doscripts = (CU->config).doscripts && J != nil;	if(dbg && (CU->config).dbgfile != "") {		dfile := sys->create((CU->config).dbgfile, sys->OWRITE, 8r666);		if(dfile != nil) {			sys->dup(dfile.fd, 1);		}	}	curres := ResourceState.cur();	newres: ResourceState;	if(dbgres) {		(CU->startres).print("starting resources");		curres = ResourceState.cur();	} 	context = G->init(context, CU);	if(dbgres) {		newres = ResourceState.cur();		newres.since(curres).print("difference after G->init (made screen windows)");		curres = newres;	}	mainwin = G->mainwin; 	# L->init() was deferred until after G was inited	L->init(CU);	if(dbgres) {		newres = ResourceState.cur();		newres.since(curres).print("difference after L->init (loaded Build, Lex)");		curres = newres;	}	(CU->imcache).init();	if(dbgres) {		newres = ResourceState.cur();		newres.since(curres).print("difference after (CU->imcache).init");		curres = newres;	}	start();	if(J != nil)		J->frametreechanged(top);	startpage := config.starturl;	g := GoSpec.newget(GoNormal, CU->makeabsurl(startpage), "_top");	if(dbgres) {		newres = ResourceState.cur();		newres.since(curres).print("difference after initial configure");		curres = newres;	}	spawn plumbwatch();	spawn go(g); 	sendopener("B"); Forloop:	for(;;) {		ev := <- ech; 		if(dbg > 1) {			pick de := ev {			Emouse =>				if(dbg > 2 || de.mtype != E->Mmove)					sys->print("%s\n", ev.tostring());			* =>				sys->print("%s\n", ev.tostring());			}		}		pick  e := ev {		Ekey =>			g = nil;			case e.keychar {			E->Kdown =>				curframe.yscroll(L->CAscrollpage, -1);			E->Kup =>				curframe.yscroll(L->CAscrollpage, 1);			E->Khome =>				curframe.yscroll(L->CAscrollpage, -10000);			E->Kend => 				curframe.yscroll(L->CAscrollpage, 10000);				E->Kaup =>				curframe.yscroll(L->CAscrollline, -1);			E->Kadown => 				curframe.yscroll(L->CAscrollline, 1);				* =>				handlekey(e);			}		Emouse =>			g = handlemouse(e);		Ereshape =>			mainwin = G->mainwin;			redraw(1);			curframe = top;			g = GoSpec.newspecial(GoHistnode, history.find(0));		Equit =>			break Forloop;		Estop =>			if(gopgrp != 0)				stop();			g = nil;		Eback =>			g = GoSpec.newspecial(GoHistnode, history.find(-1));		Efwd =>			g = GoSpec.newspecial(GoHistnode, history.find(1));		Eform =>			formaction(e.frameid, e.formid, e.ftype, 0);			g = nil;		Eformfield =>			formfieldaction(e.frameid, e.formid, e.fieldid, e.fftype);			g = nil;		Ego =>			case e.gtype {			E->EGnormal =>				url := CU->makeabsurl(e.url);				if (url != nil)					g = GoSpec.newget(GoNormal,url, e.target);				else					g = nil;			E->EGreplace =>				g = GoSpec.newget(GoReplace, U->parse(e.url), e.target);			E->EGreload =>				g = GoSpec.newspecial(GoHistnode, history.find(0));			E->EGforward =>				g = GoSpec.newspecial(GoHistnode, history.find(1));			E->EGback =>				g = GoSpec.newspecial(GoHistnode, history.find(-1));			E->EGdelta =>				g = GoSpec.newspecial(GoHistnode, history.find(e.delta));			E->EGlocation =>				g = GoSpec.newspecial(GoHistnode, history.findurl(e.url));			}		Esubmit =>			if(e.subkind == CU->HGet)				g = GoSpec.newget(GoNormal, e.action, e.target);			else {				g = GoSpec.newpost(e.action, e.data, e.target);			}		Escroll =>			f := findframe(top, e.frameid);			if (f != nil)				f.scrollabs(e.pt);			g = nil;		Escrollr =>			f := findframe(top, e.frameid);			if (f != nil)				f.scrollrel(e.pt);			g = nil;		Esettext =>			f := findframe(top, e.frameid);			if (f != nil)				g = ref GoSpec (GoSettext, e.url, 0, e.text, f.name, "", nil);		Elostfocus =>			setfocus(nil);			g = nil;		Edismisspopup =>			if (popupctl != nil)				setfocus(popupctl.donepopup());			popupctl = nil;			grabctl = nil;		} 		if (g == nil)			continue; 		if (g.kind != GoSettext) {			if (g.url != nil) {				scheme := g.url.scheme;				if (scheme == "javascript") {					if (doscripts)						spawn dojsurl(g);					continue;				}				if (!CU->schemeok(scheme)) {					url := g.url.tostring();					if (plumbsend(url, "url") == -1)						G->setstatus(X("bad URL", "gui")+": "+url);					continue;				}			}		} 		if(gopgrp != 0)			stop();		spawn go(g);	}	finish();} mkprog(c: Command, ctxt: ref Draw->Context, args: list of string){	sys->pctl(Sys->NEWPGRP|Sys->NEWFD, list of {0, 1, 2});	c->init(ctxt, args);} start(){	top = Frame.new();	curframe = top;	history = ref History(nil, 0, 0);		keyfocus = nil;	mouseover = nil;	redraw(1);} redraw(resized: int){	im := mainwin;	if(resized) {#		top.r = im.r.inset(2*L->ReliefBd);		top.r = im.r;		top.cim = mainwin;		top.reset();		(CU->imcache).resetlimits();	}	im.clipr = im.r;#	L->drawrelief(im, top.r.inset(-L->ReliefBd), L->ReliefRaised);#	L->drawrelief(im, top.r, L->ReliefSunk);	L->drawfill(im, top.r, CU->White);	G->flush(im.r);#	im.clipr = top.r;} # Return a Loc representing a control in the frame fframeloc(c: ref Control, f: ref Frame) : ref Loc{	loc := Loc.new();	loc.add(L->LEframe, f.r.min);	loc.le[loc.n-1].frame = f;	if (c != nil) {		loc.add(L->LEcontrol, c.r.min);		loc.le[loc.n-1].control = c;	}	return loc;} resetkeyfocus(f: ref Frame){	# determine if focus is in frame f or one of its sub-frames	if (keyfocus == nil)		return; 	for (focusf := keyfocus.f; focusf != nil; focusf = focusf.parent) {		if (focusf == f) {			keyfocus = nil;			break;		}	}	# current focus not in frameset being modified - leave as is} ctlmouse(e: ref Event.Emouse, ctl, grab: ref Control): ref Control{	ev := E->SEnone;	(action, newgrab) := ctl.domouse(e.p, e.mtype, grab);	case (action) {	L->CAbuttonpush =>		if(doscripts && ctl.ff != nil && ctl.ff.evmask)			ev = E->SEonclick;		else			pushaction(ctl, e.p.sub(ctl.r.min));	L->CAkeyfocus =>		setfocus(ctl);	L->CAchanged =>		# Select Formfield - selection has changed		ev = E->SEonchange;	L->CAselected =>		# text input Formfield - text selection has changed		ev = E->SEonselect;	L->CAdopopup =>		popupctl = ctl.dopopup();		if (popupctl != nil)			setfocus(popupctl);	L->CAdonepopup =>		setfocus(ctl.donepopup());		ev = E->SEonchange;		popupctl = nil;	}	if (doscripts && ctl.ff != nil && (ctl.ff.evmask & ev)) {		se := ref E->ScriptEvent(ev, ctl.f.id, ctl.ff.form.formid, ctl.ff.fieldid,				-1, -1, e.p.x, e.p.y, 1, nil, nil, 0);		J->jevchan <-= se;	}	return newgrab;} mainwinmouse(e: ref Event.Emouse) : (ref GoSpec, ref Control){	p := e.p;	g : ref GoSpec;	ctl : ref Control;	newgrab : ref Control;	domouseout := 0;	loc : ref Loc;	if(mouseover != nil)		domouseout = 1; 	loc = top.find(p, nil);	if(loc != nil) {		if(dbg > 1)			loc.print("mouse loc");		f := loc.lastframe();		hasscripts := f.doc.hasscripts;		if(e.mtype != E->Mmove)			curframe = f;		n1 := loc.n-1;		case loc.le[n1].kind {		L->LEitem =>			it := loc.le[n1].item;			if (it.anchorid < 0)				break; 			a : ref Build->Anchor = nil;			for(al := f.doc.anchors; al != nil; al = tl al) {				a = hd al;

Lines 1–500 of 2171.