1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::time::Duration;

use crate::application::ApplicationHandler;
use crate::event_loop::EventLoop;

/// Additional methods on [`EventLoop`] for pumping events within an external event loop
pub trait EventLoopExtPumpEvents {
    /// Pump the `EventLoop` to check for and dispatch pending events.
    ///
    /// This API is designed to enable applications to integrate Winit into an
    /// external event loop, for platforms that can support this.
    ///
    /// The given `timeout` limits how long it may block waiting for new events.
    ///
    /// Passing a `timeout` of `Some(Duration::ZERO)` would ensure your external
    /// event loop is never blocked but you would likely need to consider how
    /// to throttle your own external loop.
    ///
    /// Passing a `timeout` of `None` means that it may wait indefinitely for new
    /// events before returning control back to the external loop.
    ///
    /// **Note:** This is not a portable API, and its usage involves a number of
    /// caveats and trade offs that should be considered before using this API!
    ///
    /// You almost certainly shouldn't use this API, unless you absolutely know it's
    /// the only practical option you have.
    ///
    /// ## Synchronous events
    ///
    /// Some events _must_ only be handled synchronously via the closure that
    /// is passed to Winit so that the handler will also be synchronized with
    /// the window system and operating system.
    ///
    /// This is because some events are driven by a window system callback
    /// where the window systems expects the application to have handled the
    /// event before returning.
    ///
    /// **These events can not be buffered and handled outside of the closure
    /// passed to Winit.**
    ///
    /// As a general rule it is not recommended to ever buffer events to handle
    /// them outside of the closure passed to Winit since it's difficult to
    /// provide guarantees about which events are safe to buffer across all
    /// operating systems.
    ///
    /// Notable events that will certainly create portability problems if
    /// buffered and handled outside of Winit include:
    /// - `RedrawRequested` events, used to schedule rendering.
    ///
    ///     macOS for example uses a `drawRect` callback to drive rendering
    ///     within applications and expects rendering to be finished before
    ///     the `drawRect` callback returns.
    ///
    ///     For portability it's strongly recommended that applications should
    ///     keep their rendering inside the closure provided to Winit.
    /// - Any lifecycle events, such as `Suspended` / `Resumed`.
    ///
    ///     The handling of these events needs to be synchronized with the
    ///     operating system and it would never be appropriate to buffer a
    ///     notification that your application has been suspended or resumed and
    ///     then handled that later since there would always be a chance that
    ///     other lifecycle events occur while the event is buffered.
    ///
    /// ## Supported Platforms
    ///
    /// - Windows
    /// - Linux
    /// - MacOS
    /// - Android
    ///
    /// ## Unsupported Platforms
    ///
    /// - **Web:**  This API is fundamentally incompatible with the event-based way in which Web
    ///   browsers work because it's not possible to have a long-running external loop that would
    ///   block the browser and there is nothing that can be polled to ask for new new events.
    ///   Events are delivered via callbacks based on an event loop that is internal to the browser
    ///   itself.
    /// - **iOS:** It's not possible to stop and start an `NSApplication` repeatedly on iOS so
    ///   there's no way to support the same approach to polling as on MacOS.
    ///
    /// ## Platform-specific
    ///
    /// - **Windows**: The implementation will use `PeekMessage` when checking for window messages
    ///   to avoid blocking your external event loop.
    ///
    /// - **MacOS**: The implementation works in terms of stopping the global application whenever
    ///   the application `RunLoop` indicates that it is preparing to block and wait for new events.
    ///
    ///   This is very different to the polling APIs that are available on other
    ///   platforms (the lower level polling primitives on MacOS are private
    ///   implementation details for `NSApplication` which aren't accessible to
    ///   application developers)
    ///
    ///   It's likely this will be less efficient than polling on other OSs and
    ///   it also means the `NSApplication` is stopped while outside of the Winit
    ///   event loop - and that's observable (for example to crates like `rfd`)
    ///   because the `NSApplication` is global state.
    ///
    ///   If you render outside of Winit you are likely to see window resizing artifacts
    ///   since MacOS expects applications to render synchronously during any `drawRect`
    ///   callback.
    fn pump_app_events<A: ApplicationHandler>(
        &mut self,
        timeout: Option<Duration>,
        app: A,
    ) -> PumpStatus;
}

impl EventLoopExtPumpEvents for EventLoop {
    fn pump_app_events<A: ApplicationHandler>(
        &mut self,
        timeout: Option<Duration>,
        app: A,
    ) -> PumpStatus {
        self.event_loop.pump_app_events(timeout, app)
    }
}

/// The return status for `pump_events`
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PumpStatus {
    /// Continue running external loop.
    Continue,
    /// Exit external loop.
    Exit(i32),
}