//! End user application handling. use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent}; use crate::event_loop::ActiveEventLoop; #[cfg(any(docsrs, macos_platform))] use crate::platform::macos::ApplicationHandlerExtMacOS; use crate::window::WindowId; /// The handler of the application events. pub trait ApplicationHandler { /// Emitted when new events arrive from the OS to be processed. /// /// This is a useful place to put code that should be done before you start processing /// events, such as updating frame timing information for benchmarking or checking the /// [`StartCause`] to see if a timer set by /// [`ControlFlow::WaitUntil`][crate::event_loop::ControlFlow::WaitUntil] has elapsed. fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) { let _ = (event_loop, cause); } /// Emitted when the application has been resumed. /// /// See [`suspended()`][Self::suspended]. /// /// ## Platform-specific /// /// ### iOS /// /// On iOS, the [`resumed()`] method is called in response to an [`applicationDidBecomeActive`] /// callback which means the application is about to transition from the inactive to active /// state (according to the [iOS application lifecycle]). /// /// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle /// /// ### Web /// /// On Web, the [`resumed()`] method is called in response to a [`pageshow`] event if the /// page is being restored from the [`bfcache`] (back/forward cache) - an in-memory cache /// that stores a complete snapshot of a page (including the JavaScript heap) as the user is /// navigating away. /// /// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event /// [`bfcache`]: https://web.dev/bfcache/ /// /// ### Android /// /// On Android, the [`resumed()`] method is called when the `Activity` is (again, if after a /// prior [`suspended()`]) being displayed to the user. This is a good place to begin drawing /// visual elements, running animations, etc. It is driven by Android's [`onStart()`] method. /// /// [`onStart()`]: https://developer.android.com/reference/android/app/Activity#onStart() /// /// ### Others /// /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported. /// /// [`resumed()`]: Self::resumed() /// [`suspended()`]: Self::suspended() /// [`exiting()`]: Self::exiting() fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted from the point onwards the application should create render surfaces. /// /// See [`destroy_surfaces()`]. /// /// ## Portability /// /// It's recommended that applications should only initialize their render surfaces after the /// [`can_create_surfaces()`] method is called. Some systems (specifically Android) won't allow /// applications to create a render surface until that point. /// /// For consistency, all platforms call this method even if they don't themselves have a formal /// surface destroy/create lifecycle. For systems without a surface destroy/create lifecycle the /// [`can_create_surfaces()`] event is always emitted after the [`StartCause::Init`] event. /// /// Applications should be able to gracefully handle back-to-back [`can_create_surfaces()`] and /// [`destroy_surfaces()`] calls. /// /// ## Platform-specific /// /// ### Android /// /// On Android, the [`can_create_surfaces()`] method is called when a new [`NativeWindow`] /// (native [`Surface`]) is created which backs the application window. This is expected to /// closely correlate with the [`onStart`] lifecycle event which typically results in a surface /// to be created after the app becomes visible. /// /// Applications that need to run on Android must wait until they have received a surface before /// they will be able to create a render surface (such as an `EGLSurface`, [`VkSurfaceKHR`] /// or [`wgpu::Surface`]) which depend on having a [`NativeWindow`]. Applications must handle /// [`destroy_surfaces()`], where their render surfaces are invalid and should be dropped. /// /// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window /// [`Surface`]: https://developer.android.com/reference/android/view/Surface /// [`onStart`]: https://developer.android.com/reference/android/app/Activity#onStart() /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html /// /// [`can_create_surfaces()`]: Self::can_create_surfaces() /// [`destroy_surfaces()`]: Self::destroy_surfaces() fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop); /// Called after a wake up is requested using [`EventLoopProxy::wake_up()`]. /// /// Multiple calls to the aforementioned method will be merged, and will only wake the event /// loop once; however, due to the nature of multi-threading some wake ups may appear /// spuriously. For these reasons, you should not rely on the number of times that this was /// called. /// /// The order in which this is emitted in relation to other events is not guaranteed. The time /// at which this will be emitted is not guaranteed, only that it will happen "soon". That is, /// there may be several executions of the event loop, including multiple redraws to windows, /// between [`EventLoopProxy::wake_up()`] being called and the event being delivered. /// /// [`EventLoopProxy::wake_up()`]: crate::event_loop::EventLoopProxy::wake_up /// /// # Example /// /// Use a [`std::sync::mpsc`] channel to handle events from a different thread. /// /// ```no_run /// use std::sync::mpsc; /// use std::thread; /// use std::time::Duration; /// /// use winit::application::ApplicationHandler; /// use winit::event_loop::{ActiveEventLoop, EventLoop}; /// /// struct MyApp { /// receiver: mpsc::Receiver, /// } /// /// impl ApplicationHandler for MyApp { /// # fn window_event( /// # &mut self, /// # _event_loop: &dyn ActiveEventLoop, /// # _window_id: winit::window::WindowId, /// # _event: winit::event::WindowEvent, /// # ) { /// # } /// # /// # fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {} /// # /// fn proxy_wake_up(&mut self, _event_loop: &dyn ActiveEventLoop) { /// // Iterate current events, since wake-ups may have been merged. /// // /// // Note: We take care not to use `recv` or `iter` here, as those are blocking, /// // and that would be bad for performance and might lead to a deadlock. /// for i in self.receiver.try_iter() { /// println!("received: {i}"); /// } /// } /// /// // Rest of `ApplicationHandler` /// } /// /// fn main() -> Result<(), Box> { /// let event_loop = EventLoop::new()?; /// /// let (sender, receiver) = mpsc::channel(); /// /// let mut app = MyApp { receiver }; /// /// // Send an event in a loop /// let proxy = event_loop.create_proxy(); /// let background_thread = thread::spawn(move || { /// let mut i = 0; /// loop { /// println!("sending: {i}"); /// if sender.send(i).is_err() { /// // Stop sending once `MyApp` is dropped /// break; /// } /// // Trigger the wake-up _after_ we placed the event in the channel. /// // Otherwise, `proxy_wake_up` might be triggered prematurely. /// proxy.wake_up(); /// i += 1; /// thread::sleep(Duration::from_secs(1)); /// } /// }); /// /// event_loop.run_app(&mut app)?; /// /// drop(app); /// background_thread.join().unwrap(); /// /// Ok(()) /// } /// ``` fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted when the OS sends an event to a winit window. fn window_event( &mut self, event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: WindowEvent, ); /// Emitted when the OS sends an event to a device. fn device_event( &mut self, event_loop: &dyn ActiveEventLoop, device_id: Option, event: DeviceEvent, ) { let _ = (event_loop, device_id, event); } /// Emitted when the event loop is about to block and wait for new events. /// /// Most applications shouldn't need to hook into this event since there is no real relationship /// between how often the event loop needs to wake up and the dispatching of any specific /// events. /// /// High frequency event sources, such as input devices could potentially lead to lots of wake /// ups and also lots of corresponding `AboutToWait` events. /// /// This is not an ideal event to drive application rendering from and instead applications /// should render in response to [`WindowEvent::RedrawRequested`] events. fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted when the application has been suspended. /// /// See [`resumed()`][Self::resumed]. /// /// ## Platform-specific /// /// ### iOS /// /// On iOS, the [`suspended()`] method is called in response to an /// [`applicationWillResignActive`] callback which means that the application is about to /// transition from the active to inactive state (according to the [iOS application lifecycle]). /// /// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle /// /// ### Web /// /// On Web, the [`suspended()`] method is called in response to a [`pagehide`] event if the /// page is being stored in the [`bfcache`] (back/forward cache) - an in-memory cache that /// stores a complete snapshot of a page (including the JavaScript heap) as the user is /// navigating away. /// /// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event /// [`bfcache`]: https://web.dev/bfcache/ /// /// ### Android /// /// On Android, the [`suspended()`] method is called when the `Activity` is no longer visible /// to the user. This is a good place to stop refreshing UI, running animations and other visual /// things. It is driven by Android's [`onStop()`] method. /// /// After this event the application either receives [`resumed()`] again, or [`exiting()`]. /// /// [`onStop()`]: https://developer.android.com/reference/android/app/Activity#onStop() /// /// ### Others /// /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported. /// /// [`resumed()`]: Self::resumed() /// [`suspended()`]: Self::suspended() /// [`exiting()`]: Self::exiting() fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted when the application must destroy its render surfaces. /// /// See [`can_create_surfaces()`] for more details. /// /// ## Platform-specific /// /// ### Android /// /// On Android, the [`destroy_surfaces()`] method is called when the application's /// [`NativeWindow`] (native [`Surface`]) is destroyed. This is expected to closely correlate /// with the [`onStop`] lifecycle event which typically results in the surface to be destroyed /// after the app becomes invisible. /// /// Applications that need to run on Android should assume their [`NativeWindow`] has been /// destroyed, which indirectly invalidates any existing render surfaces that may have been /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]). /// /// When receiving [`destroy_surfaces()`] Android applications should drop all render surfaces /// before the event callback completes, which may be re-created when the application next /// receives [`can_create_surfaces()`]. /// /// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window /// [`Surface`]: https://developer.android.com/reference/android/view/Surface /// [`onStop`]: https://developer.android.com/reference/android/app/Activity#onStop() /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html /// /// ### Others /// /// - **iOS / macOS / Orbital / Wayland / Web / Windows / X11:** Unsupported. /// /// [`can_create_surfaces()`]: Self::can_create_surfaces() /// [`destroy_surfaces()`]: Self::destroy_surfaces() fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted when the event loop is being shut down. /// /// This is irreversible - if this method is called, it is guaranteed that the event loop /// will exit right after. fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// Emitted when the application has received a memory warning. /// /// ## Platform-specific /// /// ### Android /// /// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The /// application must [release memory] or risk being killed. /// /// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory() /// [release memory]: https://developer.android.com/topic/performance/memory#release /// /// ### iOS /// /// On iOS, the `MemoryWarning` event is emitted in response to an /// [`applicationDidReceiveMemoryWarning`] callback. The application must free as much /// memory as possible or risk being terminated, see [how to respond to memory warnings]. /// /// [`applicationDidReceiveMemoryWarning`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623063-applicationdidreceivememorywarni /// [how to respond to memory warnings]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle/responding_to_memory_warnings /// /// ### Others /// /// - **macOS / Orbital / Wayland / Web / Windows:** Unsupported. fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } /// The macOS-specific handler. /// /// The return value from this should not change at runtime. #[cfg(any(docsrs, macos_platform))] #[inline(always)] fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { None } } #[deny(clippy::missing_trait_methods)] impl ApplicationHandler for &mut A { #[inline] fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) { (**self).new_events(event_loop, cause); } #[inline] fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).resumed(event_loop); } #[inline] fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).can_create_surfaces(event_loop); } #[inline] fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).proxy_wake_up(event_loop); } #[inline] fn window_event( &mut self, event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: WindowEvent, ) { (**self).window_event(event_loop, window_id, event); } #[inline] fn device_event( &mut self, event_loop: &dyn ActiveEventLoop, device_id: Option, event: DeviceEvent, ) { (**self).device_event(event_loop, device_id, event); } #[inline] fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).about_to_wait(event_loop); } #[inline] fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).suspended(event_loop); } #[inline] fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).destroy_surfaces(event_loop); } #[inline] fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).exiting(event_loop); } #[inline] fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).memory_warning(event_loop); } #[cfg(any(docsrs, macos_platform))] #[inline] fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { (**self).macos_handler() } } #[deny(clippy::missing_trait_methods)] impl ApplicationHandler for Box { #[inline] fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) { (**self).new_events(event_loop, cause); } #[inline] fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).resumed(event_loop); } #[inline] fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).can_create_surfaces(event_loop); } #[inline] fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).proxy_wake_up(event_loop); } #[inline] fn window_event( &mut self, event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: WindowEvent, ) { (**self).window_event(event_loop, window_id, event); } #[inline] fn device_event( &mut self, event_loop: &dyn ActiveEventLoop, device_id: Option, event: DeviceEvent, ) { (**self).device_event(event_loop, device_id, event); } #[inline] fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).about_to_wait(event_loop); } #[inline] fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).suspended(event_loop); } #[inline] fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).destroy_surfaces(event_loop); } #[inline] fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).exiting(event_loop); } #[inline] fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).memory_warning(event_loop); } #[cfg(any(docsrs, macos_platform))] #[inline] fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { (**self).macos_handler() } }