summaryrefslogtreecommitdiff
path: root/appl/charon/event.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/charon/event.b')
-rw-r--r--appl/charon/event.b273
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");
+}