diff options
Diffstat (limited to 'appl/charon/event.b')
| -rw-r--r-- | appl/charon/event.b | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/appl/charon/event.b b/appl/charon/event.b new file mode 100644 index 00000000..79a9a5e1 --- /dev/null +++ b/appl/charon/event.b @@ -0,0 +1,273 @@ +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"); +} |
