Skip to main content

wingy_core/event_loop/
pump_events.rs

1use std::time::Duration;
2
3use crate::application::ApplicationHandler;
4
5#[allow(rustdoc::broken_intra_doc_links)] // FIXME(madsmtm): Fix these.
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 Wingy 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 Wingy 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 Wingy.**
40    ///
41    /// As a general rule it is not recommended to ever buffer events to handle
42    /// them outside of the closure passed to Wingy 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 Wingy 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 Wingy.
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 Wingy
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 Wingy 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
109/// The return status for `pump_events`
110#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
111#[allow(clippy::exhaustive_enums)]
112pub enum PumpStatus {
113    /// Continue running external loop.
114    Continue,
115    /// Exit external loop.
116    Exit(i32),
117}