implement Charon; include "common.m"; include "cci.m"; include "debug.m"; #####################international include "charon_gui.m"; include "charon_code.m"; sys: Sys; CU: CharonUtils; ByteSource, MaskedImage, CImage, ImageCache, ReqInfo, Header, ResourceState, config, max, min: import CU; D: Draw; Point, Rect, Font, Image, Display, Screen: import D; charon_gui: Charon_gui; charon_code: Charon_code; 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; cci: CCI; G: Gui; popupwin, grabmouse : import G; C : Ctype; include "sh.m"; # package up info related to a navigation command GoSpec: 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, GoBookmarks, GoHome, GoHelp, GoHistory, GoSettext: con iota; # Information about a set of frames making up the screen DocConfig: 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 configuration HistNode: 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 strings AuthInfo: adt { realm: string; credentials: string; }; auths: list of ref AuthInfo = nil; CtlLayout: adt { logoicon: ref Image; logopos: Point; butspos: Point; entrypos: Point; statuspos: Point; controls: list of ref Control; backbut: ref Control; fwdbut: ref Control; reloadbut: ref Control; stopbut: ref Control; histbut: ref Control; bmarkbut: ref Control; editbut: ref Control; confbut: ref Control; homebut: ref Control; helpbut: ref Control; copybut: ref Control; keybdbut: ref Control; exitbut: ref Control; entry: ref Control; status: string; flyover: string; }; ProgLayout: adt { box: array of ref Control; nused: int; first: Point; dx: int; sslpos: Point; sslstate: int; sslon: ref Image; ssloff: ref Image; }; PopupLayout: adt { kind: int; # PopupNone, PopupAuth, etc. controls: list of ref Control; okbut: ref Control; cancelbut: ref Control; refocus: ref Loc; # return focus here when popup done }; lock : adt { count: int; ack: chan of int; }; claimc : chan of ref lock; releasec : chan of ref lock; popuplock : ref lock; PopupNone, PopupAuth, PopupSaveAs, PopupEditBookmarks, PopupConfig, PopupAlert, PopupConfirm, PopupPrompt: con iota; popupans: chan of (int, string); popupactive := 0; # list action for edit bookmarks CLmoveup, CLmovedown, CLdelete, CLadd: con iota; history : ref History; ctllay: CtlLayout; proglay: ProgLayout; popuplay: PopupLayout; keyfocus: ref Loc; mouseover: ref B->Anchor; mouseoverfr: ref Frame; CTLHEIGHT : con 65; # height of control (menu and toolbar) window PROGHEIGHT : con 24; # height of progress window ALERTLINELEN: con 80; # max number of characters in an alert line SP : con 8; # a spacer for between controls SP2 : con 4; # half of SP SP3 : con 2; pgrp := 0; gopgrp := 0; dbg := 0; warn := 0; dbgres := 0; doscripts := 0; top, curframe, ctlframe, progframe, popupframe: ref Frame; mainwin, ctlwin, progwin: ref Image; zp := Point(0,0); tbw, tbr: chan of string; usetoolbar: int = 0; toolbarinit(ctxt: ref Draw->Context, argv: list of string, wc, rc: chan of string) { sys = load Sys Sys->PATH; if(ctxt != nil && wc != nil && rc != nil) { if ((sys->bind(Gui->GUITBPATH, Gui->GUIWMPATH, Sys->MREPL)) < 0) sys->print("failed to bind %s over %s\n", Gui->GUITBPATH, Gui->GUIWMPATH); usetoolbar = 1; } # else ignore toolbar tbw = wc; tbr = rc; # append exec name argv = Charon->PATH :: argv; init(ctxt, argv); } init(ctxt: ref Draw->Context, argl: list of string) { sys = load Sys Sys->PATH; (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); exc := ref sys->Exception; # if(sys->rescue("*", exc) == sys->EXCEPTION) { # if(exc.name == "") # sys->rescued(sys->EXIT, nil); # sys->print("exception %s, in module %s, %s", # exc.name, exc.mod, pctoloc(exc.mod, exc.pc)); # sys->rescued(sys->RAISE, nil); # fatalerror(sys->sprint("exception %s, in module %s, %s", # exc.name, exc.mod, pctoloc(exc.mod, exc.pc))); # } CU = load CharonUtils CharonUtils->PATH; if(CU == nil){ estr := sys->sprint("EXInternal: couldn't load CharonUtils: %r"); if(len estr > Sys->ERRLEN) estr = estr[:Sys->ERRLEN]; sys->raise(estr); } ech := chan of ref Event; errpath := CU->init(load Charon SELF, CU, argl, ctxt!=nil, ech); if(errpath != "") fatalerror(sys->sprint("Couldn't load %s\n", errpath)); #####################international charon_gui= load Charon_gui Charon_gui->PATH; if(charon_gui==nil) CU->raise(sys->sprint("EXinternal:couldn't load Charon_gui:%r")); charon_gui->init(); charon_code= load Charon_code Charon_code->PATH; if(charon_code==nil) CU->raise(sys->sprint("EXinternal:couldn't load Charon_code:%r")); charon_code->init(); 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; claimc = chan of ref lock; releasec = chan of ref lock; popuplock = ref lock(0, chan of int); 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; showprog := (CU->config).showprogress; 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(); } x := config.x; y := config.y; rctl := Rect((x,y), (x+config.defaultwidth,y+CTLHEIGHT)); rmain := Rect((x,y+CTLHEIGHT), (x+config.defaultwidth, y+config.defaultheight)); rprog := Rect((x,rmain.max.y),(x+config.defaultwidth,rmain.max.y)); if(showprog) { rmain.max.y -= PROGHEIGHT; rprog.min.y -= PROGHEIGHT; } if(usetoolbar) (rmain, rctl, rprog) = G->tbinit(ctxt, tbw, tbr, rmain, rctl, rprog, CU); else (rmain, rctl, rprog) = G->init(ctxt, rmain, rctl, rprog, CU); if(dbgres) { newres = ResourceState.cur(); newres.since(curres).print("difference after G->init (made screen windows)"); curres = newres; } mainwin = G->mainwin; ctlwin = G->ctlwin; progwin = G->progwin; # 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; } if(dbgres) { newres = ResourceState.cur(); newres.since(curres).print("difference after I->init"); curres = newres; } (CU->imcache).init(); if(ctxt == nil) start(1); else { if(usetoolbar) tbstart(1); else start(ctxt==nil); } if((CU->config).docookies > 0) CU->ReadCookies(); if(J != nil) J->frametreechanged(top); startpage := config.starturl; g := GoSpec.newget(GoNormal, startpage, "_top"); if(showprog) spawn progressmon(); if(dbgres) { newres = ResourceState.cur(); newres.since(curres).print("difference after initial configure"); curres = newres; } if(config.usecci) { cci = load CCI CCI->PATH; if(cci != nil) cci->init(S, E, U); } spawn plumbwatch(); spawn go(g); Forloop: for(;;) { ev : ref E->Event; l : ref lock; alt { l = <- claimc => if (l.count++ == 0) l.ack <- = 1; continue; l = <- releasec => if (--l.count > 0) l.ack <- = 1; continue; 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); g = nil; E->Kup => curframe.yscroll(L->CAscrollpage, 1); g = nil; E->Khome => curframe.yscroll(L->CAscrollpage, -10000); g = nil; E->Kend => curframe.yscroll(L->CAscrollpage, 10000); g = nil; E->Kaup => curframe.yscroll(L->CAscrollline, -1); g = nil; E->Kadown => curframe.yscroll(L->CAscrollline, 1); g = nil; * => g = handlekey(e); } Emouse => g = handlemouse(ctxt, e); Ereshape => mainwin = G->mainwin; ctlwin = G->ctlwin; progwin = G->progwin; if(usetoolbar) tbredrawctl(1); else redrawctl(1); redrawmain(1); tbredrawprog(1); curframe = top; g = GoSpec.newspecial(GoHistnode, history.find(0)); Eexpose => g = nil; Ehide => g = nil; Ehelp => g = GoSpec.newspecial(GoHelp, nil); Elower => if(popupactive) finishpopup(0); g = nil; Equit => break Forloop; Estop => if(gopgrp != 0) stop(); g = nil; Ealert => spawn alert(e.msg, e.sync); g = nil; Econfirm => spawn confirm(e.msg, e.sync); g = nil; Eprompt => spawn prompt(e.msg, e.inputdflt, e.sync); g = nil; 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 => g = GoSpec.newget(GoNormal, U->makeurl(e.url), e.target); E->EGreplace => g = GoSpec.newget(GoReplace, U->makeurl(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->EGhome => g = GoSpec.newspecial(GoHome, nil); E->EGbookmarks => g = GoSpec.newspecial(GoBookmarks, nil); 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; Eframefocus => f := findframe(top, e.frameid); if (f != nil) { loc : ref Loc; curf := keyfocus.lastframe(); if (e.focus && f != curf) loc = frameloc(nil, f); if (!e.focus && f == curf) { if (f.parent != nil) loc = frameloc(nil, f.parent); else loc = frameloc(nil, ctlframe); } if (loc != nil) setfocus(loc); } g = nil; Esettext => f := findframe(top, e.frameid); if (f != nil) g = ref GoSpec (GoSettext, e.url, 0, e.text, f.name, "", nil); } if(g != nil) { if (g.kind != GoSettext && g.url != nil && g.url.scheme == Url->JAVASCRIPT) { if (doscripts) spawn dojsurl(g); continue; } if(gopgrp != 0) stop(); if(g.url != nil && g.url.scheme == Url->MAILTO) { sdest := g.url.tostring(); showstatus(charon_gui->iRedirEmail + sdest, 0); mailto := "-m" + sdest[7:]; if(usetoolbar) tbw <-= "redirect EMAIL ; " + mailto; else { mailtool := load Command "/dis/wm/mailtool.dis"; if(mailtool != nil) { args := "mailtool" :: mailto :: nil; spawn mkprog(mailtool, ctxt, args); mailtool = nil; } else showstatus(charon_gui->iFailMail, 0); } } else 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); } claim(l : ref lock) { claimc <- = l; <- l.ack; } release(l : ref lock) { releasec <- = l; } start(needexit: int) { top = Frame.new(); ctlframe = Frame.new(); # not really a frame, but need cim pointer progframe = Frame.new(); # ditto popupframe = Frame.new(); # ditto curframe = top; history = ref History(nil, 0, 0); (ctllay.logoicon, nil) = G->geticon(G->IClogo); (iback, ibackm) := G->geticon(G->ICback); #####################international ctllay.backbut = Control.newbutton(ctlframe,iback,ibackm,charon_gui->iGoBack,nil,1,1); (ifwd, ifwdm) := G->geticon(G->ICfwd); ctllay.fwdbut = Control.newbutton(ctlframe, ifwd, ifwdm, charon_gui->iGoForward, nil, 1, 1); (ireload, ireloadm) := G->geticon(G->ICreload); ctllay.reloadbut = Control.newbutton(ctlframe, ireload, ireloadm, charon_gui->iReload, nil, 1, 1); (istop, istopm) := G->geticon(G->ICstop); ctllay.stopbut = Control.newbutton(ctlframe, istop, istopm, charon_gui->iStop, nil, 1, 1); (ihist, ihistm) := G->geticon(G->IChist); ctllay.histbut = Control.newbutton(ctlframe, ihist, ihistm, charon_gui->iHistory, nil, 1, 1); (ibmark, ibmarkm) := G->geticon(G->ICbmark); ctllay.bmarkbut = Control.newbutton(ctlframe, ibmark, ibmarkm, charon_gui->iShowBookmarks, nil, 1, 1); (iedit, ieditm) := G->geticon(G->ICedit); ctllay.editbut = Control.newbutton(ctlframe, iedit, ieditm, charon_gui->iEditBookmarks, nil, 1, 1); (iconf, iconfm) := G->geticon(G->ICconf); ctllay.confbut = Control.newbutton(ctlframe, iconf, iconfm, charon_gui-> iConfig, nil, 1, 1); (ihome, ihomem) := G->geticon(G->IChome); ctllay.homebut = Control.newbutton(ctlframe, ihome, ihomem, charon_gui->iHomePage,nil, 1, 1); (ihelp, ihelpm) := G->geticon(G->IChelp); ctllay.helpbut = Control.newbutton(ctlframe, ihelp, ihelpm, charon_gui->iHelp, nil, 1, 1); ctllay.controls = nil; if(needexit) { (iexit, iexitm) := G->geticon(G->ICexit); ctllay.exitbut = Control.newbutton(ctlframe, iexit, iexitm, charon_gui->iExit, nil, 1, 1); ctllay.controls = ctllay.exitbut :: nil; } else ctllay.exitbut = nil; ctllay.entry = Control.newentry(ctlframe, 30, 1, 0); ctllay.controls = ctllay.backbut :: ctllay.fwdbut :: ctllay.reloadbut :: ctllay.stopbut :: ctllay.homebut :: ctllay.histbut :: ctllay.bmarkbut :: ctllay.editbut :: ctllay.confbut :: ctllay.helpbut :: ctllay.entry :: ctllay.controls; ctllay.backbut.disable(); ctllay.fwdbut.disable(); ctllay.stopbut.disable(); ctllay.status = ""; keyfocus = frameloc(ctllay.entry, ctlframe); mouseover = nil; ctllay.entry.gainfocus(0); popuplay.kind = PopupNone; popupans = chan of (int, string); (proglay.sslon, nil) = G->geticon(G->ICsslon); (proglay.ssloff, nil) = G->geticon(G->ICssloff); redrawctl(1); redrawmain(1); tbredrawprog(1); } redrawctl(resized: int) { ctlwin.clipr = ctlwin.r; r := ctlwin.r.inset(L->ReliefBd); L->drawfill(ctlwin, r, CU->Grey); L->drawrelief(ctlwin, r, L->ReliefRaised); ctlwin.clipr = r; n := 0; p := ctllay.logopos; li := ctllay.logoicon; lw := li.r.dx(); lh := li.r.dy(); conter := 0; if(resized) { ctlframe.r = ctlwin.r.inset(2*L->ReliefBd); ctlframe.cr = ctlframe.r; ctlframe.cim = ctlwin; p = r.min.add(Point(7,7)); ctllay.logopos = p; x := p.x + lw; y := p.y; x += SP; x1 := x; y1 := y; for(bl := ctllay.controls; bl != nil; bl = tl bl) { b := hd bl; if(b == ctllay.entry || b == ctllay.exitbut) continue; b.r = b.r.subpt(b.r.min); b.r = b.r.addpt(Point(x,y)); if(conter == 4) { x = x1; y += b.r.dx() + SP3; } else { x += b.r.dx() + SP2; } conter++; } x += SP2; ctllay.entrypos = Point(x,y1); ctllay.entry.r = Rect(ctllay.entrypos, Point(r.max.x-7,y1+22)); ctllay.statuspos = Point(x,y+SP); if(ctllay.exitbut != nil) { ctllay.entry.r.max.x -= ctllay.exitbut.r.dx() + SP2; ctllay.exitbut.r = ctllay.exitbut.r.addpt(Point(ctllay.entry.r.max.x+SP2,y1)); } } #ctllay.statuspos = Point(p.x + lw + SP, p.y + (hd ctllay.controls).r.dy() + SP); ctlwin.draw(Rect(p,p.add(Point(lw,lh))), li, nil, zp); for(bl := ctllay.controls; bl != nil; bl = tl bl) (hd bl).draw(0); showstatus(ctllay.status, 0); ctlwin.flush(D->Flushnow); } tbstart(nil: int) # parameter is: needexit { top = Frame.new(); ctlframe = Frame.new(); # not really a frame, but need cim pointer progframe = Frame.new(); # ditto popupframe = Frame.new(); # ditto curframe = top; history = ref History(nil, 0, 0); (ctllay.logoicon, nil) = G->geticon(G->IClogo); (iback, ibackm) := G->geticon(G->ICback); ctllay.backbut = Control.newbutton(ctlframe, iback, ibackm, charon_gui->iGoBack, nil, 1, 1); (ifwd, ifwdm) := G->geticon(G->ICfwd); ctllay.fwdbut = Control.newbutton(ctlframe, ifwd, ifwdm, charon_gui->iGoForward, nil, 1, 1); (ireload, ireloadm) := G->geticon(G->ICreload); ctllay.reloadbut = Control.newbutton(ctlframe, ireload, ireloadm, charon_gui->iReload, nil, 1, 1); (istop, istopm) := G->geticon(G->ICstop); ctllay.stopbut = Control.newbutton(ctlframe, istop, istopm, charon_gui->iStop, nil, 1, 1); (ihist, ihistm) := G->geticon(G->IChist); ctllay.histbut = Control.newbutton(ctlframe, ihist, ihistm, charon_gui->iHistory, nil, 1, 1); (ibmark, ibmarkm) := G->geticon(G->ICbmark); ctllay.bmarkbut = Control.newbutton(ctlframe, ibmark, ibmarkm, charon_gui->iShowBookmarks, nil, 1, 1); (iedit, ieditm) := G->geticon(G->ICedit); ctllay.editbut = Control.newbutton(ctlframe, iedit, ieditm, charon_gui->iEditBookmarks, nil, 1, 1); (iconf, iconfm) := G->geticon(G->ICconf); ctllay.confbut = Control.newbutton(ctlframe, iconf, iconfm, charon_gui->iConfig, nil, 1, 1); (ihome, ihomem) := G->geticon(G->IChome); ctllay.homebut = Control.newbutton(ctlframe, ihome, ihomem, charon_gui->iHomePage,nil, 1, 1); (ihelp, ihelpm) := G->geticon(G->IChelp); ctllay.helpbut = Control.newbutton(ctlframe, ihelp, ihelpm, charon_gui->iHelp, nil, 1, 1); (icopy, icopym) := G->geticon(G->ICcopy); ctllay.copybut = Control.newbutton(ctlframe, icopy, icopym, charon_gui->iCopyLoc, nil, 1, 1); ctllay.controls = nil; (ikbd, ikbdm) := G->geticon(G->ICkeybd); ctllay.keybdbut = Control.newbutton(ctlframe, ikbd, ikbd, charon_gui->iSoftKeyboard, nil, 1, 1); ctllay.entry = Control.newentry(ctlframe, 30, 1, 0); ctllay.controls = ctllay.backbut :: ctllay.fwdbut :: ctllay.reloadbut :: ctllay.stopbut :: ctllay.homebut :: ctllay.keybdbut :: ctllay.histbut :: ctllay.bmarkbut :: ctllay.editbut :: ctllay.confbut :: ctllay.helpbut :: ctllay.copybut :: ctllay.entry :: ctllay.controls; ctllay.backbut.disable(); ctllay.fwdbut.disable(); ctllay.stopbut.disable(); ctllay.status = ""; keyfocus = frameloc(ctllay.entry, ctlframe); ctllay.entry.gainfocus(0); popuplay.kind = PopupNone; popupans = chan of (int, string); (proglay.sslon, nil) = G->geticon(G->ICsslon); (proglay.ssloff, nil) = G->geticon(G->ICssloff); tbredrawctl(1); redrawmain(1); tbredrawprog(1); } tbredrawctl(resized: int) { ctlwin.clipr = ctlwin.r; r := ctlwin.r.inset(L->ReliefBd); L->drawfill(ctlwin, r, CU->Grey); L->drawrelief(ctlwin, r, L->ReliefRaised); ctlwin.clipr = r; p := r.min; li := ctllay.logoicon; lw := 0; lh := 0; stat := 0; cont := 0; if(!usetoolbar) { p = ctllay.logopos; lw = li.r.dx(); lh = li.r.dy(); } if(resized) { ctlframe.r = ctlwin.r.inset(2*L->ReliefBd); ctlframe.cim = ctlwin; if(!usetoolbar) p = r.min.add(Point(7,7)); ctllay.logopos = p; x := p.x + lw; y := p.y + SP2; x += SP; x2 := x; for(bl := ctllay.controls; bl != nil; bl = tl bl) { b := hd bl; if(b == ctllay.entry || b == ctllay.exitbut) continue; b.r = b.r.subpt(b.r.min); b.r = b.r.addpt(Point(x,y)); if (cont == 3) { x += 20; # stat = x + 30 + SP2; } if (cont == 5) { stat = x; x = x2 - 28; y = p.y + b.r.dy() + SP2; } if (cont == 9) x += 20; cont += 1; x += b.r.dx() + SP2; } x += SP2; x = r.max.x - 7; ctllay.entrypos = Point(stat + 49, y-23); ctllay.entry.r = Rect(ctllay.entrypos, Point(r.max.x-25,y)); ctllay.statuspos = Point(stat + 49 , y+SP); } if(!usetoolbar) ctlwin.draw(Rect(p,p.add(Point(lw,lh))), li, nil, zp); for(bl := ctllay.controls; bl != nil; bl = tl bl){ (hd bl).draw(0); } showstatus(ctllay.status, 0); ctlwin.flush(D->Flushnow); } redrawmain(resized: int) { im := mainwin; if(resized) { top.r = im.r.inset(2*L->ReliefBd); 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); im.clipr = top.r; L->drawfill(im, top.r, CU->White); im.flush(D->Flushnow); } tbredrawprog(resized: int) { if (progwin == nil) return; progwin.clipr = progwin.r; r := progwin.r.inset(L->ReliefBd); L->drawfill(progwin, r, CU->Grey); L->drawrelief(progwin, r, L->ReliefRaised); progwin.clipr = r; p := proglay.sslpos; si : ref Image; if(proglay.sslstate) si = proglay.sslon; else si = proglay.ssloff; sw := si.r.dx(); sh := si.r.dy(); if(resized) { #p := proglay.first; nbox := len proglay.box; progframe.r = progwin.r.inset(2*L->ReliefBd); progframe.cr = progframe.r; progframe.cim = progwin; nboxold := nbox; c := Control.newprogbox(progframe); vo := (r.dy() - c.r.dy()) / 2; p = r.min.add(Point(7,vo)); proglay.sslpos = p; proglay.first = Point(p.x + sw + SP, p.y); proglay.dx = c.r.dx() + SP2; nbox = (r.dx() - 2*7 - SP2 - sw - SP) / proglay.dx; if(nboxold != nbox) { newbox := array[nbox] of ref Control; if(nboxold > 0) { if(nboxold > nbox) newbox[0:] = proglay.box[0:nbox]; else { newbox[0:] = proglay.box; } } proglay.box = newbox; proglay.nused = min(proglay.nused, len proglay.box); for(i := nboxold; i < nbox; i++) proglay.box[i] = Control.newprogbox(progframe); } for(i := 0; i < nbox; i++) { c = proglay.box[i]; c.r = c.r.subpt(c.r.min); c.r = c.r.addpt(Point(p.x+i*proglay.dx + sw + SP, p.y)); } } progwin.draw(Rect(p,p.add(Point(sw,sh))), si, nil, zp); for(i := 0; i < proglay.nused; i++) proglay.box[i].draw(0); progwin.flush(D->Flushnow); } # Display popup of given kind (s & s2 are more info for drawing, depending on kind), # and return user's answer on popupans as (code, string), where code will # be -1 for error, 0 when the user hit cancel, and 1 when the user hit OK. dopopup(kind: int, s, s2: string) : int { claim(popuplock); if (popupactive) { popupans <- = (-1, ""); popupactive = 0; } cok := Control.newbutton(popupframe, nil, nil, charon_gui->iOk, nil, 1,1); ccancel := Control.newbutton(popupframe, nil, nil, charon_gui->iCancel,nil, 1, 1); p := Point(0,0); case kind { PopupAuth => chead := Control.newlabel(popupframe, "Type your user name and password"); crealm := Control.newlabel(popupframe, "Resource: " + s); cunlab := Control.newlabel(popupframe, "User Name: "); cpwlab := Control.newlabel(popupframe, "Password: "); cuser := Control.newentry(popupframe, 30, 1, 0); cpass := Control.newentry(popupframe, 30, 1, 0); w := SP + max(chead.r.max.x, max(crealm.r.max.x, cunlab.r.max.x + cuser.r.max.x)) + SP; w = min(w, mainwin.r.dx()-2*SP); h := SP + chead.r.max.y + SP + crealm.r.max.y + SP + cuser.r.max.y + SP + cpass.r.max.y + 2*SP + cok.r.max.y + SP; popupwin = G->makepopup(w, h); if(popupwin == nil) { release(popuplock); return -1; } # put user, password entries at beginning of list for easy access popuplay.controls = cuser :: cpass :: chead :: crealm :: cunlab :: cpwlab :: cok :: ccancel :: nil; p = popupwin.r.min.add(Point(SP,SP)); chead.r = chead.r.addpt(p); p.y += chead.r.dy() + SP; crealm.r = crealm.r.addpt(p); p.y += crealm.r.dy() + SP; cunlab.r = cunlab.r.addpt(p); cuser.r = cuser.r.addpt(p.add(Point(cunlab.r.dx(),0))); p.y += cuser.r.dy() + SP; cpwlab.r = cpwlab.r.addpt(p); cpass.r = cuser.r.addpt(Point(0,cuser.r.dy()+SP)); p.y += cpass.r.dy() + 2*SP; pick cinit := cpass { Centry => cinit.flags |= L->CFsecure; } PopupSaveAs => clab := Control.newlabel(popupframe, "Save As: "); cfile := Control.newentry(popupframe, 40, 1, 0); pick ce := cfile { Centry => ce.s = s; } w := SP + clab.r.max.x + cfile.r.max.x + SP; h := SP + cfile.r.max.y + 2*SP + cok.r.max.y + SP; popupwin = G->makepopup(w, h); if(popupwin == nil) { release(popuplock); return -1; } popuplay.controls = cfile :: clab :: cok :: ccancel :: nil; p = popupwin.r.min.add(Point(SP,SP)); clab.r = clab.r.addpt(p); cfile.r = cfile.r.addpt(p.add(Point(clab.r.dx()+SP,0))); p.y += clab.r.dy() + 2*SP; # PopupAlert/PopupConfirm/PopupPrompt similar # PopupConfirm adds Cancel button to PopupAlert # PopupPrompt adds Entry field to PopupConfirm PopupAlert or PopupConfirm or PopupPrompt => rows : list of string = nil; (nl, lines) := sys->tokenize(s, "\n"); for (; lines != nil; lines = tl lines) { line := hd lines; # split line up into rows of at most ALERTLINELEN characters each (n, words) := sys->tokenize(line, " \t\r"); curlen := 0; currow := ""; for( ; words != nil; words = tl words) { w := hd words; nw := len w; if(curlen + nw >= ALERTLINELEN && currow != "") { rows = currow :: rows; currow = w; curlen = nw; } else { if(currow != "") { currow += " "; curlen++; } currow += w; curlen += nw; } } if(currow != "") rows = currow :: rows; } # rows are in reverse order, so the following # puts the controls in the correct order popuplay.controls = nil; w := SP + cok.r.max.x + SP; if(kind == PopupAlert) ccancel = nil; else w += ccancel.r.max.x + SP; h := SP + 2*SP + cok.r.max.y + SP; for(; rows != nil; rows = tl rows) { l := hd rows; c := Control.newlabel(popupframe, l); popuplay.controls = c :: popuplay.controls; w = max(w, SP + c.r.dx() + SP); h += c.r.dy(); } cinput : ref Control; if(kind == PopupPrompt) { cinput = Control.newentry(popupframe, 40, 1, 0); pick ce := cinput { Centry => ce.s = s2; ce.sel = (len s2, len s2); } w = max(w, SP + cinput.r.dx() + SP); h += cinput.r.dy() + SP; } popupwin = G->makepopup(w, h); if(popupwin == nil) { release(popuplock); return -1; } p = popupwin.r.min.add(Point(SP,SP)); for(cl := popuplay.controls; cl != nil; cl = tl cl) { c := hd cl; c.r = c.r.addpt(p); p.y += c.r.dy(); } if(kind == PopupPrompt) { p.y += SP; cinput.r = cinput.r.addpt(p); p.y += cinput.r.dy(); } p.y += 2*SP; if(kind != PopupAlert) popuplay.controls = ccancel :: popuplay.controls; popuplay.controls = cok :: popuplay.controls; if(kind == PopupPrompt) popuplay.controls = cinput :: popuplay.controls; PopupEditBookmarks => chead := Control.newlabel(popupframe, charon_gui->iEditBookmarks); (iup, iupm) := G->geticon(G->ICup); cmoveup := Control.newbutton(popupframe, iup, iupm, charon_gui->iMoveupButton, nil, 1, 1); (idown, idownm) := G->geticon(G->ICdown); cmovedown := Control.newbutton(popupframe, idown, idownm, charon_gui->iMovedownButton, nil, 1, 1); (idel, idelm) := G->geticon(G->ICminus); cdelete := Control.newbutton(popupframe, idel, idelm, charon_gui->iDeleteButton, nil, 1, 1); (iadd, iaddm) := G->geticon(G->ICplus); cadd := Control.newbutton(popupframe, iadd, iaddm, charon_gui->iAddButton, nil, 1, 1); options: array of B->Option; fname := config.userdir + "/bookmarks.html"; fd := sys->open(fname, sys->OREAD); if(fd != nil) { buf := array [8192] of byte; nbyte := 0; while((nr := sys->read(fd, buf[nbyte:], len buf-nbyte)) > 0){ nbyte += nr; if(nbyte == len buf) buf = (array[len buf+8192] of byte)[0:] = buf; } if(nbyte <= 0) options = nil; else options = parsebookmarks(buf[0:nbyte]); } if(options != nil && len options != 0) options[0].selected = 1; clist := Control.newlistbox(popupframe, 8, 25, options); ctitlelab := Control.newlabel(popupframe, charon_gui->iTitleLabel); curllab := Control.newlabel(popupframe, charon_gui->iUrlLabel); ctitle := Control.newentry(popupframe, 21, 1, 0); curl := Control.newentry(popupframe, 21, 1, 0); xp := clist.r.max.x + SP; w := SP + xp + SP + cmovedown.r.max.x + SP; h := SP + chead.r.max.y + SP + clist.r.max.y + SP + ctitle.r.max.y + SP + curl.r.max.y + 2*SP + cok.r.max.y + SP; popupwin = G->makepopup(w, h); if(popupwin == nil) { release(popuplock); return -1; } popuplay.controls = clist :: ctitle :: curl :: cmoveup :: cmovedown :: cdelete :: cadd :: cok :: ccancel :: chead :: ctitlelab :: curllab :: nil; p = popupwin.r.min.add(Point(SP, SP)); chead.r = chead.r.addpt(p); p.y += chead.r.dy() + SP; clist.r = clist.r.addpt(p); xp += SP; cmoveup.r = cmoveup.r.addpt(p.add(Point(xp, 0))); yp := cmoveup.r.dy() + SP; cdelete.r = cdelete.r.addpt(p.add(Point(xp, yp))); yp += cdelete.r.dy() + SP; cmovedown.r = cmovedown.r.addpt(p.add(Point(xp, yp))); p.y += clist.r.dy() + SP; ctitlelab.r = ctitlelab.r.addpt(p); ctitle.r = ctitle.r.addpt(p.add(Point(ctitlelab.r.dx(), 0))); p.y += ctitle.r.dy() + SP; curllab.r = curllab.r.addpt(p); curl.r = curl.r.addpt(p.add(Point(curllab.r.dx(), 0))); cadd.r = cadd.r.addpt(p.add(Point(xp, 0))); p.y += curl.r.dy() + 2*SP; if(history != nil && history.h != nil) { root := history.h[history.n-1].topconfig; pick c := ctitle { Centry => c.s = root.title; } pick c := curl { Centry => c.s = root.gospec.url.tostring(); } } PopupConfig => chead := Control.newlabel(popupframe, charon_gui->iUserPreferences); cinfo := Control.newlabel(popupframe, charon_gui->iProxyCaption1); cinfo1 := Control.newlabel(popupframe, charon_gui->iProxyCaption2); cproxylab := Control.newlabel(popupframe, charon_gui->iProxyLabel); cproxy := Control.newentry(popupframe, 25, 1, 0); cportlab := Control.newlabel(popupframe, charon_gui->iPortLabel); cport := Control.newentry(popupframe, 5, 1, 0); cnoproxylab := Control.newlabel(popupframe, charon_gui->iNoproxyLabel); cnoproxy := Control.newentry(popupframe, 31, 1, 0); chomelab := Control.newlabel(popupframe, charon_gui->iHomepageLabel); chome := Control.newentry(popupframe, 33, 1, 0); cimglab := Control.newlabel(popupframe, charon_gui->iLoadimageLabel); cimg := Control.newcheckbox(popupframe, 0); cssllab := Control.newlabel(popupframe, charon_gui->iUseSSL); cv2lab := Control.newlabel(popupframe, charon_gui->iSSLV2); cv2 := Control.newcheckbox(popupframe, 0); cv3lab := Control.newlabel(popupframe, charon_gui->iSSLV3); cv3 := Control.newcheckbox(popupframe, 0); cjslab := Control.newlabel(popupframe, "JavaScript: "); cjs := Control.newcheckbox(popupframe, 0); w, h : int; w = SP + max(cinfo.r.max.x, max(cnoproxylab.r.max.x+cnoproxy.r.max.x, cproxylab.r.max.x+cproxy.r.max.x+cportlab.r.max.x+cport.r.max.x)) + SP; h = SP + chead.r.max.y + SP + cinfo.r.max.y + SP2 + cinfo1.r.max.y + SP + cproxy.r.max.y + SP + cnoproxy.r.max.y + SP + chome.r.max.y + SP + cimg.r.max.y + SP + cv2.r.max.y + SP + cok.r.max.y + 2*SP; if (J != nil) h += cjs.r.max.y + SP; popupwin = G->makepopup(w, h); if(popupwin == nil){ release(popuplock); return -1; } if (J != nil) popuplay.controls = cproxy :: cport :: cnoproxy :: chome :: cimg :: cv2 :: cv3 :: cjs :: cok :: ccancel :: chead :: cinfo :: cinfo1 :: cproxylab :: cportlab :: cnoproxylab :: chomelab :: cimglab :: cssllab :: cv2lab :: cv3lab :: cjslab :: nil; else popuplay.controls = cproxy :: cport :: cnoproxy :: chome :: cimg :: cv2 :: cv3 :: cok :: ccancel :: chead :: cinfo :: cinfo1 :: cproxylab :: cportlab :: cnoproxylab :: chomelab :: cimglab :: cssllab :: cv2lab :: cv3lab :: nil; p = popupwin.r.min.add(Point(SP, SP)); chead.r = chead.r.addpt(p); p.y += chead.r.dy() + SP; cinfo.r = cinfo.r.addpt(p); p.y += cinfo.r.dy(); cinfo1.r = cinfo1.r.addpt(p); p.y += cinfo1.r.dy() + SP; cproxylab.r = cproxylab.r.addpt(p); xp := cproxylab.r.dx(); cproxy.r = cproxy.r.addpt(p.add(Point(xp, 0))); xp += cproxy.r.dx(); cportlab.r = cportlab.r.addpt(p.add(Point(xp, 0))); xp += cportlab.r.dx(); cport.r = cport.r.addpt(p.add(Point(xp, 0))); p.y += cproxy.r.dy() + SP; cnoproxylab.r = cnoproxylab.r.addpt(p); cnoproxy.r = cnoproxy.r.addpt(p.add(Point(cnoproxylab.r.dx(), 0))); p.y += cnoproxy.r.dy() + SP; chomelab.r = chomelab.r.addpt(p); chome.r = chome.r.addpt(p.add(Point(chomelab.r.dx(), 0))); p.y += chome.r.dy() + SP; cimglab.r = cimglab.r.addpt(p); cimg.r = cimg.r.addpt(p.add(Point(cimglab.r.dx(), SP2))); p.y += cimg.r.dy() + SP; cssllab.r = cssllab.r.addpt(p); xp = cssllab.r.dx(); cv2lab.r = cv2lab.r.addpt(p.add(Point(xp, 0))); xp += cv2lab.r.dx(); cv2.r = cv2.r.addpt(p.add(Point(xp, SP2))); xp += cv2.r.dx() + SP; cv3lab.r = cv3lab.r.addpt(p.add(Point(xp, 0))); xp += cv3.r.dx() + SP; cv3.r = cv3.r.addpt(p.add(Point(xp, SP2))); if (J != nil) { p.y += cv2.r.dy() + SP; cjslab.r = cjslab.r.addpt(p); xp = cjslab.r.dx(); cjs.r = cjs.r.addpt(p.add(Point(xp, SP2))); } p.y += cjs.r.dy() + SP; pick cinit := cproxy { Centry => if(config.httpproxy != nil) cinit.s = config.httpproxy.host; } pick cinit := cport { Centry => if(config.httpproxy != nil) cinit.s = config.httpproxy.port; } pick cinit := cnoproxy { Centry => cinit.s = ""; doml := config.noproxydoms; while(doml != nil) { cinit.s += hd doml + ", "; doml = tl doml; } } pick cinit := chome { Centry => cinit.s = config.homeurl.tostring(); } if(!config.change_homeurl) chome.disable(); pick cinit := cimg { Ccheckbox => if(config.imagelvl == 0) cimg.flags &= ~L->CFactive; else cimg.flags |= L->CFactive; } pick v2 := cv2 { Ccheckbox => if(config.usessl & CU->SSLV2) v2.flags |= L->CFactive; else v2.flags &= ~L->CFactive; } pick v3 := cv3 { Ccheckbox => if(config.usessl & CU->SSLV3) v3.flags |= L->CFactive; else v3.flags &= ~L->CFactive; } pick js := cjs { Ccheckbox => if(config.doscripts) js.flags |= L->CFactive; else js.flags &= ~L->CFactive; } * => CU->assert(0); } # center the buttons on the bottom if(ccancel == nil) { p.x += (popupwin.r.dx() - cok.r.max.x) / 2 - SP; cok.r = cok.r.addpt(p); } else { p.x += (popupwin.r.dx() - (cok.r.max.x + SP + ccancel.r.max.x)) / 2 - SP; cok.r = cok.r.addpt(p); p.x += cok.r.dx() + SP; ccancel.r = ccancel.r.addpt(p); } popupframe.cim = popupwin; popupframe.cr = popupframe.r = popupwin.r; popuplay.kind = kind; popuplay.okbut = cok; popuplay.cancelbut = ccancel; popupactive = 1; popuplay.refocus = keyfocus; # oldc := keyfocus.le[keyfocus.n-1].control; # if(oldc != nil) { # popuplay.refocus = keyfocus; # oldc.losefocus(popupactive); # } # else # popuplay.refocus = nil; newc := hd popuplay.controls; setfocus(frameloc(newc, popupframe)); # newc.gainfocus(popupactive); redrawpopup(); # answer will be delivered from finishpopup release(popuplock); return 0; } redrawpopup() { if(popuplay.kind == PopupNone) return; CU->assert(popupwin != nil); popupwin.clipr = popupwin.r; r := popupwin.r.inset(L->ReliefBd); L->drawfill(popupwin, r, CU->Grey); L->drawrelief(popupwin, r, L->ReliefRaised); popupwin.clipr = r; for(cl := popuplay.controls; cl != nil; cl = tl cl) (hd cl).draw(0); popupwin.flush(D->Flushnow); } finishpopup(code: int) { str := ""; case popuplay.kind { PopupConfig => if(code == 1) { c := popuplay.controls; host := ctlentrytext(hd c); c = tl c; port := ctlentrytext(hd c); if(host == nil) config.httpproxy = nil; else config.httpproxy = CU->makeabsurl("http://" + host + ":" + port); c = tl c; (nil, config.noproxydoms) = sys->tokenize(ctlentrytext(hd c), ";, \t"); c = tl c; homeurl := ctlentrytext(hd c); if(homeurl != "") config.homeurl = CU->makeabsurl(homeurl); c = tl c; config.imagelvl = 0; # default pick cc := hd c { Ccheckbox => if(cc.flags&L->CFactive) config.imagelvl = CU->ImgFull; * => CU->assert(0); } c = tl c; pick v2 := hd c { Ccheckbox => if(v2.flags&L->CFactive) config.usessl |= CU->SSLV2; * => CU->assert(0); } c = tl c; pick v3 := hd c { Ccheckbox => if(v3.flags&L->CFactive) config.usessl |= CU->SSLV3; * => CU->assert(0); } if (J != nil) { c = tl c; pick js := hd c { Ccheckbox => config.doscripts = (js.flags & L->CFactive); doscripts = config.doscripts; * => CU->assert(0); } } fname := config.userdir + "/config"; if(CU->saveconfig(fname) < 0){ sys->print("can't save user config\n"); code = -1; } } PopupEditBookmarks => if(code == 1) { pick c := hd popuplay.controls { Clistbox => savebookmarks(c.options); } } PopupAuth => str = ctlentrytext(hd popuplay.controls) + ":" + ctlentrytext(hd (tl popuplay.controls)); PopupSaveAs or PopupPrompt => str = ctlentrytext(hd popuplay.controls); } popuplay.kind = PopupNone; popuplay.controls = nil; popuplay.okbut = nil; popuplay.cancelbut = nil; popupframe.cim = nil; popupwin = nil; setfocus(popuplay.refocus); # refocus := popuplay.refocus; # if(refocus != nil) { # keyfocus = refocus; # popuplay.refocus = nil; # oldc := keyfocus.le[keyfocus.n-1].control; # oldc.gainfocus(popupactive); # } popupactive = 0; popupans <-= (code, str); } # assuming c is an entry control, return its contents ctlentrytext(c: ref Control) : string { pick ec := c { Centry => return ec.s; * => CU->assert(0); } return ""; } # Return a Loc representing a control in the frame f frameloc(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; } # Frame oldf is being reset, so change keyfocus back to ctllay.entry resetkeyfocus(f: ref Frame) { # determine if focus is in frame f or one of its sub-frames if (keyfocus != nil) { for (focusf := keyfocus.lastframe(); focusf != nil; focusf = focusf.parent) if (focusf == f) break; if (focusf == nil) # current focus not in frameset being modified - leave as is return; } keyfocus = frameloc(ctllay.entry, ctlframe); ctllay.entry.gainfocus(0); } popupmouse(nil: ref Draw->Context, e: ref Event.Emouse, grab: ref Control) : (ref GoSpec, ref Control) { p := e.p; action : int; newgrab : ref Control; cindex := 0; for(cl := popuplay.controls; cl != nil; (cl, cindex) = (tl cl, cindex + 1)) { c := hd cl; if((c == grab) || (grab == nil && p.in(c.r))) { if(dbg > 1) sys->print("mouse in popup control\n"); (action, newgrab) = c.domouse(p, e.mtype, grab); case (action) { L->CAbuttonpush => if(c == popuplay.okbut) finishpopup(1); else if(c == popuplay.cancelbut) finishpopup(0); if(popuplay.kind == PopupEditBookmarks) { clist := hd popuplay.controls; # TODO: edit listbox case cindex { 3 => # move up ctllist(clist, CLmoveup, "", ""); 4 => # move down ctllist(clist, CLmovedown, "", ""); 5 => # delete ctllist(clist, CLdelete, "", ""); 6 => # add display, value: string; pick ctitle := hd tl popuplay.controls { Centry => display = ctlentrytext(ctitle); } pick curl := hd tl tl popuplay.controls { Centry => value = " HREF=" + ctlentrytext(curl) + " TARGET=_top"; } ctllist(clist, CLadd, value, display); } #clist.draw(1); } L->CAkeyfocus => if(dbg > 1) keyfocus.print("old focus"); setfocus(frameloc(c, popupframe)); if(dbg > 1) keyfocus.print("new focus"); } break; } } return (nil, newgrab); } controlmouse(ctxt : ref Draw->Context, e: ref Event.Emouse, grab : ref Control) : (ref GoSpec, ref Control) { p := e.p; g : ref GoSpec; action : int; newgrab : ref Control; flyover := 0; for(cl := ctllay.controls; cl != nil; cl = tl cl) { c := hd cl; if((c == grab) || (grab == nil && p.in(c.r))) { if(dbg > 1) sys->print("mouse in controlwin control\n"); (action, newgrab) = c.domouse(p, e.mtype, grab); case (action) { L->CAbuttonpush => if(c == ctllay.backbut) g = GoSpec.newspecial(GoHistnode, history.find(-1)); else if(c == ctllay.fwdbut) g = GoSpec.newspecial(GoHistnode, history.find(1)); else if(c == ctllay.reloadbut) g = GoSpec.newspecial(GoHistnode, history.find(0)); else if(c == ctllay.histbut) g = GoSpec.newspecial(GoHistory, nil); else if(c == ctllay.bmarkbut) g = GoSpec.newspecial(GoBookmarks, nil); else if(c == ctllay.stopbut) { if(gopgrp != 0) stop(); } else if(c == ctllay.editbut) spawn editbookmarks(); else if(c == ctllay.confbut) spawn doconfig(); else if(c == ctllay.homebut) g = GoSpec.newspecial(GoHome, nil); else if(c == ctllay.helpbut) g = GoSpec.newspecial(GoHelp, nil); else if(c == ctllay.copybut) { pick ce := ctllay.entry { Centry => s := ce.s; if(s != "") G->snarfput(s); } } else if(c == ctllay.keybdbut) { if(usetoolbar) { # handle software keyboard spawn G->skeyboard(ctxt); } } else if(c == ctllay.exitbut) finish(); L->CAflyover => flyover = 1; pick pc := c { Cbutton => showstatus(pc.label, 1); } L->CAkeyfocus => if(dbg > 1) keyfocus.print("old focus"); setfocus(frameloc(c, ctlframe)); if(dbg > 1) keyfocus.print("new focus"); } break; } } if (!flyover && ctllay.flyover != nil) showstatus("", 1); return (g, newgrab); } mainwinmouse(nil : ref Draw->Context, e: ref Event.Emouse, grab : ref Control) : (ref GoSpec, ref Control) { p := e.p; g : ref GoSpec; ctl : ref Control; newgrab : ref Control; action : int; domouseout := 0; loc : ref Loc; if(mouseover != nil) domouseout = 1; if (grab != nil) { ctl = grab; loc = grabloc; # fix-up loc.pos as mouse point relative to control origin loc.pos = p.sub(loc.le[loc.n-1].pos); } else { 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; if(a.index == it.anchorid) break; } if (al == nil) break; if(dbg > 1) sys->print("in anchor %d, href=%s\n", a.index, a.href.tostring()); if(doscripts && a.evmask) { if(a == mouseover) { domouseout = 0; # still over same anchor } else if(e.mtype == E->Mmove) { if(domouseout) { if(mouseover.evmask & E->SEonmouseout) { se := ref E->ScriptEvent(E->SEonmouseout, mouseoverfr.id, -1, -1, mouseover.index, -1, 0, 0, 0, nil, nil); J->jevchan <-= se; } domouseout = 0; } mouseover = a; mouseoverfr = f; if(a.evmask & E->SEonmouseover) { se := ref E->ScriptEvent(E->SEonmouseover, f.id, -1, -1, a.index, -1, e.p.x, e.p.y, 0, nil, nil); J->jevchan <-= se; } } if (e.mtype == E->Mlbuttonup || e.mtype == E->Mldrop) { if(a.evmask & E->SEonclick) { se := ref E->ScriptEvent(E->SEonclick, f.id, -1, -1, a.index, -1, 0, 0, 0, nil, nil); J->jevchan <-= se; break; } ctl = nil; } } if(e.mtype == E->Mlbuttonup || e.mtype == E->Mldrop) { g = anchorgospec(it, a, loc.pos); if (g == nil) break; } else if(e.mtype == E->Mmbuttonup) { g = anchorgospec(it, a, loc.pos); if (g == nil) break; showstatus(g.url.tostring(), 0); g = nil; } L->LEcontrol => ctl = loc.le[n1].control; } } } if (ctl != nil) { ev := E->SEnone; (action, newgrab) = ctl.domouse(p, e.mtype, grab); case (action) { L->CAbuttonpush => if(doscripts && ctl.ff != nil && ctl.ff.evmask) ev = E->SEonclick; else { pushaction(ctl, loc); g = nil; } L->CAkeyfocus => if(dbg > 1) keyfocus.print("old focus"); setfocus(loc); if(dbg > 1) keyfocus.print("new focus"); L->CAchanged => # Select Formfield - selection has changed ev = E->SEonchange; L->CAselected => # text input Formfield - text selection has changed ev = E->SEonselect; } 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); J->jevchan <-= se; return (nil, newgrab); } } if(newgrab == nil && domouseout && doscripts) { if(mouseover.evmask & E->SEonmouseout) { se := ref E->ScriptEvent(E->SEonmouseout, mouseoverfr.id, -1, -1, mouseover.index, -1, 0, 0, 0, nil, nil); J->jevchan <-= se; } mouseoverfr = nil; mouseover = nil; } if (newgrab != nil) grabloc = loc; return (g, newgrab); } dojsurl(g : ref GoSpec) { f := curframe; case g.target { "_top" => f = top; "_self" => ; # curframe is already OK "_parent" => if(f.parent != nil) f = f.parent; "_blank" => f = top; # we don't create new browsers... * => # this is recommended "current practice" f = findnamedframe(f, g.target); if(f == nil) { f = findnamedframe(top, g.target); if(f == nil) f = top; } } jev := ref E->ScriptEvent (E->SEscript, f.id, -1, -1, -1, -1, 0, 0, 0, g.url.path, chan of string); J->jevchan <-= jev; v := <- jev.reply; if (v != nil) { ev := ref Event.Esettext(f.id, g.url, v); E->evchan <-= ev; } } progwinmouse(nil : ref Draw->Context, e: ref Event.Emouse, grab : ref Control) : (ref GoSpec, ref Control) { action : int; p := e.p; newgrab : ref Control; for(i := 0; i < len proglay.box; i++) { c := proglay.box[i]; if((c == grab) || (grab == nil && p.in(c.r))) { if(dbg > 1) sys->print("mouse in progbox control %d\n", i); (action, newgrab) = c.domouse(p, e.mtype, grab); case (action) { L->CAbuttonpush => pick pc := c { Cprogbox => msg := sys->sprint("%s, %d%% done", pc.src, pc.pcnt); if(pc.err != "") msg += ", " + pc.err; if(dbg) msg += sys->sprint(", bsid=%d", pc.bsid); showstatus(msg, 0); } } } } return (nil, newgrab); } grabctl : ref Control; grabloc : ref Loc; grabrgn : int; Rpopup, Rcontrol, Rmainwin, Rprogwin : con iota; # If mouse event results in command to navigate somewhere else, # return a GoSpec ref, else nil. # TODO: deactivate activated controls if mouse leaves the area; # perhaps do grabs? handlemouse(ctxt : ref Draw->Context, e: ref Event.Emouse) : ref GoSpec { newgrab : ref Control; p := e.p; g : ref GoSpec = nil; if (popupactive) { (g, newgrab) = popupmouse(ctxt, e, grabctl); grabrgn = Rpopup; } else if((grabctl == nil && p.in(ctlwin.r)) || (grabctl != nil && grabrgn == Rcontrol)) { (g, newgrab) = controlmouse(ctxt, e, grabctl); grabrgn = Rcontrol; } else if(grabctl == nil && (p.in(mainwin.r)) || (grabctl != nil && grabrgn == Rmainwin)) { (g, newgrab) = mainwinmouse(ctxt, e, grabctl); grabrgn = Rmainwin; if (ctllay.flyover != nil) showstatus("", 1); } else if((grabctl == nil && progwin != nil && p.in(progwin.r)) || (grabctl != nil && grabrgn == Rprogwin)) { (g, newgrab) = progwinmouse(ctxt, e, grabctl); grabrgn = Rprogwin; if (ctllay.flyover != nil) showstatus("", 1); } if (grabctl != newgrab) grabmouse(newgrab != nil); grabctl = newgrab; # turn off animation flushes while a control has grabbed the mouse # (helps stop screen flashing while scrolling) if (grabctl != nil) CU->flushanim = 0; else CU->flushanim = 1; return g; } setfocus(newloc : ref Loc) { # Navigator behaviour - something like... # blur loc chain of original frame # restore loc chain of new frame # blur original focus element of new frame # set focus to new element of new frame # It's not worth trying to reproduce this scheme. # just do something sensible... if (keyfocus == nil) keyfocus = newloc; oldf := keyfocus.lastframe(); newf := newloc.lastframe(); oldc := keyfocus.le[keyfocus.n-1].control; newc := newloc.le[newloc.n-1].control; if (oldf == newf && oldc == newc) return; if (oldc != nil) oldc.losefocus(1); if (oldf != newf) { oldf.focus(0, 1); newf.focus(1, 1); } if (newc != nil) { if (oldf != newf) newf.focus(0, 1); newc.gainfocus(1); } keyfocus = newloc; } editbookmarks() { (code, ans) := (-1, ""); if (dopopup(PopupEditBookmarks, "", "") != -1) (code, ans) = <-popupans; if(code == -1) sys->print("couldn't create popup window\n"); else { # modify bookmarks } } doconfig() { (code, ans) := (-1, ""); if (dopopup(PopupConfig, "", "") != -1) (code, ans) = <-popupans; if(code == -1) sys->print("couldn't create popup window\n"); else { # modify config data } } ctllist(sc: ref Control, action: int, value, display: string) { changed := 0; pick c := sc { Clistbox => case action { CLmoveup => for(i := 0; i < len c.options; i++) { if(c.options[i].selected == 1) { if(i != 0) { changed = 1; swapopt(c.options, i-1, i); } break; } } CLmovedown => for(i := 0; i < len c.options; i++) { if(c.options[i].selected == 1) { if(i != (len c.options - 1)) { changed = 1; swapopt(c.options, i, i+1); } break; } } CLdelete => if(c.options == nil){ c.first = 0; return; } n := len c.options; if(n <= 1) { c.options = nil; } else { nopt := array[n-1] of B->Option; i, found, sel : int = 0; for(; i < n; i++) { if(c.options[i].selected == 1){ sel = i; found = 1; break; } else { nopt[i].selected = 0; nopt[i].value = c.options[i].value; nopt[i].display = c.options[i].display; } } for(; i < n-1; i++) { nopt[i].selected = 0; nopt[i].value = c.options[i+1].value; nopt[i].display = c.options[i+1].display; } if(found && n > 1) { if(sel < n-1) nopt[sel].selected = 1; else nopt[n-2].selected = 1; } c.options = nopt; } changed = 1; CLadd => n := len c.options; nopt := (array[n+1] of B->Option)[0:] = c.options; for(i := 0; i < n; i++) nopt[i].selected = 0; nopt[n].selected = 1; nopt[n].value = value; nopt[n].display = display; c.options = nopt; if(n+1 <= c.nvis) c.first = 0; else c.first = n + 1 - c.nvis; c.maxcol = max(c.maxcol, L->stringwidth(display)); changed = 1; } } if(changed) sc.draw(1); } swapopt(a: array of B->Option, i, j: int) { selected := a[i].selected; value := a[i].value; display := a[i].display; a[i].selected = a[j].selected; a[i].value = a[j].value; a[i].display = a[j].display; a[j].selected = selected; a[j].value = value; a[j].display = display; } parsebookmarks(b: array of byte): array of B->Option { opts := array [100] of B->Option; LookForBeginA, LookForEndA : con iota; nopt := 0; state := LookForBeginA; begin : int = 0; for(i := 0; i < len b; i++) { case state { LookForBeginA => # look for pattern # look for pattern if(b[i] == byte '<') { if(len b <= i+3) break; if(b[i+1] == byte '/' && b[i+2] == byte 'A' && b[i+3] == byte '>') { # break into value and display (value, display) := S->splitl(string b[begin:i], ">"); if(nopt >= len opts) opts = (array[len opts+100] of B->Option)[0:] = opts; opts[nopt].selected = 0; opts[nopt].value = value; opts[nopt++].display = display[1:]; state = LookForBeginA; } } } } return opts[0:nopt]; } savebookmarks(options: array of B->Option) { fname := config.userdir + "/bookmarks.html"; fd := sys->create(fname, sys->OWRITE, 8r600); if(fd == nil) { #if(warn) sys->print("can't create user bookmarks file\n"); return; } buf := array [Sys->ATOMICIO] of byte; line := "