winit_core/application/
mod.rs

1//! End user application handling.
2
3use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent};
4use crate::event_loop::ActiveEventLoop;
5use crate::window::WindowId;
6
7pub mod macos;
8
9/// The handler of application-level events.
10pub trait ApplicationHandler {
11    /// Emitted when new events arrive from the OS to be processed.
12    ///
13    /// This is a useful place to put code that should be done before you start processing
14    /// events, such as updating frame timing information for benchmarking or checking the
15    /// [`StartCause`] to see if a timer set by
16    /// [`ControlFlow::WaitUntil`][crate::event_loop::ControlFlow::WaitUntil] has elapsed.
17    fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
18        let _ = (event_loop, cause);
19    }
20
21    /// Emitted when the application has been resumed.
22    ///
23    /// See [`suspended()`][Self::suspended].
24    ///
25    /// ## Platform-specific
26    ///
27    /// ### iOS
28    ///
29    /// On iOS, the [`resumed()`] method is called in response to an [`applicationDidBecomeActive`]
30    /// callback which means the application is about to transition from the inactive to active
31    /// state (according to the [iOS application lifecycle]).
32    ///
33    /// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
34    /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
35    ///
36    /// ### Web
37    ///
38    /// On Web, the [`resumed()`] method is called in response to a [`pageshow`] event if the
39    /// page is being restored from the [`bfcache`] (back/forward cache) - an in-memory cache
40    /// that stores a complete snapshot of a page (including the JavaScript heap) as the user is
41    /// navigating away.
42    ///
43    /// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
44    /// [`bfcache`]: https://web.dev/bfcache/
45    ///
46    /// ### Android
47    ///
48    /// On Android, the [`resumed()`] method is called when the `Activity` is (again, if after a
49    /// prior [`suspended()`]) being displayed to the user. This is a good place to begin drawing
50    /// visual elements, running animations, etc. It is driven by Android's [`onStart()`] method.
51    ///
52    /// [`onStart()`]: https://developer.android.com/reference/android/app/Activity#onStart()
53    ///
54    /// ### Others
55    ///
56    /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported.
57    ///
58    /// [`resumed()`]: Self::resumed()
59    /// [`suspended()`]: Self::suspended()
60    fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) {
61        let _ = event_loop;
62    }
63
64    /// Emitted from the point onwards the application should create render surfaces.
65    ///
66    /// See [`destroy_surfaces()`].
67    ///
68    /// ## Portability
69    ///
70    /// It's recommended that applications should only initialize their render surfaces after the
71    /// [`can_create_surfaces()`] method is called. Some systems (specifically Android) won't allow
72    /// applications to create a render surface until that point.
73    ///
74    /// For consistency, all platforms call this method even if they don't themselves have a formal
75    /// surface destroy/create lifecycle. For systems without a surface destroy/create lifecycle the
76    /// [`can_create_surfaces()`] event is always emitted after the [`StartCause::Init`] event.
77    ///
78    /// Applications should be able to gracefully handle back-to-back [`can_create_surfaces()`] and
79    /// [`destroy_surfaces()`] calls.
80    ///
81    /// ## Platform-specific
82    ///
83    /// ### Android
84    ///
85    /// On Android, the [`can_create_surfaces()`] method is called when a new [`NativeWindow`]
86    /// (native [`Surface`]) is created which backs the application window. This is expected to
87    /// closely correlate with the [`onStart`] lifecycle event which typically results in a surface
88    /// to be created after the app becomes visible.
89    ///
90    /// Applications that need to run on Android must wait until they have received a surface before
91    /// they will be able to create a render surface (such as an `EGLSurface`, [`VkSurfaceKHR`]
92    /// or [`wgpu::Surface`]) which depend on having a [`NativeWindow`]. Applications must handle
93    /// [`destroy_surfaces()`], where their render surfaces are invalid and should be dropped.
94    ///
95    /// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window
96    /// [`Surface`]: https://developer.android.com/reference/android/view/Surface
97    /// [`onStart`]: https://developer.android.com/reference/android/app/Activity#onStart()
98    /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
99    /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
100    ///
101    /// [`can_create_surfaces()`]: Self::can_create_surfaces()
102    /// [`destroy_surfaces()`]: Self::destroy_surfaces()
103    fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop);
104
105    /// Called after a wake up is requested using [`EventLoopProxy::wake_up()`].
106    ///
107    /// Multiple calls to the aforementioned method will be merged, and will only wake the event
108    /// loop once; however, due to the nature of multi-threading some wake ups may appear
109    /// spuriously. For these reasons, you should not rely on the number of times that this was
110    /// called.
111    ///
112    /// The order in which this is emitted in relation to other events is not guaranteed. The time
113    /// at which this will be emitted is not guaranteed, only that it will happen "soon". That is,
114    /// there may be several executions of the event loop, including multiple redraws to windows,
115    /// between [`EventLoopProxy::wake_up()`] being called and the event being delivered.
116    ///
117    /// [`EventLoopProxy::wake_up()`]: crate::event_loop::EventLoopProxy::wake_up
118    ///
119    /// # Example
120    ///
121    /// Use a [`std::sync::mpsc`] channel to handle events from a different thread.
122    ///
123    /// ```no_run
124    /// use std::sync::mpsc;
125    /// use std::thread;
126    /// use std::time::Duration;
127    ///
128    /// use winit::event_loop::EventLoop;
129    /// use winit_core::application::ApplicationHandler;
130    /// use winit_core::event_loop::ActiveEventLoop;
131    ///
132    /// struct MyApp {
133    ///     receiver: mpsc::Receiver<u64>,
134    /// }
135    ///
136    /// impl ApplicationHandler for MyApp {
137    ///     # fn window_event(
138    ///     #     &mut self,
139    ///     #     _event_loop: &dyn ActiveEventLoop,
140    ///     #     _window_id: winit::window::WindowId,
141    ///     #     _event: winit::event::WindowEvent,
142    ///     # ) {
143    ///     # }
144    ///     #
145    ///     # fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {}
146    ///     #
147    ///     fn proxy_wake_up(&mut self, _event_loop: &dyn ActiveEventLoop) {
148    ///         // Iterate current events, since wake-ups may have been merged.
149    ///         //
150    ///         // Note: We take care not to use `recv` or `iter` here, as those are blocking,
151    ///         // and that would be bad for performance and might lead to a deadlock.
152    ///         for i in self.receiver.try_iter() {
153    ///             println!("received: {i}");
154    ///         }
155    ///     }
156    ///
157    ///     // Rest of `ApplicationHandler`
158    /// }
159    ///
160    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
161    ///     let event_loop = EventLoop::new()?;
162    ///
163    ///     let (sender, receiver) = mpsc::channel();
164    ///
165    ///     // Send an event in a loop
166    ///     let proxy = event_loop.create_proxy();
167    ///     let background_thread = thread::spawn(move || {
168    ///         let mut i = 0;
169    ///         loop {
170    ///             println!("sending: {i}");
171    ///             if sender.send(i).is_err() {
172    ///                 // Stop sending once the receiver is dropped
173    ///                 break;
174    ///             }
175    ///             // Trigger the wake-up _after_ we placed the event in the channel.
176    ///             // Otherwise, `proxy_wake_up` might be triggered prematurely.
177    ///             proxy.wake_up();
178    ///             i += 1;
179    ///             thread::sleep(Duration::from_secs(1));
180    ///         }
181    ///     });
182    ///
183    ///     event_loop.run_app(MyApp { receiver })?;
184    ///
185    ///     background_thread.join().unwrap();
186    ///
187    ///     Ok(())
188    /// }
189    /// ```
190    fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
191        let _ = event_loop;
192    }
193
194    /// Emitted when the OS sends an event to a winit window.
195    fn window_event(
196        &mut self,
197        event_loop: &dyn ActiveEventLoop,
198        window_id: WindowId,
199        event: WindowEvent,
200    );
201
202    /// Emitted when the OS sends an event to a device.
203    ///
204    /// Whether device events are delivered depends on the backend in use.
205    fn device_event(
206        &mut self,
207        event_loop: &dyn ActiveEventLoop,
208        device_id: Option<DeviceId>,
209        event: DeviceEvent,
210    ) {
211        let _ = (event_loop, device_id, event);
212    }
213
214    /// Emitted when the event loop is about to block and wait for new events.
215    ///
216    /// Most applications shouldn't need to hook into this event since there is no real relationship
217    /// between how often the event loop needs to wake up and the dispatching of any specific
218    /// events.
219    ///
220    /// High frequency event sources, such as input devices could potentially lead to lots of wake
221    /// ups and also lots of corresponding `AboutToWait` events.
222    ///
223    /// This is not an ideal event to drive application rendering from and instead applications
224    /// should render in response to [`WindowEvent::RedrawRequested`] events.
225    fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
226        let _ = event_loop;
227    }
228
229    /// Emitted when the application has been suspended.
230    ///
231    /// See [`resumed()`][Self::resumed].
232    ///
233    /// ## Platform-specific
234    ///
235    /// ### iOS
236    ///
237    /// On iOS, the [`suspended()`] method is called in response to an
238    /// [`applicationWillResignActive`] callback which means that the application is about to
239    /// transition from the active to inactive state (according to the [iOS application lifecycle]).
240    ///
241    /// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
242    /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
243    ///
244    /// ### Web
245    ///
246    /// On Web, the [`suspended()`] method is called in response to a [`pagehide`] event if the
247    /// page is being stored in the [`bfcache`] (back/forward cache) - an in-memory cache that
248    /// stores a complete snapshot of a page (including the JavaScript heap) as the user is
249    /// navigating away.
250    ///
251    /// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
252    /// [`bfcache`]: https://web.dev/bfcache/
253    ///
254    /// ### Android
255    ///
256    /// On Android, the [`suspended()`] method is called when the `Activity` is no longer visible
257    /// to the user. This is a good place to stop refreshing UI, running animations and other visual
258    /// things. It is driven by Android's [`onStop()`] method.
259    ///
260    /// After this event the application either receives [`resumed()`] again, or will exit.
261    ///
262    /// [`onStop()`]: https://developer.android.com/reference/android/app/Activity#onStop()
263    ///
264    /// ### Others
265    ///
266    /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported.
267    ///
268    /// [`resumed()`]: Self::resumed()
269    /// [`suspended()`]: Self::suspended()
270    fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) {
271        let _ = event_loop;
272    }
273
274    /// Emitted when the application must destroy its render surfaces.
275    ///
276    /// See [`can_create_surfaces()`] for more details.
277    ///
278    /// ## Platform-specific
279    ///
280    /// ### Android
281    ///
282    /// On Android, the [`destroy_surfaces()`] method is called when the application's
283    /// [`NativeWindow`] (native [`Surface`]) is destroyed. This is expected to closely correlate
284    /// with the [`onStop`] lifecycle event which typically results in the surface to be destroyed
285    /// after the app becomes invisible.
286    ///
287    /// Applications that need to run on Android should assume their [`NativeWindow`] has been
288    /// destroyed, which indirectly invalidates any existing render surfaces that may have been
289    /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
290    ///
291    /// When receiving [`destroy_surfaces()`] Android applications should drop all render surfaces
292    /// before the event callback completes, which may be re-created when the application next
293    /// receives [`can_create_surfaces()`].
294    ///
295    /// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window
296    /// [`Surface`]: https://developer.android.com/reference/android/view/Surface
297    /// [`onStop`]: https://developer.android.com/reference/android/app/Activity#onStop()
298    /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
299    /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
300    ///
301    /// ### Others
302    ///
303    /// - **iOS / macOS / Orbital / Wayland / Web / Windows / X11:** Unsupported.
304    ///
305    /// [`can_create_surfaces()`]: Self::can_create_surfaces()
306    /// [`destroy_surfaces()`]: Self::destroy_surfaces()
307    fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
308        let _ = event_loop;
309    }
310
311    /// Emitted when the application has received a memory warning.
312    ///
313    /// ## Platform-specific
314    ///
315    /// ### Android
316    ///
317    /// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The
318    /// application must [release memory] or risk being killed.
319    ///
320    /// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory()
321    /// [release memory]: https://developer.android.com/topic/performance/memory#release
322    ///
323    /// ### iOS
324    ///
325    /// On iOS, the `MemoryWarning` event is emitted in response to an
326    /// [`applicationDidReceiveMemoryWarning`] callback. The application must free as much
327    /// memory as possible or risk being terminated, see [how to respond to memory warnings].
328    ///
329    /// [`applicationDidReceiveMemoryWarning`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623063-applicationdidreceivememorywarni
330    /// [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
331    ///
332    /// ### Others
333    ///
334    /// - **macOS / Orbital / Wayland / Web / Windows:** Unsupported.
335    fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
336        let _ = event_loop;
337    }
338
339    /// The macOS-specific handler.
340    ///
341    /// The return value from this should not change at runtime.
342    #[inline(always)]
343    fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> {
344        None
345    }
346}
347
348#[deny(clippy::missing_trait_methods)]
349impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
350    #[inline]
351    fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
352        (**self).new_events(event_loop, cause);
353    }
354
355    #[inline]
356    fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) {
357        (**self).resumed(event_loop);
358    }
359
360    #[inline]
361    fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
362        (**self).can_create_surfaces(event_loop);
363    }
364
365    #[inline]
366    fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
367        (**self).proxy_wake_up(event_loop);
368    }
369
370    #[inline]
371    fn window_event(
372        &mut self,
373        event_loop: &dyn ActiveEventLoop,
374        window_id: WindowId,
375        event: WindowEvent,
376    ) {
377        (**self).window_event(event_loop, window_id, event);
378    }
379
380    #[inline]
381    fn device_event(
382        &mut self,
383        event_loop: &dyn ActiveEventLoop,
384        device_id: Option<DeviceId>,
385        event: DeviceEvent,
386    ) {
387        (**self).device_event(event_loop, device_id, event);
388    }
389
390    #[inline]
391    fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
392        (**self).about_to_wait(event_loop);
393    }
394
395    #[inline]
396    fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) {
397        (**self).suspended(event_loop);
398    }
399
400    #[inline]
401    fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
402        (**self).destroy_surfaces(event_loop);
403    }
404
405    #[inline]
406    fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
407        (**self).memory_warning(event_loop);
408    }
409
410    #[inline]
411    fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> {
412        (**self).macos_handler()
413    }
414}
415
416#[deny(clippy::missing_trait_methods)]
417impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
418    #[inline]
419    fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
420        (**self).new_events(event_loop, cause);
421    }
422
423    #[inline]
424    fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) {
425        (**self).resumed(event_loop);
426    }
427
428    #[inline]
429    fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
430        (**self).can_create_surfaces(event_loop);
431    }
432
433    #[inline]
434    fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
435        (**self).proxy_wake_up(event_loop);
436    }
437
438    #[inline]
439    fn window_event(
440        &mut self,
441        event_loop: &dyn ActiveEventLoop,
442        window_id: WindowId,
443        event: WindowEvent,
444    ) {
445        (**self).window_event(event_loop, window_id, event);
446    }
447
448    #[inline]
449    fn device_event(
450        &mut self,
451        event_loop: &dyn ActiveEventLoop,
452        device_id: Option<DeviceId>,
453        event: DeviceEvent,
454    ) {
455        (**self).device_event(event_loop, device_id, event);
456    }
457
458    #[inline]
459    fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
460        (**self).about_to_wait(event_loop);
461    }
462
463    #[inline]
464    fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) {
465        (**self).suspended(event_loop);
466    }
467
468    #[inline]
469    fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
470        (**self).destroy_surfaces(event_loop);
471    }
472
473    #[inline]
474    fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
475        (**self).memory_warning(event_loop);
476    }
477
478    #[inline]
479    fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> {
480        (**self).macos_handler()
481    }
482}