new object $event_handler: $foundation; var $event_handler events = 0; var $event_handler hooked = #[]; var $event_handler hooks = #[]; var $root created_on = 850790316; var $root flags = ['variables, 'methods, 'code, 'core]; var $root inited = 1; var $root managed = [$event_handler]; var $root manager = $event_handler; public method .clear_event_hook() { arg event; var o; (> .perms(sender(), 'writer) <); if ((!hooks) || (!(hooks.contains(event)))) return; for o in (hooks[event]) (| o.event_hook_removed(event) |); hooks = dict_del(hooks, event); if (!hooks) { (| clear_var('hooks) |); (| clear_var('hooked) |); } }; public method .deregister_event() { arg event, update_on; var value, event, src, status; (> .perms(sender()) <); if ((events.contains(update_on)) && ((events[update_on]).contains(event))) { // clean it up first.. (ignore status) [event, [status, source]] = events[update_on]; switch (source) { case 'location: (| loc.unhook_from_event(event) |); case 'this: (| .unhook_from_event(event) |); default: (| source.hook_into_event(event) |); } // now cleanup 'events' value = (events[update_on]).del(event); if (value) events = events.add(update_on, value); else events = events.del(update_on); if (!events) clear_var('events); } }; protected method .did_hook() { arg event, obj; }; public method .event_hook_removed() { arg event; (> .perms(caller(), $event_handler) <); }; public method .event_hooks() { if (hooks) return dict_keys(hooks); return []; }; public method .event_notify() { arg event, origin, @args; if (caller() != $event_handler) throw(~perm, caller() + " is not $event_handler."); }; public method .hook_events() { arg type; var status, source, event, l, all; if (events && (events.contains(type))) { all = events[type]; events = events.del(type); l = .location(); for event in (all) { [event, [status, source]] = event; switch (source) { case 'location: l.hook_into_event(event); case 'this: .hook_into_event(event); default: source.hook_into_event(event); } all = all.add(event, [1, source]); } events = events.add(type, all); } }; public method .hook_into_event() { arg event; if (!hooks) hooks = #[]; (> .will_hook(event, sender()) <); hooks = dict_add(hooks, event, setadd((| hooks[event] |) || [], sender())); hooked = (hooked || #[]).setadd_elem(sender(), event); (| .did_hook(event, sender()) |); }; public method .register_event() { arg event, update_on, src; var value, all; (> .perms(sender()) <); if (!events) events = #[]; // If/when more are added.. also update $help_sys_event_register if ((update_on != 'move) && (update_on != 'startup)) throw(~type, "Update on must be either 'move or 'startup"); if (type(src) == 'symbol) { if ((src != 'location) && (src != 'this)) throw(~type, "Source types must be either 'location or 'this."); } else if (type(src) != 'objnum) { throw(~type, "Source type must be either a symbol or object."); } else if (!(src.is($event_handler))) { throw(~type, ("Source " + (src.namef('ref))) + " is not an event handler."); } if (events.contains(update_on)) { all = events[update_on]; if ((events[update_on]).contains(event)) { value = replace(all[event], 2, src); events = events.add(update_on, all.add(event, value)); } else { events = events.add(update_on, all.add(event, [0, src])); } } else { events = events.add(update_on, #[[event, [0, src]]]); } }; public method .send_event() { arg event, @args; var o; // some sort of perms checking.. if ((!hooks) || (!(hooks.contains(event)))) return; for o in (hooks[event]) { if (!valid(o)) { hooks = dict_add(hooks, event, setremove(hooks[event], o)); hooked = (hooked || #[]).del_elem(o, event); } (| o.event_notify(event, sender(), @args) |); } if (!hooked) (| clear_var('hooked) |); }; public method .unhook_events() { arg type, @loc; var all, event, status, source; if (events && (events.contains(type))) { all = events[type]; events = events.del(type); loc = loc ? (loc[1]) : (.location()); for event in (all) { [event, [status, source]] = event; switch (source) { case 'location: (| loc.unhook_from_event(event) |); case 'this: (| .unhook_from_event(event) |); default: (| source.hook_into_event(event) |); } all = all.add(event, [0, source]); } events = events.add(type, all); } }; public method .unhook_from_all() { var e; if ((!hooked) || (!(hooked.contains(sender())))) return; for e in (hooked[sender()]) hooks = dict_add(hooks, e, setremove(hooks[e], sender())); hooked = dict_del(hooked, sender()); }; public method .unhook_from_event() { arg event; if (hooks) hooks = dict_add(hooks, event, setremove(hooks[event], sender())); if (hooked) hooked = hooked.del_elem(sender(), event); }; root method .uninit_event_handler() { var event, obj, update_on; for update_on in ((events || #[]).keys()) { for event in ((events[update_on]).keys()) (| .deregister_event(event, update_on) |); } for obj in ((hooks || #[]).keys()) { for event in (hooks[obj]) (| obj.event_hook_removed(event) |); } }; protected method .will_hook() { arg event, obj; };