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}