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}