1 | //! The [`EventLoop`] struct and assorted supporting types, including |
2 | //! [`ControlFlow`]. |
3 | //! |
4 | //! If you want to send custom events to the event loop, use |
5 | //! [`EventLoop::create_proxy`] to acquire an [`EventLoopProxy`] and call its |
6 | //! [`send_event`][EventLoopProxy::send_event] method. |
7 | //! |
8 | //! See the root-level documentation for information on how to create and use an event loop to |
9 | //! handle events. |
10 | use std::marker::PhantomData; |
11 | #[cfg (any(x11_platform, wayland_platform))] |
12 | use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; |
13 | use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; |
14 | use std::{error, fmt}; |
15 | |
16 | #[cfg (not(web_platform))] |
17 | use std::time::{Duration, Instant}; |
18 | #[cfg (web_platform)] |
19 | use web_time::{Duration, Instant}; |
20 | |
21 | use crate::application::ApplicationHandler; |
22 | use crate::error::{EventLoopError, OsError}; |
23 | use crate::event::Event; |
24 | use crate::monitor::MonitorHandle; |
25 | use crate::platform_impl; |
26 | use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes}; |
27 | |
28 | /// Provides a way to retrieve events from the system and from the windows that were registered to |
29 | /// the events loop. |
30 | /// |
31 | /// An `EventLoop` can be seen more or less as a "context". Calling [`EventLoop::new`] |
32 | /// initializes everything that will be required to create windows. For example on Linux creating |
33 | /// an event loop opens a connection to the X or Wayland server. |
34 | /// |
35 | /// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs. |
36 | /// |
37 | /// Note that this cannot be shared across threads (due to platform-dependant logic |
38 | /// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access, |
39 | /// the [`Window`] created from this _can_ be sent to an other thread, and the |
40 | /// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread. |
41 | /// |
42 | /// [`Window`]: crate::window::Window |
43 | pub struct EventLoop<T: 'static> { |
44 | pub(crate) event_loop: platform_impl::EventLoop<T>, |
45 | pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync |
46 | } |
47 | |
48 | /// Target that associates windows with an [`EventLoop`]. |
49 | /// |
50 | /// This type exists to allow you to create new windows while Winit executes |
51 | /// your callback. |
52 | pub struct ActiveEventLoop { |
53 | pub(crate) p: platform_impl::ActiveEventLoop, |
54 | pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync |
55 | } |
56 | |
57 | /// Object that allows building the event loop. |
58 | /// |
59 | /// This is used to make specifying options that affect the whole application |
60 | /// easier. But note that constructing multiple event loops is not supported. |
61 | /// |
62 | /// This can be created using [`EventLoop::new`] or [`EventLoop::with_user_event`]. |
63 | #[derive (Default)] |
64 | pub struct EventLoopBuilder<T: 'static> { |
65 | pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes, |
66 | _p: PhantomData<T>, |
67 | } |
68 | |
69 | static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false); |
70 | |
71 | impl EventLoopBuilder<()> { |
72 | /// Start building a new event loop. |
73 | #[inline ] |
74 | #[deprecated = "use `EventLoop::builder` instead" ] |
75 | pub fn new() -> Self { |
76 | EventLoop::builder() |
77 | } |
78 | } |
79 | |
80 | impl<T> EventLoopBuilder<T> { |
81 | /// Builds a new event loop. |
82 | /// |
83 | /// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread, |
84 | /// and only once per application.*** |
85 | /// |
86 | /// Calling this function will result in display backend initialisation. |
87 | /// |
88 | /// ## Panics |
89 | /// |
90 | /// Attempting to create the event loop off the main thread will panic. This |
91 | /// restriction isn't strictly necessary on all platforms, but is imposed to |
92 | /// eliminate any nasty surprises when porting to platforms that require it. |
93 | /// `EventLoopBuilderExt::any_thread` functions are exposed in the relevant |
94 | /// [`platform`] module if the target platform supports creating an event |
95 | /// loop on any thread. |
96 | /// |
97 | /// ## Platform-specific |
98 | /// |
99 | /// - **Wayland/X11:** to prevent running under `Wayland` or `X11` unset `WAYLAND_DISPLAY` or |
100 | /// `DISPLAY` respectively when building the event loop. |
101 | /// - **Android:** must be configured with an `AndroidApp` from `android_main()` by calling |
102 | /// [`.with_android_app(app)`] before calling `.build()`, otherwise it'll panic. |
103 | /// |
104 | /// [`platform`]: crate::platform |
105 | #[cfg_attr ( |
106 | android_platform, |
107 | doc = "[`.with_android_app(app)`]: \ |
108 | crate::platform::android::EventLoopBuilderExtAndroid::with_android_app" |
109 | )] |
110 | #[cfg_attr ( |
111 | not(android_platform), |
112 | doc = "[`.with_android_app(app)`]: #only-available-on-android" |
113 | )] |
114 | #[inline ] |
115 | pub fn build(&mut self) -> Result<EventLoop<T>, EventLoopError> { |
116 | let _span = tracing::debug_span!("winit::EventLoopBuilder::build" ).entered(); |
117 | |
118 | if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) { |
119 | return Err(EventLoopError::RecreationAttempt); |
120 | } |
121 | |
122 | // Certain platforms accept a mutable reference in their API. |
123 | #[allow (clippy::unnecessary_mut_passed)] |
124 | Ok(EventLoop { |
125 | event_loop: platform_impl::EventLoop::new(&mut self.platform_specific)?, |
126 | _marker: PhantomData, |
127 | }) |
128 | } |
129 | |
130 | #[cfg (web_platform)] |
131 | pub(crate) fn allow_event_loop_recreation() { |
132 | EVENT_LOOP_CREATED.store(false, Ordering::Relaxed); |
133 | } |
134 | } |
135 | |
136 | impl<T> fmt::Debug for EventLoop<T> { |
137 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
138 | f.pad("EventLoop { .. }" ) |
139 | } |
140 | } |
141 | |
142 | impl fmt::Debug for ActiveEventLoop { |
143 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
144 | f.pad("ActiveEventLoop { .. }" ) |
145 | } |
146 | } |
147 | |
148 | /// Set through [`ActiveEventLoop::set_control_flow()`]. |
149 | /// |
150 | /// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted. |
151 | /// |
152 | /// Defaults to [`Wait`]. |
153 | /// |
154 | /// [`Wait`]: Self::Wait |
155 | #[derive (Copy, Clone, Debug, Default, PartialEq, Eq)] |
156 | pub enum ControlFlow { |
157 | /// When the current loop iteration finishes, immediately begin a new iteration regardless of |
158 | /// whether or not new events are available to process. |
159 | Poll, |
160 | |
161 | /// When the current loop iteration finishes, suspend the thread until another event arrives. |
162 | #[default] |
163 | Wait, |
164 | |
165 | /// When the current loop iteration finishes, suspend the thread until either another event |
166 | /// arrives or the given time is reached. |
167 | /// |
168 | /// Useful for implementing efficient timers. Applications which want to render at the |
169 | /// display's native refresh rate should instead use [`Poll`] and the VSync functionality |
170 | /// of a graphics API to reduce odds of missed frames. |
171 | /// |
172 | /// [`Poll`]: Self::Poll |
173 | WaitUntil(Instant), |
174 | } |
175 | |
176 | impl ControlFlow { |
177 | /// Creates a [`ControlFlow`] that waits until a timeout has expired. |
178 | /// |
179 | /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is |
180 | /// instead set to [`Wait`]. |
181 | /// |
182 | /// [`WaitUntil`]: Self::WaitUntil |
183 | /// [`Wait`]: Self::Wait |
184 | pub fn wait_duration(timeout: Duration) -> Self { |
185 | match Instant::now().checked_add(duration:timeout) { |
186 | Some(instant: Instant) => Self::WaitUntil(instant), |
187 | None => Self::Wait, |
188 | } |
189 | } |
190 | } |
191 | |
192 | impl EventLoop<()> { |
193 | /// Create the event loop. |
194 | /// |
195 | /// This is an alias of `EventLoop::builder().build()`. |
196 | #[inline ] |
197 | pub fn new() -> Result<EventLoop<()>, EventLoopError> { |
198 | Self::builder().build() |
199 | } |
200 | |
201 | /// Start building a new event loop. |
202 | /// |
203 | /// This returns an [`EventLoopBuilder`], to allow configuring the event loop before creation. |
204 | /// |
205 | /// To get the actual event loop, call [`build`][EventLoopBuilder::build] on that. |
206 | #[inline ] |
207 | pub fn builder() -> EventLoopBuilder<()> { |
208 | Self::with_user_event() |
209 | } |
210 | } |
211 | |
212 | impl<T> EventLoop<T> { |
213 | /// Start building a new event loop, with the given type as the user event |
214 | /// type. |
215 | pub fn with_user_event() -> EventLoopBuilder<T> { |
216 | EventLoopBuilder { platform_specific: Default::default(), _p: PhantomData } |
217 | } |
218 | |
219 | /// See [`run_app`]. |
220 | /// |
221 | /// [`run_app`]: Self::run_app |
222 | #[inline ] |
223 | #[deprecated = "use `EventLoop::run_app` instead" ] |
224 | #[cfg (not(all(web_platform, target_feature = "exception-handling" )))] |
225 | pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError> |
226 | where |
227 | F: FnMut(Event<T>, &ActiveEventLoop), |
228 | { |
229 | let _span = tracing::debug_span!("winit::EventLoop::run" ).entered(); |
230 | |
231 | self.event_loop.run(event_handler) |
232 | } |
233 | |
234 | /// Run the application with the event loop on the calling thread. |
235 | /// |
236 | /// See the [`set_control_flow()`] docs on how to change the event loop's behavior. |
237 | /// |
238 | /// ## Platform-specific |
239 | /// |
240 | /// - **iOS:** Will never return to the caller and so values not passed to this function will |
241 | /// *not* be dropped before the process exits. |
242 | /// - **Web:** Will _act_ as if it never returns to the caller by throwing a Javascript |
243 | /// exception (that Rust doesn't see) that will also mean that the rest of the function is |
244 | /// never executed and any values not passed to this function will *not* be dropped. |
245 | /// |
246 | /// Web applications are recommended to use |
247 | #[cfg_attr ( |
248 | web_platform, |
249 | doc = "[`EventLoopExtWebSys::spawn_app()`][crate::platform::web::EventLoopExtWebSys::spawn_app()]" |
250 | )] |
251 | #[cfg_attr (not(web_platform), doc = "`EventLoopExtWebSys::spawn()`" )] |
252 | /// [^1] instead of [`run_app()`] to avoid the need |
253 | /// for the Javascript exception trick, and to make it clearer that the event loop runs |
254 | /// asynchronously (via the browser's own, internal, event loop) and doesn't block the |
255 | /// current thread of execution like it does on other platforms. |
256 | /// |
257 | /// This function won't be available with `target_feature = "exception-handling"`. |
258 | /// |
259 | /// [`set_control_flow()`]: ActiveEventLoop::set_control_flow() |
260 | /// [`run_app()`]: Self::run_app() |
261 | /// [^1]: `EventLoopExtWebSys::spawn_app()` is only available on Web. |
262 | #[inline ] |
263 | #[cfg (not(all(web_platform, target_feature = "exception-handling" )))] |
264 | pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> { |
265 | self.event_loop.run(|event, event_loop| dispatch_event_for_app(app, event_loop, event)) |
266 | } |
267 | |
268 | /// Creates an [`EventLoopProxy`] that can be used to dispatch user events |
269 | /// to the main event loop, possibly from another thread. |
270 | pub fn create_proxy(&self) -> EventLoopProxy<T> { |
271 | EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy() } |
272 | } |
273 | |
274 | /// Gets a persistent reference to the underlying platform display. |
275 | /// |
276 | /// See the [`OwnedDisplayHandle`] type for more information. |
277 | pub fn owned_display_handle(&self) -> OwnedDisplayHandle { |
278 | OwnedDisplayHandle { platform: self.event_loop.window_target().p.owned_display_handle() } |
279 | } |
280 | |
281 | /// Change if or when [`DeviceEvent`]s are captured. |
282 | /// |
283 | /// See [`ActiveEventLoop::listen_device_events`] for details. |
284 | /// |
285 | /// [`DeviceEvent`]: crate::event::DeviceEvent |
286 | pub fn listen_device_events(&self, allowed: DeviceEvents) { |
287 | let _span = tracing::debug_span!( |
288 | "winit::EventLoop::listen_device_events" , |
289 | allowed = ?allowed |
290 | ) |
291 | .entered(); |
292 | |
293 | self.event_loop.window_target().p.listen_device_events(allowed); |
294 | } |
295 | |
296 | /// Sets the [`ControlFlow`]. |
297 | pub fn set_control_flow(&self, control_flow: ControlFlow) { |
298 | self.event_loop.window_target().p.set_control_flow(control_flow) |
299 | } |
300 | |
301 | /// Create a window. |
302 | /// |
303 | /// Creating window without event loop running often leads to improper window creation; |
304 | /// use [`ActiveEventLoop::create_window`] instead. |
305 | #[deprecated = "use `ActiveEventLoop::create_window` instead" ] |
306 | #[inline ] |
307 | pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> { |
308 | let _span = tracing::debug_span!( |
309 | "winit::EventLoop::create_window" , |
310 | window_attributes = ?window_attributes |
311 | ) |
312 | .entered(); |
313 | |
314 | let window = |
315 | platform_impl::Window::new(&self.event_loop.window_target().p, window_attributes)?; |
316 | Ok(Window { window }) |
317 | } |
318 | |
319 | /// Create custom cursor. |
320 | pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor { |
321 | self.event_loop.window_target().p.create_custom_cursor(custom_cursor) |
322 | } |
323 | } |
324 | |
325 | #[cfg (feature = "rwh_06" )] |
326 | impl<T> rwh_06::HasDisplayHandle for EventLoop<T> { |
327 | fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> { |
328 | rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target()) |
329 | } |
330 | } |
331 | |
332 | #[cfg (feature = "rwh_05" )] |
333 | unsafe impl<T> rwh_05::HasRawDisplayHandle for EventLoop<T> { |
334 | /// Returns a [`rwh_05::RawDisplayHandle`] for the event loop. |
335 | fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { |
336 | rwh_05::HasRawDisplayHandle::raw_display_handle(self.event_loop.window_target()) |
337 | } |
338 | } |
339 | |
340 | #[cfg (any(x11_platform, wayland_platform))] |
341 | impl<T> AsFd for EventLoop<T> { |
342 | /// Get the underlying [EventLoop]'s `fd` which you can register |
343 | /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the |
344 | /// loop must be polled with the [`pump_app_events`] API. |
345 | /// |
346 | /// [`calloop`]: https://crates.io/crates/calloop |
347 | /// [`mio`]: https://crates.io/crates/mio |
348 | /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events |
349 | fn as_fd(&self) -> BorrowedFd<'_> { |
350 | self.event_loop.as_fd() |
351 | } |
352 | } |
353 | |
354 | #[cfg (any(x11_platform, wayland_platform))] |
355 | impl<T> AsRawFd for EventLoop<T> { |
356 | /// Get the underlying [EventLoop]'s raw `fd` which you can register |
357 | /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the |
358 | /// loop must be polled with the [`pump_app_events`] API. |
359 | /// |
360 | /// [`calloop`]: https://crates.io/crates/calloop |
361 | /// [`mio`]: https://crates.io/crates/mio |
362 | /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events |
363 | fn as_raw_fd(&self) -> RawFd { |
364 | self.event_loop.as_raw_fd() |
365 | } |
366 | } |
367 | |
368 | impl ActiveEventLoop { |
369 | /// Create the window. |
370 | /// |
371 | /// Possible causes of error include denied permission, incompatible system, and lack of memory. |
372 | /// |
373 | /// ## Platform-specific |
374 | /// |
375 | /// - **Web:** The window is created but not inserted into the web page automatically. Please |
376 | /// see the web platform module for more information. |
377 | #[inline ] |
378 | pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> { |
379 | let _span = tracing::debug_span!( |
380 | "winit::ActiveEventLoop::create_window" , |
381 | window_attributes = ?window_attributes |
382 | ) |
383 | .entered(); |
384 | |
385 | let window = platform_impl::Window::new(&self.p, window_attributes)?; |
386 | Ok(Window { window }) |
387 | } |
388 | |
389 | /// Create custom cursor. |
390 | pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor { |
391 | let _span = tracing::debug_span!("winit::ActiveEventLoop::create_custom_cursor" ,).entered(); |
392 | |
393 | self.p.create_custom_cursor(custom_cursor) |
394 | } |
395 | |
396 | /// Returns the list of all the monitors available on the system. |
397 | #[inline ] |
398 | pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> { |
399 | let _span = tracing::debug_span!("winit::ActiveEventLoop::available_monitors" ,).entered(); |
400 | |
401 | #[allow (clippy::useless_conversion)] // false positive on some platforms |
402 | self.p.available_monitors().into_iter().map(|inner| MonitorHandle { inner }) |
403 | } |
404 | |
405 | /// Returns the primary monitor of the system. |
406 | /// |
407 | /// Returns `None` if it can't identify any monitor as a primary one. |
408 | /// |
409 | /// ## Platform-specific |
410 | /// |
411 | /// **Wayland / Web:** Always returns `None`. |
412 | #[inline ] |
413 | pub fn primary_monitor(&self) -> Option<MonitorHandle> { |
414 | let _span = tracing::debug_span!("winit::ActiveEventLoop::primary_monitor" ,).entered(); |
415 | |
416 | self.p.primary_monitor().map(|inner| MonitorHandle { inner }) |
417 | } |
418 | |
419 | /// Change if or when [`DeviceEvent`]s are captured. |
420 | /// |
421 | /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit |
422 | /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing |
423 | /// this at runtime to explicitly capture them again. |
424 | /// |
425 | /// ## Platform-specific |
426 | /// |
427 | /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported. |
428 | /// |
429 | /// [`DeviceEvent`]: crate::event::DeviceEvent |
430 | pub fn listen_device_events(&self, allowed: DeviceEvents) { |
431 | let _span = tracing::debug_span!( |
432 | "winit::ActiveEventLoop::listen_device_events" , |
433 | allowed = ?allowed |
434 | ) |
435 | .entered(); |
436 | |
437 | self.p.listen_device_events(allowed); |
438 | } |
439 | |
440 | /// Returns the current system theme. |
441 | /// |
442 | /// Returns `None` if it cannot be determined on the current platform. |
443 | /// |
444 | /// ## Platform-specific |
445 | /// |
446 | /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported. |
447 | pub fn system_theme(&self) -> Option<Theme> { |
448 | self.p.system_theme() |
449 | } |
450 | |
451 | /// Sets the [`ControlFlow`]. |
452 | pub fn set_control_flow(&self, control_flow: ControlFlow) { |
453 | self.p.set_control_flow(control_flow) |
454 | } |
455 | |
456 | /// Gets the current [`ControlFlow`]. |
457 | pub fn control_flow(&self) -> ControlFlow { |
458 | self.p.control_flow() |
459 | } |
460 | |
461 | /// This exits the event loop. |
462 | /// |
463 | /// See [`LoopExiting`][Event::LoopExiting]. |
464 | pub fn exit(&self) { |
465 | let _span = tracing::debug_span!("winit::ActiveEventLoop::exit" ,).entered(); |
466 | |
467 | self.p.exit() |
468 | } |
469 | |
470 | /// Returns if the [`EventLoop`] is about to stop. |
471 | /// |
472 | /// See [`exit()`][Self::exit]. |
473 | pub fn exiting(&self) -> bool { |
474 | self.p.exiting() |
475 | } |
476 | |
477 | /// Gets a persistent reference to the underlying platform display. |
478 | /// |
479 | /// See the [`OwnedDisplayHandle`] type for more information. |
480 | pub fn owned_display_handle(&self) -> OwnedDisplayHandle { |
481 | OwnedDisplayHandle { platform: self.p.owned_display_handle() } |
482 | } |
483 | } |
484 | |
485 | #[cfg (feature = "rwh_06" )] |
486 | impl rwh_06::HasDisplayHandle for ActiveEventLoop { |
487 | fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> { |
488 | let raw: RawDisplayHandle = self.p.raw_display_handle_rwh_06()?; |
489 | // SAFETY: The display will never be deallocated while the event loop is alive. |
490 | Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) }) |
491 | } |
492 | } |
493 | |
494 | #[cfg (feature = "rwh_05" )] |
495 | unsafe impl rwh_05::HasRawDisplayHandle for ActiveEventLoop { |
496 | /// Returns a [`rwh_05::RawDisplayHandle`] for the event loop. |
497 | fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { |
498 | self.p.raw_display_handle_rwh_05() |
499 | } |
500 | } |
501 | |
502 | /// A proxy for the underlying display handle. |
503 | /// |
504 | /// The purpose of this type is to provide a cheaply cloneable handle to the underlying |
505 | /// display handle. This is often used by graphics APIs to connect to the underlying APIs. |
506 | /// It is difficult to keep a handle to the [`EventLoop`] type or the [`ActiveEventLoop`] |
507 | /// type. In contrast, this type involves no lifetimes and can be persisted for as long as |
508 | /// needed. |
509 | /// |
510 | /// For all platforms, this is one of the following: |
511 | /// |
512 | /// - A zero-sized type that is likely optimized out. |
513 | /// - A reference-counted pointer to the underlying type. |
514 | #[derive (Clone)] |
515 | pub struct OwnedDisplayHandle { |
516 | #[cfg_attr (not(any(feature = "rwh_05" , feature = "rwh_06" )), allow(dead_code))] |
517 | platform: platform_impl::OwnedDisplayHandle, |
518 | } |
519 | |
520 | impl fmt::Debug for OwnedDisplayHandle { |
521 | #[inline ] |
522 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
523 | f.debug_struct(name:"OwnedDisplayHandle" ).finish_non_exhaustive() |
524 | } |
525 | } |
526 | |
527 | #[cfg (feature = "rwh_06" )] |
528 | impl rwh_06::HasDisplayHandle for OwnedDisplayHandle { |
529 | #[inline ] |
530 | fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> { |
531 | let raw: RawDisplayHandle = self.platform.raw_display_handle_rwh_06()?; |
532 | |
533 | // SAFETY: The underlying display handle should be safe. |
534 | let handle: DisplayHandle<'_> = unsafe { rwh_06::DisplayHandle::borrow_raw(raw) }; |
535 | |
536 | Ok(handle) |
537 | } |
538 | } |
539 | |
540 | #[cfg (feature = "rwh_05" )] |
541 | unsafe impl rwh_05::HasRawDisplayHandle for OwnedDisplayHandle { |
542 | #[inline ] |
543 | fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { |
544 | self.platform.raw_display_handle_rwh_05() |
545 | } |
546 | } |
547 | |
548 | /// Used to send custom events to [`EventLoop`]. |
549 | pub struct EventLoopProxy<T: 'static> { |
550 | event_loop_proxy: platform_impl::EventLoopProxy<T>, |
551 | } |
552 | |
553 | impl<T: 'static> Clone for EventLoopProxy<T> { |
554 | fn clone(&self) -> Self { |
555 | Self { event_loop_proxy: self.event_loop_proxy.clone() } |
556 | } |
557 | } |
558 | |
559 | impl<T: 'static> EventLoopProxy<T> { |
560 | /// Send an event to the [`EventLoop`] from which this proxy was created. This emits a |
561 | /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this |
562 | /// function. |
563 | /// |
564 | /// Returns an `Err` if the associated [`EventLoop`] no longer exists. |
565 | /// |
566 | /// [`UserEvent(event)`]: Event::UserEvent |
567 | pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { |
568 | let _span: EnteredSpan = tracing::debug_span!("winit::EventLoopProxy::send_event" ,).entered(); |
569 | |
570 | self.event_loop_proxy.send_event(event) |
571 | } |
572 | } |
573 | |
574 | impl<T: 'static> fmt::Debug for EventLoopProxy<T> { |
575 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
576 | f.pad("EventLoopProxy { .. }" ) |
577 | } |
578 | } |
579 | |
580 | /// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that |
581 | /// no longer exists. |
582 | /// |
583 | /// Contains the original event given to [`EventLoopProxy::send_event`]. |
584 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
585 | pub struct EventLoopClosed<T>(pub T); |
586 | |
587 | impl<T> fmt::Display for EventLoopClosed<T> { |
588 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
589 | f.write_str(data:"Tried to wake up a closed `EventLoop`" ) |
590 | } |
591 | } |
592 | |
593 | impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {} |
594 | |
595 | /// Control when device events are captured. |
596 | #[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] |
597 | pub enum DeviceEvents { |
598 | /// Report device events regardless of window focus. |
599 | Always, |
600 | /// Only capture device events while the window is focused. |
601 | #[default] |
602 | WhenFocused, |
603 | /// Never capture device events. |
604 | Never, |
605 | } |
606 | |
607 | /// A unique identifier of the winit's async request. |
608 | /// |
609 | /// This could be used to identify the async request once it's done |
610 | /// and a specific action must be taken. |
611 | /// |
612 | /// One of the handling scenarios could be to maintain a working list |
613 | /// containing [`AsyncRequestSerial`] and some closure associated with it. |
614 | /// Then once event is arriving the working list is being traversed and a job |
615 | /// executed and removed from the list. |
616 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
617 | pub struct AsyncRequestSerial { |
618 | serial: usize, |
619 | } |
620 | |
621 | impl AsyncRequestSerial { |
622 | // TODO(kchibisov): Remove `cfg` when the clipboard will be added. |
623 | #[allow (dead_code)] |
624 | pub(crate) fn get() -> Self { |
625 | static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0); |
626 | // NOTE: We rely on wrap around here, while the user may just request |
627 | // in the loop usize::MAX times that's issue is considered on them. |
628 | let serial: usize = CURRENT_SERIAL.fetch_add(val:1, order:Ordering::Relaxed); |
629 | Self { serial } |
630 | } |
631 | } |
632 | |
633 | /// Shim for various run APIs. |
634 | #[inline (always)] |
635 | pub(crate) fn dispatch_event_for_app<T: 'static, A: ApplicationHandler<T>>( |
636 | app: &mut A, |
637 | event_loop: &ActiveEventLoop, |
638 | event: Event<T>, |
639 | ) { |
640 | match event { |
641 | Event::NewEvents(cause: StartCause) => app.new_events(event_loop, cause), |
642 | Event::WindowEvent { window_id: WindowId, event: WindowEvent } => app.window_event(event_loop, window_id, event), |
643 | Event::DeviceEvent { device_id: DeviceId, event: DeviceEvent } => app.device_event(event_loop, device_id, event), |
644 | Event::UserEvent(event: T) => app.user_event(event_loop, event), |
645 | Event::Suspended => app.suspended(event_loop), |
646 | Event::Resumed => app.resumed(event_loop), |
647 | Event::AboutToWait => app.about_to_wait(event_loop), |
648 | Event::LoopExiting => app.exiting(event_loop), |
649 | Event::MemoryWarning => app.memory_warning(event_loop), |
650 | } |
651 | } |
652 | |