Windows: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand

A surprising amount of work was required to enable these extensions
on Windows.

I had originally assumed that pump_events was going to be very similar
to run except would use PeekMessageW instead of GetMessageW to avoid
blocking the external loop but I found the Windows backend broke
several assumptions I had.

Overall I think these changes can hopefully be considered a quite a
significant simplification (I think it's a net deletion of a fair amount
of code) and I think it also helps bring it into slightly closer alignment
with other backends too

Key changes:
- I have removed the `wait_thread` that was a fairly fiddly way of handling
  `ControlFlow::WaitUntil` timeouts in favor of using `SetTimer` which works
  with the same messages picked up by `GetMessage` and `PeekMessage`.
- I have removed the ordering guarantees between `MainEventsCleared`,
  `RedrawRequested` and `RedrawEventsCleared` events due to the complexity in
  maintaining this artificial ordering, which is already not supported
  consistently across backends anyway (in particular this ordering already
  isn't compatible with how MacOS / iOS work).
- `RedrawRequested` events are now directly dispatched via `WM_PAINT` messages
  - comparable to how `RedrawRequested` is dispatched via `drawRect` in the
  MacOS backend.
- I have re-worked how `NewEvents`, `MainEventsCleared`, and `RedrawEventsCleared`
  get dispatched to be more in line with the MacOS backend and also more in line
  with how we have recently discussed defining them for all platforms.

  `NewEvents` is conceptually delivered when the event loop "wakes up" and
  `MainEventsCleared` gets dispatched when the event loop is about to ask the
  OS to wait for new events.

  This is a more portable model, and is already how these events work in the
  MacOS backend.

  `RedrawEventsCleared` are just delivered after `MainEventsCleared` but this
  event no longer has a useful meaning.

Probably the most controversial thing here is that this "breaks" the ordering
rules for redraw event handling, but since my changes interacted with how the
order is maintained I was very reluctant to figure out how to continue
maintaining something that we have recently been discussing changing:

https://github.com/rust-windowing/winit/issues/2640.

Additionally, since the MacOS backend already doesn't strictly maintain this
order it's somewhat academic to see this as a breakage if Winit applications
can't really rely on it already.

This updates the documentation for `request_redraw()` to reflect that we
no longer guarantee that `RedrawRequested` events must be dispatched
after `MainEventsCleared`.
This commit is contained in:
Robert Bragg 2023-06-18 11:42:57 +01:00 committed by Kirill Chibisov
parent f5e73b0af4
commit 420840278b
5 changed files with 341 additions and 434 deletions

View file

@ -1,16 +1,13 @@
use std::{
any::Any,
cell::{Cell, RefCell},
collections::{HashSet, VecDeque},
mem, panic, ptr,
collections::VecDeque,
mem, panic,
rc::Rc,
time::Instant,
};
use windows_sys::Win32::{
Foundation::HWND,
Graphics::Gdi::{RedrawWindow, RDW_INTERNALPAINT},
};
use windows_sys::Win32::Foundation::HWND;
use crate::{
dpi::PhysicalSize,
@ -30,7 +27,11 @@ type EventHandler<T> = Cell<Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)
pub(crate) struct EventLoopRunner<T: 'static> {
// The event loop's win32 handles
pub(super) thread_msg_target: HWND,
wait_thread_id: u32,
// Setting this will ensure pump_events will return to the external
// loop asap. E.g. set after each RedrawRequested to ensure pump_events
// can't stall an external loop beyond a frame
pub(super) interrupt_msg_dispatch: Cell<bool>,
control_flow: Cell<ControlFlow>,
runner_state: Cell<RunnerState>,
@ -38,8 +39,6 @@ pub(crate) struct EventLoopRunner<T: 'static> {
event_handler: EventHandler<T>,
event_buffer: RefCell<VecDeque<BufferedEvent<T>>>,
owned_windows: Cell<HashSet<HWND>>,
panic_error: Cell<Option<PanicError>>,
}
@ -47,7 +46,7 @@ pub type PanicError = Box<dyn Any + Send + 'static>;
/// See `move_state_to` function for details on how the state loop works.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum RunnerState {
pub(crate) enum RunnerState {
/// The event loop has just been created, and an `Init` event must be sent.
Uninitialized,
/// The event loop is idling.
@ -55,9 +54,6 @@ enum RunnerState {
/// The event loop is handling the OS's events and sending them to the user's callback.
/// `NewEvents` has been sent, and `MainEventsCleared` hasn't.
HandlingMainEvents,
/// The event loop is handling the redraw events and sending them to the user's callback.
/// `MainEventsCleared` has been sent, and `RedrawEventsCleared` hasn't.
HandlingRedrawEvents,
/// The event loop has been destroyed. No other events will be emitted.
Destroyed,
}
@ -68,20 +64,30 @@ enum BufferedEvent<T: 'static> {
}
impl<T> EventLoopRunner<T> {
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: u32) -> EventLoopRunner<T> {
pub(crate) fn new(thread_msg_target: HWND) -> EventLoopRunner<T> {
EventLoopRunner {
thread_msg_target,
wait_thread_id,
interrupt_msg_dispatch: Cell::new(false),
runner_state: Cell::new(RunnerState::Uninitialized),
control_flow: Cell::new(ControlFlow::Poll),
panic_error: Cell::new(None),
last_events_cleared: Cell::new(Instant::now()),
event_handler: Cell::new(None),
event_buffer: RefCell::new(VecDeque::new()),
owned_windows: Cell::new(HashSet::new()),
}
}
/// Associate the application's event handler with the runner
///
/// # Safety
/// This is ignoring the lifetime of the application handler (which may not
/// outlive the EventLoopRunner) and can lead to undefined behaviour if
/// the handler is not cleared before the end of real lifetime.
///
/// All public APIs that take an event handler (`run`, `run_ondemand`,
/// `pump_events`) _must_ pair a call to `set_event_handler` with
/// a call to `clear_event_handler` before returning to avoid
/// undefined behaviour.
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
where
F: FnMut(Event<'_, T>, &mut ControlFlow),
@ -93,18 +99,22 @@ impl<T> EventLoopRunner<T> {
assert!(old_event_handler.is_none());
}
pub(crate) fn clear_event_handler(&self) {
self.event_handler.set(None);
}
pub(crate) fn reset_runner(&self) {
let EventLoopRunner {
thread_msg_target: _,
wait_thread_id: _,
interrupt_msg_dispatch,
runner_state,
panic_error,
control_flow,
last_events_cleared: _,
event_handler,
event_buffer: _,
owned_windows: _,
} = self;
interrupt_msg_dispatch.set(false);
runner_state.set(RunnerState::Uninitialized);
panic_error.set(None);
control_flow.set(ControlFlow::Poll);
@ -114,18 +124,11 @@ impl<T> EventLoopRunner<T> {
/// State retrieval functions.
impl<T> EventLoopRunner<T> {
#[allow(unused)]
pub fn thread_msg_target(&self) -> HWND {
self.thread_msg_target
}
pub fn wait_thread_id(&self) -> u32 {
self.wait_thread_id
}
pub fn redrawing(&self) -> bool {
self.runner_state.get() == RunnerState::HandlingRedrawEvents
}
pub fn take_panic_error(&self) -> Result<(), PanicError> {
match self.panic_error.take() {
Some(err) => Err(err),
@ -133,12 +136,16 @@ impl<T> EventLoopRunner<T> {
}
}
pub fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
pub fn state(&self) -> RunnerState {
self.runner_state.get()
}
pub fn handling_events(&self) -> bool {
self.runner_state.get() != RunnerState::Idle
pub fn set_exit_control_flow(&self, code: i32) {
self.control_flow.set(ControlFlow::ExitWithCode(code))
}
pub fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub fn should_buffer(&self) -> bool {
@ -177,42 +184,25 @@ impl<T> EventLoopRunner<T> {
None
}
}
pub fn register_window(&self, window: HWND) {
let mut owned_windows = self.owned_windows.take();
owned_windows.insert(window);
self.owned_windows.set(owned_windows);
}
pub fn remove_window(&self, window: HWND) {
let mut owned_windows = self.owned_windows.take();
owned_windows.remove(&window);
self.owned_windows.set(owned_windows);
}
pub fn owned_windows(&self, mut f: impl FnMut(HWND)) {
let mut owned_windows = self.owned_windows.take();
for hwnd in &owned_windows {
f(*hwnd);
}
let new_owned_windows = self.owned_windows.take();
owned_windows.extend(&new_owned_windows);
self.owned_windows.set(owned_windows);
}
}
/// Event dispatch functions.
impl<T> EventLoopRunner<T> {
pub(crate) unsafe fn poll(&self) {
pub(crate) fn prepare_wait(&self) {
self.move_state_to(RunnerState::Idle);
}
pub(crate) fn wakeup(&self) {
self.move_state_to(RunnerState::HandlingMainEvents);
}
pub(crate) unsafe fn send_event(&self, event: Event<'_, T>) {
pub(crate) fn send_event(&self, event: Event<'_, T>) {
if let Event::RedrawRequested(_) = event {
if self.runner_state.get() != RunnerState::HandlingRedrawEvents {
warn!("RedrawRequested dispatched without explicit MainEventsCleared");
self.move_state_to(RunnerState::HandlingRedrawEvents);
}
self.call_event_handler(event);
// As a rule, to ensure that `pump_events` can't block an external event loop
// for too long, we always guarantee that `pump_events` will return control to
// the external loop asap after a `RedrawRequested` event is dispatched.
self.interrupt_msg_dispatch.set(true);
} else if self.should_buffer() {
// 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.
@ -220,25 +210,16 @@ impl<T> EventLoopRunner<T> {
.borrow_mut()
.push_back(BufferedEvent::from_event(event))
} else {
self.move_state_to(RunnerState::HandlingMainEvents);
self.call_event_handler(event);
self.dispatch_buffered_events();
}
}
pub(crate) unsafe fn main_events_cleared(&self) {
self.move_state_to(RunnerState::HandlingRedrawEvents);
}
pub(crate) unsafe fn redraw_events_cleared(&self) {
self.move_state_to(RunnerState::Idle);
}
pub(crate) unsafe fn loop_destroyed(&self) {
pub(crate) fn loop_destroyed(&self) {
self.move_state_to(RunnerState::Destroyed);
}
unsafe fn call_event_handler(&self, event: Event<'_, T>) {
fn call_event_handler(&self, event: Event<'_, T>) {
self.catch_unwind(|| {
let mut control_flow = self.control_flow.take();
let mut event_handler = self.event_handler.take()
@ -255,7 +236,7 @@ impl<T> EventLoopRunner<T> {
});
}
unsafe fn dispatch_buffered_events(&self) {
fn dispatch_buffered_events(&self) {
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
@ -278,24 +259,22 @@ impl<T> EventLoopRunner<T> {
/// Uninitialized
/// |
/// V
/// HandlingMainEvents
/// ^ |
/// | V
/// Idle <--- HandlingRedrawEvents
/// |
/// V
/// Destroyed
/// Idle
/// ^ |
/// | V
/// HandlingMainEvents
/// |
/// V
/// Destroyed
/// ```
///
/// Attempting to transition back to `Uninitialized` will result in a panic. Attempting to
/// transition *from* `Destroyed` will also reuslt in a panic. Transitioning to the current
/// transition *from* `Destroyed` will also result in a panic. Transitioning to the current
/// state is a no-op. Even if the `new_runner_state` isn't the immediate next state in the
/// runner state machine (e.g. `self.runner_state == HandlingMainEvents` and
/// `new_runner_state == Idle`), the intermediate state transitions will still be executed.
unsafe fn move_state_to(&self, new_runner_state: RunnerState) {
use RunnerState::{
Destroyed, HandlingMainEvents, HandlingRedrawEvents, Idle, Uninitialized,
};
fn move_state_to(&self, new_runner_state: RunnerState) {
use RunnerState::{Destroyed, HandlingMainEvents, Idle, Uninitialized};
match (
self.runner_state.replace(new_runner_state),
@ -304,17 +283,12 @@ impl<T> EventLoopRunner<T> {
(Uninitialized, Uninitialized)
| (Idle, Idle)
| (HandlingMainEvents, HandlingMainEvents)
| (HandlingRedrawEvents, HandlingRedrawEvents)
| (Destroyed, Destroyed) => (),
// State transitions that initialize the event loop.
(Uninitialized, HandlingMainEvents) => {
self.call_new_events(true);
}
(Uninitialized, HandlingRedrawEvents) => {
self.call_new_events(true);
self.call_event_handler(Event::MainEventsCleared);
}
(Uninitialized, Idle) => {
self.call_new_events(true);
self.call_event_handler(Event::MainEventsCleared);
@ -332,19 +306,11 @@ impl<T> EventLoopRunner<T> {
(Idle, HandlingMainEvents) => {
self.call_new_events(false);
}
(Idle, HandlingRedrawEvents) => {
self.call_new_events(false);
self.call_event_handler(Event::MainEventsCleared);
}
(Idle, Destroyed) => {
self.call_event_handler(Event::LoopDestroyed);
}
(HandlingMainEvents, HandlingRedrawEvents) => {
self.call_event_handler(Event::MainEventsCleared);
}
(HandlingMainEvents, Idle) => {
warn!("RedrawEventsCleared emitted without explicit MainEventsCleared");
self.call_event_handler(Event::MainEventsCleared);
self.call_redraw_events_cleared();
}
@ -354,24 +320,11 @@ impl<T> EventLoopRunner<T> {
self.call_event_handler(Event::LoopDestroyed);
}
(HandlingRedrawEvents, Idle) => {
self.call_redraw_events_cleared();
}
(HandlingRedrawEvents, HandlingMainEvents) => {
warn!("NewEvents emitted without explicit RedrawEventsCleared");
self.call_redraw_events_cleared();
self.call_new_events(false);
}
(HandlingRedrawEvents, Destroyed) => {
self.call_redraw_events_cleared();
self.call_event_handler(Event::LoopDestroyed);
}
(Destroyed, _) => panic!("cannot move state from Destroyed"),
}
}
unsafe fn call_new_events(&self, init: bool) {
fn call_new_events(&self, init: bool) {
let start_cause = match (init, self.control_flow()) {
(true, _) => StartCause::Init,
(false, ControlFlow::Poll) => StartCause::Poll,
@ -402,10 +355,9 @@ impl<T> EventLoopRunner<T> {
self.call_event_handler(Event::Resumed);
}
self.dispatch_buffered_events();
RedrawWindow(self.thread_msg_target, ptr::null(), 0, RDW_INTERNALPAINT);
}
unsafe fn call_redraw_events_cleared(&self) {
fn call_redraw_events_cleared(&self) {
self.call_event_handler(Event::RedrawEventsCleared);
self.last_events_cleared.set(Instant::now());
}