Clean up and document the core of stdweb event handling

This commit is contained in:
Ryan Goldstein 2019-04-25 00:02:13 -04:00
parent 9e25561edf
commit fe5e300062

View file

@ -67,7 +67,7 @@ pub struct ELRShared<T> {
struct EventLoopRunner<T> { struct EventLoopRunner<T> {
control: ControlFlow, control: ControlFlow,
handling: bool, is_busy: bool,
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
} }
@ -246,49 +246,93 @@ fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IE
} }
impl<T> ELRShared<T> { impl<T> ELRShared<T> {
// Set the event callback to use for the event loop runner
// This the event callback is a fairly thin layer over the user-provided callback that closes
// over a RootEventLoopWindowTarget reference
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) { fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
*self.runner.borrow_mut() = Some(EventLoopRunner { *self.runner.borrow_mut() = Some(EventLoopRunner {
control: ControlFlow::Poll, control: ControlFlow::Poll,
handling: false, is_busy: false,
event_handler event_handler
}); });
} }
// TODO: handle event loop closures // Add an event to the event loop runner
// TODO: handle event buffer //
// It will determine if the event should be immediately sent to the user or buffered for later
pub fn send_event(&self, event: Event<T>) { pub fn send_event(&self, event: Event<T>) {
let start_cause = StartCause::Poll; // TODO: this is obviously not right // If the event loop is closed, it should discard any new events
self.handle_start(start_cause); if self.closed() {
self.handle_event(event); return;
self.handle_event(Event::EventsCleared); }
}
fn handle_start(&self, start: StartCause) { let start_cause = StartCause::Poll; // TODO: determine start cause
let is_handling = if let Some(ref runner) = *self.runner.borrow() {
runner.handling // Determine if event handling is in process, and then release the borrow on the runner
let is_busy = if let Some(ref runner) = *self.runner.borrow() {
runner.is_busy
} else { } else {
false true // If there is no event runner yet, then there's no point in processing events
}; };
if is_handling {
self.handle_event(Event::NewEvents(start)); if is_busy {
self.events.borrow_mut().push_back(event);
} else {
// Handle starting a new batch of events
//
// The user is informed via Event::NewEvents that there is a batch of events to process
// However, there is only one of these per batch of events
self.handle_event(Event::NewEvents(start_cause));
self.handle_event(event);
self.handle_event(Event::EventsCleared);
// If the event loop is closed, it has been closed this iteration and now the closing
// event should be emitted
if self.closed() {
self.handle_event(Event::LoopDestroyed);
}
} }
} }
// Check if the event loop is currntly closed
fn closed(&self) -> bool {
match *self.runner.borrow() {
Some(ref runner) => runner.control == ControlFlow::Exit,
None => false, // If the event loop is None, it has not been intialised yet, so it cannot be closed
}
}
// handle_event takes in events and either queues them or applies a callback
//
// It should only ever be called from send_event
fn handle_event(&self, event: Event<T>) { fn handle_event(&self, event: Event<T>) {
let closed = self.closed();
match *self.runner.borrow_mut() { match *self.runner.borrow_mut() {
Some(ref mut runner) if !runner.handling => { Some(ref mut runner) => {
runner.handling = true; // An event is being processed, so the runner should be marked busy
let closed = runner.control == ControlFlow::Exit; runner.is_busy = true;
// TODO: bracket this in control flow events? // TODO: bracket this in control flow events?
(runner.event_handler)(event, &mut runner.control); (runner.event_handler)(event, &mut runner.control);
// Maintain closed state, even if the callback changes it
if closed { if closed {
runner.control = ControlFlow::Exit; runner.control = ControlFlow::Exit;
} }
runner.handling = false;
// An event is no longer being processed
runner.is_busy = false;
} }
// If an event is being handled without a runner somehow, add it to the event queue so
// it will eventually be processed
_ => self.events.borrow_mut().push_back(event) _ => self.events.borrow_mut().push_back(event)
} }
if self.runner.borrow().is_some() {
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
// If the runner doesn't exist and this method recurses, it will recurse infinitely
if !closed && self.runner.borrow().is_some() {
// Take an event out of the queue and handle it
if let Some(event) = self.events.borrow_mut().pop_front() { if let Some(event) = self.events.borrow_mut().pop_front() {
self.handle_event(event); self.handle_event(event);
} }