diff --git a/examples/window.rs b/examples/window.rs index 12e0593e..e2265dbd 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -20,7 +20,10 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => *control_flow = ControlFlow::Exit, - _ => *control_flow = ControlFlow::Wait, + Event::MainEventsCleared => { + window.request_redraw(); + } + _ => *control_flow = ControlFlow::Poll, } }); } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 183879b2..08b74204 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -13,16 +13,14 @@ //! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to //! add a `WindowState` entry to a list of window to be used by the callback. +mod runner; + use parking_lot::Mutex; use std::{ - any::Any, - cell::RefCell, - collections::VecDeque, marker::PhantomData, mem, panic, ptr, rc::Rc, sync::{ - atomic::{AtomicBool, Ordering}, mpsc::{self, Receiver, Sender}, Arc, }, @@ -44,9 +42,10 @@ use winapi::{ }, }; +use self::runner::{ELRShared, EventLoopRunnerShared}; use crate::{ dpi::{LogicalPosition, LogicalSize, PhysicalSize}, - event::{DeviceEvent, Event, Force, KeyboardInput, StartCause, Touch, TouchPhase, WindowEvent}, + event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent}, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, platform_impl::platform::{ dpi::{ @@ -127,7 +126,6 @@ pub struct EventLoop { pub struct EventLoopWindowTarget { thread_id: DWORD, - trigger_newevents_on_redraw: Arc, thread_msg_target: HWND, pub(crate) runner_shared: EventLoopRunnerShared, } @@ -167,10 +165,7 @@ impl EventLoop { pub fn new_dpi_unaware_any_thread() -> EventLoop { let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; - let runner_shared = Rc::new(ELRShared { - runner: RefCell::new(None), - buffer: RefCell::new(VecDeque::new()), - }); + let runner_shared = Rc::new(ELRShared::new()); let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); @@ -179,7 +174,6 @@ impl EventLoop { window_target: RootELW { p: EventLoopWindowTarget { thread_id, - trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), thread_msg_target, runner_shared, }, @@ -206,44 +200,23 @@ impl EventLoop { { let event_loop_windows_ref = &self.window_target; - let mut runner = unsafe { - EventLoopRunner::new(self, move |event, control_flow| { - event_handler(event, event_loop_windows_ref, control_flow) - }) - }; - { - let runner_shared = self.window_target.p.runner_shared.clone(); - let mut runner_ref = runner_shared.runner.borrow_mut(); - loop { - let event = runner_shared.buffer.borrow_mut().pop_front(); - match event { - Some(e) => { - runner.process_event(e); - } - None => break, - } - } - *runner_ref = Some(runner); + unsafe { + self.window_target + .p + .runner_shared + .set_runner(self, move |event, control_flow| { + event_handler(event, event_loop_windows_ref, control_flow) + }) } - macro_rules! runner { - () => { - self.window_target - .p - .runner_shared - .runner - .borrow_mut() - .as_mut() - .unwrap() - }; - } + let runner = &self.window_target.p.runner_shared; unsafe { let mut msg = mem::zeroed(); let mut msg_unprocessed = false; 'main: loop { - runner!().new_events(); + runner.new_events(); loop { if !msg_unprocessed { if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { @@ -255,13 +228,14 @@ impl EventLoop { msg_unprocessed = false; } - runner!().events_cleared(); - if let Some(payload) = runner!().panic_error.take() { + runner.events_cleared(); + if let Err(payload) = runner.take_panic_error() { + runner.destroy_runner(); panic::resume_unwind(payload); } if !msg_unprocessed { - let control_flow = runner!().control_flow; + let control_flow = runner.control_flow(); match control_flow { ControlFlow::Exit => break 'main, ControlFlow::Wait => { @@ -279,8 +253,10 @@ impl EventLoop { } } - runner!().call_event_handler(Event::LoopDestroyed); - *self.window_target.p.runner_shared.runner.borrow_mut() = None; + unsafe { + runner.call_event_handler(Event::LoopDestroyed); + } + runner.destroy_runner(); } pub fn create_proxy(&self) -> EventLoopProxy { @@ -296,7 +272,6 @@ impl EventLoopWindowTarget { pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { thread_id: self.thread_id, - trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone(), target_window: self.thread_msg_target, } } @@ -317,291 +292,6 @@ fn main_thread_id() -> DWORD { unsafe { MAIN_THREAD_ID } } -pub(crate) type EventLoopRunnerShared = Rc>; -pub(crate) struct ELRShared { - runner: RefCell>>, - buffer: RefCell>>, -} -pub(crate) struct EventLoopRunner { - trigger_newevents_on_redraw: Arc, - control_flow: ControlFlow, - runner_state: RunnerState, - modal_redraw_window: HWND, - in_modal_loop: bool, - in_repaint: bool, - event_handler: Box, &mut ControlFlow)>, - panic_error: Option, -} -type PanicError = Box; - -impl ELRShared { - 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.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, -} - -impl EventLoopRunner { - unsafe fn new(event_loop: &EventLoop, f: F) -> EventLoopRunner - where - F: FnMut(Event, &mut ControlFlow), - { - EventLoopRunner { - trigger_newevents_on_redraw: event_loop - .window_target - .p - .trigger_newevents_on_redraw - .clone(), - control_flow: ControlFlow::default(), - runner_state: RunnerState::New, - in_modal_loop: false, - in_repaint: 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, - } - } - - 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::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)), - } - } - - self.runner_state = RunnerState::HandlingEvents; - match (self.in_repaint, &event) { - ( - true, - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - }, - ) - | (false, _) => self.call_event_handler(event), - (true, _) => { - self.events_cleared(); - self.new_events(); - self.process_event(event); - } - } - } - - fn events_cleared(&mut self) { - self.in_repaint = false; - - match self.runner_state { - // If we were handling events, send the EventsCleared message. - RunnerState::HandlingEvents => { - self.call_event_handler(Event::EventsCleared); - 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::EventsCleared); - } - // 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::EventsCleared); - } - } - // 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) { - match event { - Event::NewEvents(_) => self - .trigger_newevents_on_redraw - .store(true, Ordering::Relaxed), - Event::EventsCleared => self - .trigger_newevents_on_redraw - .store(false, Ordering::Relaxed), - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => self.in_repaint = true, - _ => (), - } - - 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(); - } - } -} - // Returns true if the wait time was reached, and false if a message must be processed. unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool { let mut msg = mem::zeroed(); @@ -667,7 +357,6 @@ impl Drop for EventLoop { pub(crate) struct EventLoopThreadExecutor { thread_id: DWORD, - trigger_newevents_on_redraw: Arc, target_window: HWND, } @@ -681,10 +370,6 @@ impl EventLoopThreadExecutor { self.thread_id == cur_thread_id } - pub(super) fn trigger_newevents_on_redraw(&self) -> bool { - !self.in_event_loop_thread() || self.trigger_newevents_on_redraw.load(Ordering::Relaxed) - } - /// Executes a function in the event loop thread. If we're already in the event loop thread, /// we just call the function directly. /// @@ -784,12 +469,6 @@ lazy_static! { winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR) } }; - // Message sent by a `Window` if it's requesting a redraw without sending a NewEvents. - pub static ref REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID: u32 = { - unsafe { - winuser::RegisterWindowMessageA("Winit::RequestRedrawNoNewevents\0".as_ptr() as LPCSTR) - } - }; // WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the // documentation in the `window_state` module for more information. pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe { @@ -922,21 +601,15 @@ unsafe extern "system" fn public_window_callback( _: UINT_PTR, subclass_input_ptr: DWORD_PTR, ) -> LRESULT { - let subclass_input = &mut *(subclass_input_ptr as *mut SubclassInput); + let subclass_input = &*(subclass_input_ptr as *const SubclassInput); match msg { winuser::WM_ENTERSIZEMOVE => { - let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(ref mut runner) = *runner { - runner.in_modal_loop = true; - } + subclass_input.event_loop_runner.set_modal_loop(true); 0 } winuser::WM_EXITSIZEMOVE => { - let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(ref mut runner) = *runner { - runner.in_modal_loop = false; - } + subclass_input.event_loop_runner.set_modal_loop(false); 0 } winuser::WM_NCCREATE => { @@ -975,48 +648,13 @@ unsafe extern "system" fn public_window_callback( event: Destroyed, }); - Box::from_raw(subclass_input); drop(subclass_input); + Box::from_raw(subclass_input_ptr as *mut SubclassInput); 0 } - _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { - use crate::event::WindowEvent::RedrawRequested; - let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); - subclass_input.window_state.lock().queued_out_of_band_redraw = false; - if let Some(ref mut runner) = *runner { - // This check makes sure that calls to `request_redraw()` during `EventsCleared` - // handling dispatch `RedrawRequested` immediately after `EventsCleared`, without - // spinning up a new event loop iteration. We do this because that's what the API - // says to do. - let runner_state = runner.runner_state; - let mut request_redraw = || { - runner.call_event_handler(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: RedrawRequested, - }); - }; - match runner_state { - RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => request_redraw(), - RunnerState::HandlingEvents => { - winuser::RedrawWindow( - window, - ptr::null(), - ptr::null_mut(), - winuser::RDW_INTERNALPAINT, - ); - } - _ => (), - } - } - 0 - } winuser::WM_PAINT => { - use crate::event::WindowEvent::RedrawRequested; - subclass_input.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: RedrawRequested, - }); + subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window)))); commctrl::DefSubclassProc(window, msg, wparam, lparam) } @@ -1984,14 +1622,7 @@ unsafe extern "system" fn thread_event_target_callback( winuser::RDW_INTERNALPAINT, ); }; - let in_modal_loop = { - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(ref runner) = *runner { - runner.in_modal_loop - } else { - false - } - }; + let in_modal_loop = subclass_input.event_loop_runner.in_modal_loop(); if in_modal_loop { let mut msg = mem::zeroed(); loop { @@ -2019,21 +1650,19 @@ unsafe extern "system" fn thread_event_target_callback( } } - let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(ref mut runner) = *runner { - runner.events_cleared(); - match runner.control_flow { - // Waiting is handled by the modal loop. - ControlFlow::Exit | ControlFlow::Wait => runner.new_events(), - ControlFlow::WaitUntil(resume_time) => { - wait_until_time_or_msg(resume_time); - runner.new_events(); - queue_call_again(); - } - ControlFlow::Poll => { - runner.new_events(); - queue_call_again(); - } + let runner = &subclass_input.event_loop_runner; + runner.events_cleared(); + match runner.control_flow() { + // Waiting is handled by the modal loop. + ControlFlow::Exit | ControlFlow::Wait => runner.new_events(), + ControlFlow::WaitUntil(resume_time) => { + wait_until_time_or_msg(resume_time); + runner.new_events(); + queue_call_again(); + } + ControlFlow::Poll => { + runner.new_events(); + queue_call_again(); } } } diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs new file mode 100644 index 00000000..243763ff --- /dev/null +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -0,0 +1,415 @@ +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(); + } + } +} diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index f647a88c..0877de46 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -38,7 +38,6 @@ use crate::{ drop_handler::FileDropHandler, event_loop::{ self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, - REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, }, icon::{self, IconType, WinIcon}, monitor, @@ -142,20 +141,12 @@ impl Window { #[inline] pub fn request_redraw(&self) { unsafe { - if self.thread_executor.trigger_newevents_on_redraw() { - winuser::RedrawWindow( - self.window.0, - ptr::null(), - ptr::null_mut(), - winuser::RDW_INTERNALPAINT, - ); - } else { - let mut window_state = self.window_state.lock(); - if !window_state.queued_out_of_band_redraw { - window_state.queued_out_of_band_redraw = true; - winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0); - } - } + winuser::RedrawWindow( + self.window.0, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT, + ); } }