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) { 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); 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 (aridlems <= 0 || arms <= 0) arev = nil; if (!timeractive && arev != nil) { 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; } Esettext => pick o := oldev { Esettext => if (n.frameid == o.frameid) 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 = ""; '\t' => t = ""; '\n' => t = ""; '\r' => t = ""; '\b' => t = ""; 16r7F => t = ""; Kup => t = ""; Kdown => t = ""; Khome => t = ""; Kleft => t = ""; Kright => t = ""; Kend => t = ""; * => 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); Eexpose => s = "expose"; Ehide => s = "hide"; Elower => s = "lower"; Eraise => s = "raise"; Equit => s = "quit"; Ehelp => s = "help"; Estop => s = "stop"; Ealert => s = "alert(" + e.msg + ")"; Econfirm => s = "confirm(" + e.msg + ")"; Eprompt => s = "prompt(" + e.msg + ", " + e.inputdflt + ")"; 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"; EGhome => s += "HOME"; EGbookmarks => s += "BOOKMARKS"; 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 + "))"; Eframefocus => s = "framefocus(" + string e.frameid + ", " + string e.focus +")"; Esettext => s = "settext(frameid=" + string e.frameid + ", text=" + e.text + ")"; } return s; }