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<T: 'static = ()> {
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: &ActiveEventLoop, cause: StartCause) {
16 let _ = (event_loop, cause);
17 }
18
19 /// Emitted when the application has been resumed.
20 ///
21 /// For consistency, all platforms emit a `Resumed` event even if they don't themselves have a
22 /// formal suspend/resume lifecycle. For systems without a formal suspend/resume lifecycle
23 /// the `Resumed` event is always emitted after the
24 /// [`NewEvents(StartCause::Init)`][StartCause::Init] event.
25 ///
26 /// # Portability
27 ///
28 /// It's recommended that applications should only initialize their graphics context and create
29 /// a window after they have received their first `Resumed` event. Some systems
30 /// (specifically Android) won't allow applications to create a render surface until they are
31 /// resumed.
32 ///
33 /// Considering that the implementation of [`Suspended`] and `Resumed` events may be internally
34 /// driven by multiple platform-specific events, and that there may be subtle differences across
35 /// platforms with how these internal events are delivered, it's recommended that applications
36 /// be able to gracefully handle redundant (i.e. back-to-back) [`Suspended`] or `Resumed`
37 /// events.
38 ///
39 /// Also see [`Suspended`] notes.
40 ///
41 /// ## Android
42 ///
43 /// On Android, the `Resumed` event is sent when a new [`SurfaceView`] has been created. This is
44 /// expected to closely correlate with the [`onResume`] lifecycle event but there may
45 /// technically be a discrepancy.
46 ///
47 /// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
48 ///
49 /// Applications that need to run on Android must wait until they have been `Resumed`
50 /// before they will be able to create a render surface (such as an `EGLSurface`,
51 /// [`VkSurfaceKHR`] or [`wgpu::Surface`]) which depend on having a
52 /// [`SurfaceView`]. Applications must also assume that if they are [`Suspended`], then their
53 /// render surfaces are invalid and should be dropped.
54 ///
55 /// Also see [`Suspended`] notes.
56 ///
57 /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
58 /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
59 /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
60 /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
61 ///
62 /// ## iOS
63 ///
64 /// On iOS, the `Resumed` event is emitted in response to an [`applicationDidBecomeActive`]
65 /// callback which means the application is "active" (according to the
66 /// [iOS application lifecycle]).
67 ///
68 /// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
69 /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
70 ///
71 /// ## Web
72 ///
73 /// On Web, the `Resumed` event is emitted in response to a [`pageshow`] event
74 /// with the property [`persisted`] being true, which means that the page is being
75 /// restored from the [`bfcache`] (back/forward cache) - an in-memory cache that
76 /// stores a complete snapshot of a page (including the JavaScript heap) as the
77 /// user is navigating away.
78 ///
79 /// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
80 /// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
81 /// [`bfcache`]: https://web.dev/bfcache/
82 /// [`Suspended`]: Self::suspended
83 fn resumed(&mut self, event_loop: &ActiveEventLoop);
84
85 /// Emitted when an event is sent from [`EventLoopProxy::send_event`].
86 ///
87 /// [`EventLoopProxy::send_event`]: crate::event_loop::EventLoopProxy::send_event
88 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
89 let _ = (event_loop, event);
90 }
91
92 /// Emitted when the OS sends an event to a winit window.
93 fn window_event(
94 &mut self,
95 event_loop: &ActiveEventLoop,
96 window_id: WindowId,
97 event: WindowEvent,
98 );
99
100 /// Emitted when the OS sends an event to a device.
101 fn device_event(
102 &mut self,
103 event_loop: &ActiveEventLoop,
104 device_id: DeviceId,
105 event: DeviceEvent,
106 ) {
107 let _ = (event_loop, device_id, event);
108 }
109
110 /// Emitted when the event loop is about to block and wait for new events.
111 ///
112 /// Most applications shouldn't need to hook into this event since there is no real relationship
113 /// between how often the event loop needs to wake up and the dispatching of any specific
114 /// events.
115 ///
116 /// High frequency event sources, such as input devices could potentially lead to lots of wake
117 /// ups and also lots of corresponding `AboutToWait` events.
118 ///
119 /// This is not an ideal event to drive application rendering from and instead applications
120 /// should render in response to [`WindowEvent::RedrawRequested`] events.
121 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
122 let _ = event_loop;
123 }
124
125 /// Emitted when the application has been suspended.
126 ///
127 /// # Portability
128 ///
129 /// Not all platforms support the notion of suspending applications, and there may be no
130 /// technical way to guarantee being able to emit a `Suspended` event if the OS has
131 /// no formal application lifecycle (currently only Android, iOS, and Web do). For this reason,
132 /// Winit does not currently try to emit pseudo `Suspended` events before the application
133 /// quits on platforms without an application lifecycle.
134 ///
135 /// Considering that the implementation of `Suspended` and [`Resumed`] events may be internally
136 /// driven by multiple platform-specific events, and that there may be subtle differences across
137 /// platforms with how these internal events are delivered, it's recommended that applications
138 /// be able to gracefully handle redundant (i.e. back-to-back) `Suspended` or [`Resumed`]
139 /// events.
140 ///
141 /// Also see [`Resumed`] notes.
142 ///
143 /// ## Android
144 ///
145 /// On Android, the `Suspended` event is only sent when the application's associated
146 /// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onPause`]
147 /// lifecycle event but there may technically be a discrepancy.
148 ///
149 /// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause()
150 ///
151 /// Applications that need to run on Android should assume their [`SurfaceView`] has been
152 /// destroyed, which indirectly invalidates any existing render surfaces that may have been
153 /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
154 ///
155 /// After being `Suspended` on Android applications must drop all render surfaces before
156 /// the event callback completes, which may be re-created when the application is next
157 /// [`Resumed`].
158 ///
159 /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
160 /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
161 /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
162 /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
163 ///
164 /// ## iOS
165 ///
166 /// On iOS, the `Suspended` event is currently emitted in response to an
167 /// [`applicationWillResignActive`] callback which means that the application is
168 /// about to transition from the active to inactive state (according to the
169 /// [iOS application lifecycle]).
170 ///
171 /// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
172 /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
173 ///
174 /// ## Web
175 ///
176 /// On Web, the `Suspended` event is emitted in response to a [`pagehide`] event
177 /// with the property [`persisted`] being true, which means that the page is being
178 /// put in the [`bfcache`] (back/forward cache) - an in-memory cache that stores a
179 /// complete snapshot of a page (including the JavaScript heap) as the user is
180 /// navigating away.
181 ///
182 /// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
183 /// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
184 /// [`bfcache`]: https://web.dev/bfcache/
185 /// [`Resumed`]: Self::resumed
186 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
187 let _ = event_loop;
188 }
189
190 /// Emitted when the event loop is being shut down.
191 ///
192 /// This is irreversible - if this method is called, it is guaranteed that the event loop
193 /// will exit right after.
194 fn exiting(&mut self, event_loop: &ActiveEventLoop) {
195 let _ = event_loop;
196 }
197
198 /// Emitted when the application has received a memory warning.
199 ///
200 /// ## Platform-specific
201 ///
202 /// ### Android
203 ///
204 /// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The
205 /// application must [release memory] or risk being killed.
206 ///
207 /// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory()
208 /// [release memory]: https://developer.android.com/topic/performance/memory#release
209 ///
210 /// ### iOS
211 ///
212 /// On iOS, the `MemoryWarning` event is emitted in response to an
213 /// [`applicationDidReceiveMemoryWarning`] callback. The application must free as much
214 /// memory as possible or risk being terminated, see [how to respond to memory warnings].
215 ///
216 /// [`applicationDidReceiveMemoryWarning`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623063-applicationdidreceivememorywarni
217 /// [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
218 ///
219 /// ### Others
220 ///
221 /// - **macOS / Orbital / Wayland / Web / Windows:** Unsupported.
222 fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
223 let _ = event_loop;
224 }
225}
226
227impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for &mut A {
228 #[inline]
229 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
230 (**self).new_events(event_loop, cause);
231 }
232
233 #[inline]
234 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
235 (**self).resumed(event_loop);
236 }
237
238 #[inline]
239 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
240 (**self).user_event(event_loop, event);
241 }
242
243 #[inline]
244 fn window_event(
245 &mut self,
246 event_loop: &ActiveEventLoop,
247 window_id: WindowId,
248 event: WindowEvent,
249 ) {
250 (**self).window_event(event_loop, window_id, event);
251 }
252
253 #[inline]
254 fn device_event(
255 &mut self,
256 event_loop: &ActiveEventLoop,
257 device_id: DeviceId,
258 event: DeviceEvent,
259 ) {
260 (**self).device_event(event_loop, device_id, event);
261 }
262
263 #[inline]
264 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
265 (**self).about_to_wait(event_loop);
266 }
267
268 #[inline]
269 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
270 (**self).suspended(event_loop);
271 }
272
273 #[inline]
274 fn exiting(&mut self, event_loop: &ActiveEventLoop) {
275 (**self).exiting(event_loop);
276 }
277
278 #[inline]
279 fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
280 (**self).memory_warning(event_loop);
281 }
282}
283
284impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for Box<A> {
285 #[inline]
286 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
287 (**self).new_events(event_loop, cause);
288 }
289
290 #[inline]
291 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
292 (**self).resumed(event_loop);
293 }
294
295 #[inline]
296 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
297 (**self).user_event(event_loop, event);
298 }
299
300 #[inline]
301 fn window_event(
302 &mut self,
303 event_loop: &ActiveEventLoop,
304 window_id: WindowId,
305 event: WindowEvent,
306 ) {
307 (**self).window_event(event_loop, window_id, event);
308 }
309
310 #[inline]
311 fn device_event(
312 &mut self,
313 event_loop: &ActiveEventLoop,
314 device_id: DeviceId,
315 event: DeviceEvent,
316 ) {
317 (**self).device_event(event_loop, device_id, event);
318 }
319
320 #[inline]
321 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
322 (**self).about_to_wait(event_loop);
323 }
324
325 #[inline]
326 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
327 (**self).suspended(event_loop);
328 }
329
330 #[inline]
331 fn exiting(&mut self, event_loop: &ActiveEventLoop) {
332 (**self).exiting(event_loop);
333 }
334
335 #[inline]
336 fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
337 (**self).memory_warning(event_loop);
338 }
339}