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}