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**: Certain actions like resizing the window will enter a "modal" state, where /// `pump_app_events` will process events internally, and block until the resize is over. /// /// Thus, if you render or run your game code outside of `ApplicationHandler`, your /// application will freeze while the window resizes. The recommended approach is to render /// inside [`WindowEvent::RedrawRequested`] instead. /// /// Furthermore, when pumping events the `NSApplication` is still considered stopped to /// crates like `rfd` that inspect [`-[NSApplication isRunning]`][isrunning]. /// /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested /// [isrunning]: https://developer.apple.com/documentation/appkit/nsapplication/isrunning?language=objc fn pump_app_events( &mut self, timeout: Option, app: A, ) -> PumpStatus; } impl EventLoopExtPumpEvents for EventLoop { fn pump_app_events( &mut self, timeout: Option, 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), }