winit/
application.rs

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