winit/platform/
pump_events.rs

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