rio_window/platform/
pump_events.rs

1use std::time::Duration;
2
3use crate::application::ApplicationHandler;
4use crate::event::Event;
5use crate::event_loop::{self, ActiveEventLoop, EventLoop};
6
7/// Additional methods on [`EventLoop`] for pumping events within an external event loop
8pub trait EventLoopExtPumpEvents {
9    /// A type provided by the user that can be passed through [`Event::UserEvent`].
10    type UserEvent: 'static;
11
12    /// Pump the `EventLoop` to check for and dispatch pending events.
13    ///
14    /// This API is designed to enable applications to integrate Winit into an
15    /// external event loop, for platforms that can support this.
16    ///
17    /// The given `timeout` limits how long it may block waiting for new events.
18    ///
19    /// Passing a `timeout` of `Some(Duration::ZERO)` would ensure your external
20    /// event loop is never blocked but you would likely need to consider how
21    /// to throttle your own external loop.
22    ///
23    /// Passing a `timeout` of `None` means that it may wait indefinitely for new
24    /// events before returning control back to the external loop.
25    ///
26    /// **Note:** This is not a portable API, and its usage involves a number of
27    /// caveats and trade offs that should be considered before using this API!
28    ///
29    /// You almost certainly shouldn't use this API, unless you absolutely know it's
30    /// the only practical option you have.
31    ///
32    /// ## Synchronous events
33    ///
34    /// Some events _must_ only be handled synchronously via the closure that
35    /// is passed to Winit so that the handler will also be synchronized with
36    /// the window system and operating system.
37    ///
38    /// This is because some events are driven by a window system callback
39    /// where the window systems expects the application to have handled the
40    /// event before returning.
41    ///
42    /// **These events can not be buffered and handled outside of the closure
43    /// passed to Winit.**
44    ///
45    /// As a general rule it is not recommended to ever buffer events to handle
46    /// them outside of the closure passed to Winit since it's difficult to
47    /// provide guarantees about which events are safe to buffer across all
48    /// operating systems.
49    ///
50    /// Notable events that will certainly create portability problems if
51    /// buffered and handled outside of Winit include:
52    /// - `RedrawRequested` events, used to schedule rendering.
53    ///
54    ///     macOS for example uses a `drawRect` callback to drive rendering
55    ///     within applications and expects rendering to be finished before
56    ///     the `drawRect` callback returns.
57    ///
58    ///     For portability it's strongly recommended that applications should
59    ///     keep their rendering inside the closure provided to Winit.
60    /// - Any lifecycle events, such as `Suspended` / `Resumed`.
61    ///
62    ///     The handling of these events needs to be synchronized with the
63    ///     operating system and it would never be appropriate to buffer a
64    ///     notification that your application has been suspended or resumed and
65    ///     then handled that later since there would always be a chance that
66    ///     other lifecycle events occur while the event is buffered.
67    ///
68    /// ## Supported Platforms
69    ///
70    /// - Windows
71    /// - Linux
72    /// - MacOS
73    /// - Android
74    ///
75    /// ## Unsupported Platforms
76    ///
77    /// - **Web:**  This API is fundamentally incompatible with the event-based way in which
78    ///     Web browsers work because it's not possible to have a long-running external
79    ///     loop that would block the browser and there is nothing that can be
80    ///     polled to ask for new new events. Events are delivered via callbacks based
81    ///     on an event loop that is internal to the browser itself.
82    /// - **iOS:** It's not possible to stop and start an `NSApplication` repeatedly on iOS so
83    ///     there's no way to support the same approach to polling as on MacOS.
84    ///
85    /// ## Platform-specific
86    ///
87    /// - **Windows**: The implementation will use `PeekMessage` when checking for window messages
88    ///     to avoid blocking your external event loop.
89    ///
90    /// - **MacOS**: The implementation works in terms of stopping the global application whenever
91    ///     the application `RunLoop` indicates that it is preparing to block and wait for new events.
92    ///
93    ///   This is very different to the polling APIs that are available on other
94    ///   platforms (the lower level polling primitives on MacOS are private
95    ///   implementation details for `NSApplication` which aren't accessible to
96    ///   application developers)
97    ///
98    ///   It's likely this will be less efficient than polling on other OSs and
99    ///   it also means the `NSApplication` is stopped while outside of the Winit
100    ///   event loop - and that's observable (for example to crates like `rfd`)
101    ///   because the `NSApplication` is global state.
102    ///
103    ///   If you render outside of Winit you are likely to see window resizing artifacts
104    ///   since MacOS expects applications to render synchronously during any `drawRect`
105    ///   callback.
106    fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
107        &mut self,
108        timeout: Option<Duration>,
109        app: &mut A,
110    ) -> PumpStatus {
111        #[allow(deprecated)]
112        self.pump_events(timeout, |event, event_loop| {
113            event_loop::dispatch_event_for_app(app, event_loop, event)
114        })
115    }
116
117    /// See [`pump_app_events`].
118    ///
119    /// [`pump_app_events`]: Self::pump_app_events
120    #[deprecated = "use EventLoopExtPumpEvents::pump_app_events"]
121    fn pump_events<F>(
122        &mut self,
123        timeout: Option<Duration>,
124        event_handler: F,
125    ) -> PumpStatus
126    where
127        F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
128}
129
130impl<T> EventLoopExtPumpEvents for EventLoop<T> {
131    type UserEvent = T;
132
133    fn pump_events<F>(
134        &mut self,
135        timeout: Option<Duration>,
136        event_handler: F,
137    ) -> PumpStatus
138    where
139        F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop),
140    {
141        self.event_loop.pump_events(timeout, event_handler)
142    }
143}
144
145/// The return status for `pump_events`
146pub enum PumpStatus {
147    /// Continue running external loop.
148    Continue,
149    /// Exit external loop.
150    Exit(i32),
151}