use std::{any::Any, cell::RefCell, collections::VecDeque, mem, panic, ptr, rc::Rc, time::Instant}; use winapi::{shared::windef::HWND, um::winuser}; use crate::{ event::{Event, StartCause}, event_loop::ControlFlow, platform_impl::platform::event_loop::EventLoop, window::WindowId, }; pub(crate) type EventLoopRunnerShared = Rc>; pub(crate) struct ELRShared { runner: RefCell>>, buffer: RefCell>>, redraw_buffer: Rc>>, } struct EventLoopRunner { control_flow: ControlFlow, runner_state: RunnerState, modal_redraw_window: HWND, in_modal_loop: bool, event_handler: Box, &mut ControlFlow)>, panic_error: Option, redraw_buffer: Rc>>, } pub type PanicError = Box; impl ELRShared { pub(crate) fn new() -> ELRShared { ELRShared { runner: RefCell::new(None), buffer: RefCell::new(VecDeque::new()), redraw_buffer: Default::default(), } } pub(crate) unsafe fn set_runner(&self, event_loop: &EventLoop, f: F) where F: FnMut(Event, &mut ControlFlow), { let mut runner = EventLoopRunner::new(event_loop, self.redraw_buffer.clone(), f); { let mut runner_ref = self.runner.borrow_mut(); loop { let event = self.buffer.borrow_mut().pop_front(); match event { Some(e) => { runner.process_event(e); } None => break, } } *runner_ref = Some(runner); } } pub(crate) fn destroy_runner(&self) { *self.runner.borrow_mut() = None; } pub(crate) fn new_events(&self) { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { runner.new_events(); } } pub(crate) unsafe fn send_event(&self, event: Event) { if let Ok(mut runner_ref) = self.runner.try_borrow_mut() { if let Some(ref mut runner) = *runner_ref { runner.process_event(event); // Dispatch any events that were buffered during the call to `process_event`. loop { // We do this instead of using a `while let` loop because if we use a `while let` // loop the reference returned `borrow_mut()` doesn't get dropped until the end // of the loop's body and attempts to add events to the event buffer while in // `process_event` will fail. let buffered_event_opt = self.buffer.borrow_mut().pop_front(); match buffered_event_opt { Some(event) => runner.process_event(event), None => break, } } return; } } // If the runner is already borrowed, we're in the middle of an event loop invocation. Add // the event to a buffer to be processed later. self.buffer_event(event); } pub(crate) unsafe fn call_event_handler(&self, event: Event) { if let Ok(mut runner_ref) = self.runner.try_borrow_mut() { if let Some(ref mut runner) = *runner_ref { runner.call_event_handler(event); return; } } } pub(crate) fn events_cleared(&self) { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { runner.events_cleared(); } } pub(crate) fn take_panic_error(&self) -> Result<(), PanicError> { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { runner.take_panic_error() } else { Ok(()) } } pub(crate) fn set_modal_loop(&self, in_modal_loop: bool) { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { runner.in_modal_loop = in_modal_loop; } } pub(crate) fn in_modal_loop(&self) -> bool { let runner = self.runner.borrow(); if let Some(ref runner) = *runner { runner.in_modal_loop } else { false } } pub fn control_flow(&self) -> ControlFlow { let runner_ref = self.runner.borrow(); if let Some(ref runner) = *runner_ref { runner.control_flow } else { ControlFlow::Exit } } fn buffer_event(&self, event: Event) { match event { Event::RedrawRequested(window_id) => { self.redraw_buffer.borrow_mut().push_back(window_id) } _ => self.buffer.borrow_mut().push_back(event), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum RunnerState { /// The event loop has just been created, and an `Init` event must be sent. New, /// The event loop is idling, and began idling at the given instant. Idle(Instant), /// The event loop has received a signal from the OS that the loop may resume, but no winit /// events have been generated yet. We're waiting for an event to be processed or the events /// to be marked as cleared to send `NewEvents`, depending on the current `ControlFlow`. DeferredNewEvents(Instant), /// The event loop is handling the OS's events and sending them to the user's callback. /// `NewEvents` has been sent, and `EventsCleared` hasn't. HandlingEvents, HandlingRedraw, } impl EventLoopRunner { unsafe fn new( event_loop: &EventLoop, redraw_buffer: Rc>>, f: F, ) -> EventLoopRunner where F: FnMut(Event, &mut ControlFlow), { EventLoopRunner { control_flow: ControlFlow::default(), runner_state: RunnerState::New, in_modal_loop: false, modal_redraw_window: event_loop.window_target.p.thread_msg_target, event_handler: mem::transmute::< Box, &mut ControlFlow)>, Box, &mut ControlFlow)>, >(Box::new(f)), panic_error: None, redraw_buffer, } } fn take_panic_error(&mut self) -> Result<(), PanicError> { match self.panic_error.take() { Some(err) => Err(err), None => Ok(()), } } fn new_events(&mut self) { self.runner_state = match self.runner_state { // If we're already handling events or have deferred `NewEvents`, we don't need to do // do any processing. RunnerState::HandlingEvents | RunnerState::HandlingRedraw | RunnerState::DeferredNewEvents(..) => self.runner_state, // Send the `Init` `NewEvents` and immediately move into event processing. RunnerState::New => { self.call_event_handler(Event::NewEvents(StartCause::Init)); RunnerState::HandlingEvents } // When `NewEvents` gets sent after an idle depends on the control flow... RunnerState::Idle(wait_start) => { match self.control_flow { // If we're polling, send `NewEvents` and immediately move into event processing. ControlFlow::Poll => { self.call_event_handler(Event::NewEvents(StartCause::Poll)); RunnerState::HandlingEvents }, // If the user was waiting until a specific time, the `NewEvents` call gets sent // at varying times depending on the current time. ControlFlow::WaitUntil(resume_time) => { match Instant::now() >= resume_time { // If the current time is later than the requested resume time, we can tell the // user that the resume time has been reached with `NewEvents` and immdiately move // into event processing. true => { self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { start: wait_start, requested_resume: resume_time, })); RunnerState::HandlingEvents }, // However, if the current time is EARLIER than the requested resume time, we // don't want to send the `WaitCancelled` event until we know an event is being // sent. Defer. false => RunnerState::DeferredNewEvents(wait_start) } }, // If we're waiting, `NewEvents` doesn't get sent until winit gets an event, so // we defer. ControlFlow::Wait | // `Exit` shouldn't really ever get sent here, but if it does do something somewhat sane. ControlFlow::Exit => RunnerState::DeferredNewEvents(wait_start), } } }; } fn process_event(&mut self, event: Event) { // If we're in the modal loop, we need to have some mechanism for finding when the event // queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities // for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have // been processed. So, we send WM_PAINT to a dummy window which calls `events_cleared` when // the events queue has been emptied. if self.in_modal_loop { unsafe { winuser::RedrawWindow( self.modal_redraw_window, ptr::null(), ptr::null_mut(), winuser::RDW_INTERNALPAINT, ); } } // If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're // already in processing nothing happens with this call. self.new_events(); // Now that an event has been received, we have to send any `NewEvents` calls that were // deferred. if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state { match self.control_flow { ControlFlow::Exit | ControlFlow::Wait => { self.call_event_handler(Event::NewEvents(StartCause::WaitCancelled { start: wait_start, requested_resume: None, })) } ControlFlow::WaitUntil(resume_time) => { let start_cause = match Instant::now() >= resume_time { // If the current time is later than the requested resume time, the resume time // has been reached. true => StartCause::ResumeTimeReached { start: wait_start, requested_resume: resume_time, }, // Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled. false => StartCause::WaitCancelled { start: wait_start, requested_resume: Some(resume_time), }, }; self.call_event_handler(Event::NewEvents(start_cause)); } // This can be reached if the control flow is changed to poll during a `RedrawRequested` // that was sent after `EventsCleared`. ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)), } } match (self.runner_state, &event) { (RunnerState::HandlingRedraw, Event::RedrawRequested(_)) => { self.call_event_handler(event) } (_, Event::RedrawRequested(_)) => { self.call_event_handler(Event::MainEventsCleared); self.runner_state = RunnerState::HandlingRedraw; self.call_event_handler(event); } (RunnerState::HandlingRedraw, _) => { warn!("Non-redraw event dispatched durning redraw phase"); self.events_cleared(); self.new_events(); self.call_event_handler(event); } (_, _) => { self.runner_state = RunnerState::HandlingEvents; self.call_event_handler(event); } } } fn flush_redraws(&mut self) { loop { let redraw_window_opt = self.redraw_buffer.borrow_mut().pop_front(); match redraw_window_opt { Some(window_id) => self.process_event(Event::RedrawRequested(window_id)), None => break, } } } fn events_cleared(&mut self) { match self.runner_state { // If we were handling events, send the EventsCleared message. RunnerState::HandlingEvents => { self.call_event_handler(Event::MainEventsCleared); self.flush_redraws(); self.call_event_handler(Event::RedrawEventsCleared); self.runner_state = RunnerState::Idle(Instant::now()); } RunnerState::HandlingRedraw => { self.call_event_handler(Event::RedrawEventsCleared); self.runner_state = RunnerState::Idle(Instant::now()); } // If we *weren't* handling events, we don't have to do anything. RunnerState::New | RunnerState::Idle(..) => (), // Some control flows require a NewEvents call even if no events were received. This // branch handles those. RunnerState::DeferredNewEvents(wait_start) => { match self.control_flow { // If we had deferred a Poll, send the Poll NewEvents and EventsCleared. ControlFlow::Poll => { self.call_event_handler(Event::NewEvents(StartCause::Poll)); self.call_event_handler(Event::MainEventsCleared); self.flush_redraws(); self.call_event_handler(Event::RedrawEventsCleared); } // If we had deferred a WaitUntil and the resume time has since been reached, // send the resume notification and EventsCleared event. ControlFlow::WaitUntil(resume_time) => { if Instant::now() >= resume_time { self.call_event_handler(Event::NewEvents( StartCause::ResumeTimeReached { start: wait_start, requested_resume: resume_time, }, )); self.call_event_handler(Event::MainEventsCleared); self.flush_redraws(); self.call_event_handler(Event::RedrawEventsCleared); } } // If we deferred a wait and no events were received, the user doesn't have to // get an event. ControlFlow::Wait | ControlFlow::Exit => (), } // Mark that we've entered an idle state. self.runner_state = RunnerState::Idle(wait_start) } } } fn call_event_handler(&mut self, event: Event) { if self.panic_error.is_none() { let EventLoopRunner { ref mut panic_error, ref mut event_handler, ref mut control_flow, .. } = self; *panic_error = panic::catch_unwind(panic::AssertUnwindSafe(|| { if *control_flow != ControlFlow::Exit { (*event_handler)(event, control_flow); } else { (*event_handler)(event, &mut ControlFlow::Exit); } })) .err(); } } }