ref: d0ab3a0dd8f6355b3603d0fb04043a9ae867639b
dir: /appl/charon/event.b/
implement Events; include "common.m"; sys: Sys; url: Url; Parsedurl: import url; archan : chan of (ref Event, int, int); init(ev : chan of ref Event) { sys = load Sys Sys->PATH; url = load Url Url->PATH; if (url != nil) url->init(); evchan = chan of ref Event; archan = chan of (ref Event, int ,int); spawn eventfilter(evchan, ev); } timer(go, tick : chan of int) { go <-= sys->pctl(0, nil); for(;;) { ms := <- go; sys->sleep(ms); tick <-= 1; } } # Handle mouse filtering and auto-repeating. # If we are waiting to send to Charon then accept events whilst they are # compatible with the pending event (eg. only keep most recent mouse move). # Once we have a recv event that isn't compatible with the pending send event # stop accepting events until the pending one has been sent. # Auto-repeat events are discarded if they cannot be sent or combined with the pending one. # eventfilter(fromc, toc : chan of ref Event) { timergo := chan of int; timertick := chan of int; timeractive := 0; spawn timer(timergo, timertick); timerpid := <-timergo; pendingev : ref Event; bufferedev : ref Event; dummyin := chan of ref Event; dummyout := chan of ref Event; inchan := fromc; outchan := dummyout; arev : ref Event; aridlems, arms : int; for (;;) alt { ev := <- inchan => outchan = toc; if (pendingev == nil) pendingev = ev; else { # an event is pending - see if we can combine/replace it replace := evreplace(pendingev, ev); if (replace != nil) pendingev = replace; else bufferedev = ev; } if (bufferedev != nil) inchan = dummyin; outchan <- = pendingev => pendingev = bufferedev; bufferedev = nil; inchan = fromc; if (pendingev == nil) outchan = dummyout; (arev, aridlems, arms) = <- archan => if (arev == nil) { if(timeractive) { # kill off old timer action so we don't get nasty # holdovers from past autorepeats. kill(timerpid); spawn timer(timergo, timertick); timerpid = <-timergo; timeractive = 0; } } else if (!timeractive) { timeractive = 1; timergo <-= aridlems; } <- timertick => timeractive = 0; if (arev != nil) { if (pendingev == nil) { pendingev = arev; } else if (bufferedev == nil) { replace := evreplace(pendingev, arev); if (replace != nil) pendingev = replace; else bufferedev = arev; } else { # try and combine with the buffered event replace := evreplace(bufferedev, arev); if (replace != nil) bufferedev = replace; } # else: discard auto-repeat event if (bufferedev != nil) inchan = dummyin; # kick-start sends (we always have something to send) outchan = toc; timergo <- = arms; timeractive = 1; } } } evreplace(oldev, newev : ref Event) : ref Event { pick n := newev { Emouse => pick o := oldev { Emouse => if (n.mtype == o.mtype && (n.mtype == Mmove || n.mtype == Mldrag || n.mtype == Mmdrag || n.mtype == Mrdrag)) return newev; } Equit => # always takes precedence return newev; Ego => pick o := oldev { Ego => if (n.target == o.target) return newev; } Escroll => pick o := oldev { Escroll => if (n.frameid == o.frameid) return newev; } Escrollr => pick o := oldev { Escrollr => if (n.frameid == o.frameid) return newev; } Esettext => pick o := oldev { Esettext => if (n.frameid == o.frameid) return newev; } Edismisspopup => if (tagof oldev == tagof Event.Edismisspopup) return newev; * => return nil; } return nil; } autorepeat(ev : ref Event, idlems, ms : int) { archan <- = (ev, idlems, ms); } Event.tostring(ev: self ref Event) : string { s := "?"; pick e := ev { Ekey => t : string; case e.keychar { ' ' => t = "<SP>"; '\t' => t = "<TAB>"; '\n' => t = "<NL>"; '\r' => t = "<CR>"; '\b' => t = "<BS>"; 16r7F => t = "<DEL>"; Kup => t = "<UP>"; Kdown => t = "<DOWN>"; Khome => t = "<HOME>"; Kleft => t = "<LEFT>"; Kright => t = "<RIGHT>"; Kend => t = "<END>"; * => t = sys->sprint("%c", e.keychar); } s = sys->sprint("key %d = %s", e.keychar, t); Emouse => t := "?"; case e.mtype { Mmove => t = "move"; Mlbuttondown => t = "lbuttondown"; Mlbuttonup => t = "lbuttonup"; Mldrag => t = "ldrag"; Mmbuttondown => t = "mbuttondown"; Mmbuttonup => t = "mbuttonup"; Mmdrag => t = "mdrag"; Mrbuttondown => t = "rbuttondown"; Mrbuttonup => t = "rbuttonup"; Mrdrag => t = "rdrag"; } s = sys->sprint("mouse (%d,%d) %s", e.p.x, e.p.y, t); Emove => s = sys->sprint("move (%d,%d)", e.p.x, e.p.y); Ereshape => s = sys->sprint("reshape (%d,%d) (%d,%d)", e.r.min.x, e.r.min.y, e.r.max.x, e.r.max.y); Equit => s = "quit"; Estop => s = "stop"; Eback => s = "back"; Efwd => s = "fwd"; Eform => case e.ftype { EFsubmit => s = "form submit"; EFreset => s = "form reset"; } Eformfield => case e.fftype { EFFblur => s = "formfield blur"; EFFfocus => s = "formfield focus"; EFFclick => s = "formfield click"; EFFselect => s = "formfield select"; EFFredraw => s = "formfield redraw"; } Ego => s = "go("; case e.gtype { EGlocation or EGnormal or EGreplace => s += e.url; EGreload => s += "RELOAD"; EGforward => s += "FORWARD"; EGback => s += "BACK"; EGdelta => s += "HISTORY[" + string e.delta + "]"; } s += ", " + e.target + ")"; Esubmit => if(e.subkind == CharonUtils->HGet) s = "GET"; else s = "POST"; s = "submit(" + s; s += ", " + e.action.tostring(); s += ", " + e.target + ")"; Escroll => s = "scroll(" + string e.frameid + ", (" + string e.pt.x + ", " + string e.pt.y + "))"; Escrollr => s = "scrollr(" + string e.frameid + ", (" + string e.pt.x + ", " + string e.pt.y + "))"; Esettext => s = "settext(frameid=" + string e.frameid + ", text=" + e.text + ")"; Elostfocus => s = "lostfocus"; Edismisspopup => s = "dismisspopup"; } return s; } kill(pid: int) { sys->fprint(sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE), "kill"); }