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}