Skip to main content

tao/platform_impl/windows/event_loop/
runner.rs

1// Copyright 2014-2021 The winit contributors
2// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6  any::Any,
7  cell::{Cell, RefCell},
8  collections::{HashSet, VecDeque},
9  mem, panic,
10  rc::Rc,
11  time::Instant,
12};
13
14use windows::Win32::{
15  Foundation::HWND,
16  Graphics::Gdi::{RedrawWindow, RDW_INTERNALPAINT},
17};
18
19use crate::{
20  dpi::PhysicalSize,
21  event::{Event, StartCause, WindowEvent},
22  event_loop::ControlFlow,
23  platform_impl::platform::util,
24  window::WindowId,
25};
26
27pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
28pub(crate) struct EventLoopRunner<T: 'static> {
29  // The event loop's win32 handles
30  thread_msg_target: HWND,
31  wait_thread_id: u32,
32
33  control_flow: Cell<ControlFlow>,
34  runner_state: Cell<RunnerState>,
35  last_events_cleared: Cell<Instant>,
36
37  event_handler: Cell<Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>>,
38  event_buffer: RefCell<VecDeque<BufferedEvent<T>>>,
39
40  owned_windows: Cell<HashSet<isize>>,
41
42  panic_error: Cell<Option<PanicError>>,
43}
44
45pub type PanicError = Box<dyn Any + Send + 'static>;
46
47/// See `move_state_to` function for details on how the state loop works.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49enum RunnerState {
50  /// The event loop has just been created, and an `Init` event must be sent.
51  Uninitialized,
52  /// The event loop is idling.
53  Idle,
54  /// The event loop is handling the OS's events and sending them to the user's callback.
55  /// `NewEvents` has been sent, and `MainEventsCleared` hasn't.
56  HandlingMainEvents,
57  /// The event loop is handling the redraw events and sending them to the user's callback.
58  /// `MainEventsCleared` has been sent, and `RedrawEventsCleared` hasn't.
59  HandlingRedrawEvents,
60  /// The event loop has been destroyed. No other events will be emitted.
61  Destroyed,
62}
63
64enum BufferedEvent<T: 'static> {
65  Event(Event<'static, T>),
66  ScaleFactorChanged(WindowId, f64, PhysicalSize<u32>),
67}
68
69impl<T> EventLoopRunner<T> {
70  pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: u32) -> EventLoopRunner<T> {
71    EventLoopRunner {
72      thread_msg_target,
73      wait_thread_id,
74      runner_state: Cell::new(RunnerState::Uninitialized),
75      control_flow: Cell::new(ControlFlow::Poll),
76      panic_error: Cell::new(None),
77      last_events_cleared: Cell::new(Instant::now()),
78      event_handler: Cell::new(None),
79      event_buffer: RefCell::new(VecDeque::new()),
80      owned_windows: Cell::new(HashSet::new()),
81    }
82  }
83
84  pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
85  where
86    F: FnMut(Event<'_, T>, &mut ControlFlow),
87  {
88    let old_event_handler = self.event_handler.replace(mem::transmute::<
89      Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>,
90      Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>,
91    >(Some(Box::new(f))));
92    assert!(old_event_handler.is_none());
93  }
94
95  pub(crate) fn reset_runner(&self) {
96    let EventLoopRunner {
97      thread_msg_target: _,
98      wait_thread_id: _,
99      runner_state,
100      panic_error,
101      control_flow,
102      last_events_cleared: _,
103      event_handler,
104      event_buffer: _,
105      owned_windows: _,
106    } = self;
107    runner_state.set(RunnerState::Uninitialized);
108    panic_error.set(None);
109    control_flow.set(ControlFlow::Poll);
110    event_handler.set(None);
111  }
112}
113
114/// State retrieval functions.
115impl<T> EventLoopRunner<T> {
116  pub fn thread_msg_target(&self) -> HWND {
117    self.thread_msg_target
118  }
119
120  pub fn wait_thread_id(&self) -> u32 {
121    self.wait_thread_id
122  }
123
124  pub fn redrawing(&self) -> bool {
125    self.runner_state.get() == RunnerState::HandlingRedrawEvents
126  }
127
128  pub fn take_panic_error(&self) -> Result<(), PanicError> {
129    match self.panic_error.take() {
130      Some(err) => Err(err),
131      None => Ok(()),
132    }
133  }
134
135  pub fn control_flow(&self) -> ControlFlow {
136    self.control_flow.get()
137  }
138
139  pub fn handling_events(&self) -> bool {
140    self.runner_state.get() != RunnerState::Idle
141  }
142
143  pub fn should_buffer(&self) -> bool {
144    let handler = self.event_handler.take();
145    let should_buffer = handler.is_none();
146    self.event_handler.set(handler);
147    should_buffer
148  }
149}
150
151/// Misc. functions
152impl<T> EventLoopRunner<T> {
153  pub fn catch_unwind<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
154    let panic_error = self.panic_error.take();
155    if panic_error.is_none() {
156      let result = panic::catch_unwind(panic::AssertUnwindSafe(f));
157
158      // Check to see if the panic error was set in a re-entrant call to catch_unwind inside
159      // of `f`. If it was, that error takes priority. If it wasn't, check if our call to
160      // catch_unwind caught any panics and set panic_error appropriately.
161      match self.panic_error.take() {
162        None => match result {
163          Ok(r) => Some(r),
164          Err(e) => {
165            self.panic_error.set(Some(e));
166            None
167          }
168        },
169        Some(e) => {
170          self.panic_error.set(Some(e));
171          None
172        }
173      }
174    } else {
175      self.panic_error.set(panic_error);
176      None
177    }
178  }
179  pub fn register_window(&self, window: HWND) {
180    let mut owned_windows = self.owned_windows.take();
181    owned_windows.insert(window.0 as _);
182    self.owned_windows.set(owned_windows);
183  }
184
185  pub fn remove_window(&self, window: HWND) {
186    let mut owned_windows = self.owned_windows.take();
187    owned_windows.remove(&(window.0 as _));
188    self.owned_windows.set(owned_windows);
189  }
190
191  pub fn owned_windows(&self, mut f: impl FnMut(HWND)) {
192    let mut owned_windows = self.owned_windows.take();
193    for hwnd in &owned_windows {
194      f(HWND(*hwnd as _));
195    }
196    let new_owned_windows = self.owned_windows.take();
197    owned_windows.extend(&new_owned_windows);
198    self.owned_windows.set(owned_windows);
199  }
200}
201
202/// Event dispatch functions.
203impl<T> EventLoopRunner<T> {
204  pub(crate) unsafe fn poll(&self) {
205    self.move_state_to(RunnerState::HandlingMainEvents);
206  }
207
208  pub(crate) unsafe fn send_event(&self, event: Event<'_, T>) {
209    if let Event::RedrawRequested(_) = event {
210      if self.runner_state.get() != RunnerState::HandlingRedrawEvents {
211        // TODO: Consider removing log once https://github.com/rust-windowing/winit/pull/2767 gets adopted.
212        debug!("RedrawRequested dispatched without explicit MainEventsCleared");
213        self.move_state_to(RunnerState::HandlingRedrawEvents);
214      }
215      self.call_event_handler(event);
216    } else if self.should_buffer() {
217      // If the runner is already borrowed, we're in the middle of an event loop invocation. Add
218      // the event to a buffer to be processed later.
219      self
220        .event_buffer
221        .borrow_mut()
222        .push_back(BufferedEvent::from_event(event))
223    } else {
224      self.move_state_to(RunnerState::HandlingMainEvents);
225      self.call_event_handler(event);
226      self.dispatch_buffered_events();
227    }
228  }
229
230  pub(crate) unsafe fn main_events_cleared(&self) {
231    self.move_state_to(RunnerState::HandlingRedrawEvents);
232  }
233
234  pub(crate) unsafe fn redraw_events_cleared(&self) {
235    self.move_state_to(RunnerState::Idle);
236  }
237
238  pub(crate) unsafe fn loop_destroyed(&self) {
239    self.move_state_to(RunnerState::Destroyed);
240  }
241
242  unsafe fn call_event_handler(&self, event: Event<'_, T>) {
243    self.catch_unwind(|| {
244            let mut control_flow = self.control_flow.take();
245            let mut event_handler = self.event_handler.take()
246                .expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
247
248            if let ControlFlow::ExitWithCode(code) = control_flow  {
249                event_handler(event, &mut ControlFlow::ExitWithCode(code));
250            } else {
251                event_handler(event, &mut control_flow);
252            }
253
254            assert!(self.event_handler.replace(Some(event_handler)).is_none());
255            self.control_flow.set(control_flow);
256        });
257  }
258
259  unsafe fn dispatch_buffered_events(&self) {
260    loop {
261      // We do this instead of using a `while let` loop because if we use a `while let`
262      // loop the reference returned `borrow_mut()` doesn't get dropped until the end
263      // of the loop's body and attempts to add events to the event buffer while in
264      // `process_event` will fail.
265      let buffered_event_opt = self.event_buffer.borrow_mut().pop_front();
266      match buffered_event_opt {
267        Some(e) => e.dispatch_event(|e| self.call_event_handler(e)),
268        None => break,
269      }
270    }
271  }
272
273  /// Dispatch control flow events (`NewEvents`, `MainEventsCleared`, `RedrawEventsCleared`, and
274  /// `LoopDestroyed`) as necessary to bring the internal `RunnerState` to the new runner state.
275  ///
276  /// The state transitions are defined as follows:
277  ///
278  /// ```text
279  ///    Uninitialized
280  ///          |
281  ///          V
282  ///  HandlingMainEvents
283  ///   ^            |
284  ///   |            V
285  /// Idle <--- HandlingRedrawEvents
286  ///   |
287  ///   V
288  /// Destroyed
289  /// ```
290  ///
291  /// Attempting to transition back to `Uninitialized` will result in a panic. Attempting to
292  /// transition *from* `Destroyed` will also reuslt in a panic. Transitioning to the current
293  /// state is a no-op. Even if the `new_runner_state` isn't the immediate next state in the
294  /// runner state machine (e.g. `self.runner_state == HandlingMainEvents` and
295  /// `new_runner_state == Idle`), the intermediate state transitions will still be executed.
296  unsafe fn move_state_to(&self, new_runner_state: RunnerState) {
297    use RunnerState::{Destroyed, HandlingMainEvents, HandlingRedrawEvents, Idle, Uninitialized};
298
299    match (
300      self.runner_state.replace(new_runner_state),
301      new_runner_state,
302    ) {
303      (Uninitialized, Uninitialized)
304      | (Idle, Idle)
305      | (HandlingMainEvents, HandlingMainEvents)
306      | (HandlingRedrawEvents, HandlingRedrawEvents)
307      | (Destroyed, Destroyed) => (),
308
309      // State transitions that initialize the event loop.
310      (Uninitialized, HandlingMainEvents) => {
311        self.call_new_events(true);
312      }
313      (Uninitialized, HandlingRedrawEvents) => {
314        self.call_new_events(true);
315        self.call_event_handler(Event::MainEventsCleared);
316      }
317      (Uninitialized, Idle) => {
318        self.call_new_events(true);
319        self.call_event_handler(Event::MainEventsCleared);
320        self.call_redraw_events_cleared();
321      }
322      (Uninitialized, Destroyed) => {
323        self.call_new_events(true);
324        self.call_event_handler(Event::MainEventsCleared);
325        self.call_redraw_events_cleared();
326        self.call_event_handler(Event::LoopDestroyed);
327      }
328      (_, Uninitialized) => panic!("cannot move state to Uninitialized"),
329
330      // State transitions that start the event handling process.
331      (Idle, HandlingMainEvents) => {
332        self.call_new_events(false);
333      }
334      (Idle, HandlingRedrawEvents) => {
335        self.call_new_events(false);
336        self.call_event_handler(Event::MainEventsCleared);
337      }
338      (Idle, Destroyed) => {
339        self.call_event_handler(Event::LoopDestroyed);
340      }
341
342      (HandlingMainEvents, HandlingRedrawEvents) => {
343        self.call_event_handler(Event::MainEventsCleared);
344      }
345      (HandlingMainEvents, Idle) => {
346        // TODO: Consider removing log once https://github.com/rust-windowing/winit/pull/2767 gets adopted.
347        debug!("RedrawEventsCleared emitted without explicit MainEventsCleared");
348        self.call_event_handler(Event::MainEventsCleared);
349        self.call_redraw_events_cleared();
350      }
351      (HandlingMainEvents, Destroyed) => {
352        self.call_event_handler(Event::MainEventsCleared);
353        self.call_redraw_events_cleared();
354        self.call_event_handler(Event::LoopDestroyed);
355      }
356
357      (HandlingRedrawEvents, Idle) => {
358        self.call_redraw_events_cleared();
359      }
360      (HandlingRedrawEvents, HandlingMainEvents) => {
361        // TODO: Consider removing log once https://github.com/rust-windowing/winit/pull/2767 gets adopted.
362        debug!("NewEvents emitted without explicit RedrawEventsCleared");
363        self.call_redraw_events_cleared();
364        self.call_new_events(false);
365      }
366      (HandlingRedrawEvents, Destroyed) => {
367        self.call_redraw_events_cleared();
368        self.call_event_handler(Event::LoopDestroyed);
369      }
370
371      (Destroyed, _) => panic!("cannot move state from Destroyed"),
372    }
373  }
374
375  unsafe fn call_new_events(&self, init: bool) {
376    let start_cause = match (init, self.control_flow()) {
377      (true, _) => StartCause::Init,
378      (false, ControlFlow::Poll) => StartCause::Poll,
379      (false, ControlFlow::ExitWithCode(_)) | (false, ControlFlow::Wait) => {
380        StartCause::WaitCancelled {
381          requested_resume: None,
382          start: self.last_events_cleared.get(),
383        }
384      }
385      (false, ControlFlow::WaitUntil(requested_resume)) => {
386        if Instant::now() < requested_resume {
387          StartCause::WaitCancelled {
388            requested_resume: Some(requested_resume),
389            start: self.last_events_cleared.get(),
390          }
391        } else {
392          StartCause::ResumeTimeReached {
393            requested_resume,
394            start: self.last_events_cleared.get(),
395          }
396        }
397      }
398    };
399    self.call_event_handler(Event::NewEvents(start_cause));
400    self.dispatch_buffered_events();
401    let _ = RedrawWindow(Some(self.thread_msg_target), None, None, RDW_INTERNALPAINT);
402  }
403
404  unsafe fn call_redraw_events_cleared(&self) {
405    self.call_event_handler(Event::RedrawEventsCleared);
406    self.last_events_cleared.set(Instant::now());
407  }
408}
409
410impl<T> BufferedEvent<T> {
411  pub fn from_event(event: Event<'_, T>) -> BufferedEvent<T> {
412    match event {
413      Event::WindowEvent {
414        event:
415          WindowEvent::ScaleFactorChanged {
416            scale_factor,
417            new_inner_size,
418          },
419        window_id,
420      } => BufferedEvent::ScaleFactorChanged(window_id, scale_factor, *new_inner_size),
421      event => BufferedEvent::Event(event.to_static().unwrap()),
422    }
423  }
424
425  pub fn dispatch_event(self, dispatch: impl FnOnce(Event<'_, T>)) {
426    match self {
427      Self::Event(event) => dispatch(event),
428      Self::ScaleFactorChanged(window_id, scale_factor, mut new_inner_size) => {
429        let os_inner_size = new_inner_size;
430
431        dispatch(Event::WindowEvent {
432          window_id,
433          event: WindowEvent::ScaleFactorChanged {
434            scale_factor,
435            new_inner_size: &mut new_inner_size,
436          },
437        });
438
439        if new_inner_size != os_inner_size {
440          util::set_inner_size_physical(
441            HWND(window_id.0 .0 as _),
442            new_inner_size.width as _,
443            new_inner_size.height as _,
444            true,
445          );
446        }
447      }
448    }
449  }
450}