winit_core/event_loop/mod.rs
1pub mod never_return;
2pub mod pump_events;
3pub mod register;
4pub mod run_on_demand;
5
6use std::fmt::{self, Debug};
7use std::sync::Arc;
8use std::sync::atomic::{AtomicUsize, Ordering};
9use std::time::Duration;
10
11use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
12
13use crate::Instant;
14use crate::as_any::AsAny;
15use crate::cursor::{CustomCursor, CustomCursorSource};
16use crate::error::RequestError;
17use crate::monitor::MonitorHandle;
18use crate::window::{Theme, Window, WindowAttributes};
19
20pub trait ActiveEventLoop: AsAny + fmt::Debug {
21 /// Creates an [`EventLoopProxy`] that can be used to dispatch user events
22 /// to the main event loop, possibly from another thread.
23 fn create_proxy(&self) -> EventLoopProxy;
24
25 /// Create the window.
26 ///
27 /// Possible causes of error include denied permission, incompatible system, and lack of memory.
28 ///
29 /// ## Platform-specific
30 ///
31 /// - **Web:** The window is created but not inserted into the Web page automatically. Please
32 /// see the Web platform module for more information.
33 fn create_window(
34 &self,
35 window_attributes: WindowAttributes,
36 ) -> Result<Box<dyn Window>, RequestError>;
37
38 /// Create custom cursor.
39 ///
40 /// ## Platform-specific
41 ///
42 /// **iOS / Android / Orbital:** Unsupported.
43 fn create_custom_cursor(
44 &self,
45 custom_cursor: CustomCursorSource,
46 ) -> Result<CustomCursor, RequestError>;
47
48 /// Returns the list of all the monitors available on the system.
49 ///
50 /// ## Platform-specific
51 ///
52 /// **Web:** Only returns the current monitor without `detailed monitor permissions`.
53 fn available_monitors(&self) -> Box<dyn Iterator<Item = MonitorHandle>>;
54
55 /// Returns the primary monitor of the system.
56 ///
57 /// Returns `None` if it can't identify any monitor as a primary one.
58 ///
59 /// ## Platform-specific
60 ///
61 /// - **Wayland:** Always returns `None`.
62 /// - **Web:** Always returns `None` without `detailed monitor permissions`.
63 fn primary_monitor(&self) -> Option<MonitorHandle>;
64
65 /// Change if or when [`DeviceEvent`]s are captured.
66 ///
67 /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
68 /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing
69 /// this at runtime to explicitly capture them again.
70 ///
71 /// ## Platform-specific
72 ///
73 /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported.
74 ///
75 /// [`DeviceEvent`]: crate::event::DeviceEvent
76 fn listen_device_events(&self, allowed: DeviceEvents);
77
78 /// Returns the current system theme.
79 ///
80 /// Returns `None` if it cannot be determined on the current platform.
81 ///
82 /// ## Platform-specific
83 ///
84 /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
85 fn system_theme(&self) -> Option<Theme>;
86
87 /// Sets the [`ControlFlow`].
88 fn set_control_flow(&self, control_flow: ControlFlow);
89
90 /// Gets the current [`ControlFlow`].
91 fn control_flow(&self) -> ControlFlow;
92
93 /// Stop the event loop.
94 ///
95 /// ## Platform-specific
96 ///
97 /// ### iOS
98 ///
99 /// It is not possible to programmatically exit/quit an application on iOS, so this function is
100 /// a no-op there. See also [this technical Q&A][qa1561].
101 ///
102 /// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html
103 fn exit(&self);
104
105 /// Returns whether the [`ActiveEventLoop`] is about to stop.
106 ///
107 /// Set by [`exit()`][Self::exit].
108 fn exiting(&self) -> bool;
109
110 /// Gets a persistent reference to the underlying platform display.
111 ///
112 /// See the [`OwnedDisplayHandle`] type for more information.
113 fn owned_display_handle(&self) -> OwnedDisplayHandle;
114
115 /// Get the raw-window-handle handle.
116 fn rwh_06_handle(&self) -> &dyn HasDisplayHandle;
117}
118
119impl HasDisplayHandle for dyn ActiveEventLoop + '_ {
120 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
121 self.rwh_06_handle().display_handle()
122 }
123}
124
125impl_dyn_casting!(ActiveEventLoop);
126
127/// Control the [`ActiveEventLoop`], possibly from a different thread, without referencing it
128/// directly.
129#[derive(Clone, Debug)]
130pub struct EventLoopProxy {
131 pub(crate) proxy: Arc<dyn EventLoopProxyProvider>,
132}
133
134impl EventLoopProxy {
135 /// Wake up the [`ActiveEventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being
136 /// called.
137 ///
138 /// Calls to this method are coalesced into a single call to [`proxy_wake_up`], see the
139 /// documentation on that for details.
140 ///
141 /// If the event loop is no longer running, this is a no-op.
142 ///
143 /// [`proxy_wake_up`]: crate::application::ApplicationHandler::proxy_wake_up
144 /// [`ApplicationHandler::proxy_wake_up()`]: crate::application::ApplicationHandler::proxy_wake_up
145 ///
146 /// # Platform-specific
147 ///
148 /// - **Windows**: The wake-up may be ignored under high contention, see [#3687].
149 ///
150 /// [#3687]: https://github.com/rust-windowing/winit/pull/3687
151 pub fn wake_up(&self) {
152 self.proxy.wake_up();
153 }
154
155 pub fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> Self {
156 Self { proxy }
157 }
158}
159
160pub trait EventLoopProxyProvider: Send + Sync + Debug {
161 /// See [`EventLoopProxy::wake_up`] for details.
162 fn wake_up(&self);
163}
164
165/// A proxy for the underlying display handle.
166///
167/// The purpose of this type is to provide a cheaply cloneable handle to the underlying
168/// display handle. This is often used by graphics APIs to connect to the underlying APIs.
169/// It is difficult to keep a handle to the underlying event loop type or the [`ActiveEventLoop`]
170/// type. In contrast, this type involves no lifetimes and can be persisted for as long as
171/// needed.
172///
173/// For all platforms, this is one of the following:
174///
175/// - A zero-sized type that is likely optimized out.
176/// - A reference-counted pointer to the underlying type.
177#[derive(Clone)]
178pub struct OwnedDisplayHandle {
179 pub(crate) handle: Arc<dyn HasDisplayHandle>,
180}
181
182impl OwnedDisplayHandle {
183 pub fn new(handle: Arc<dyn HasDisplayHandle>) -> Self {
184 Self { handle }
185 }
186}
187
188impl HasDisplayHandle for OwnedDisplayHandle {
189 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
190 self.handle.display_handle()
191 }
192}
193
194impl fmt::Debug for OwnedDisplayHandle {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive()
197 }
198}
199
200impl PartialEq for OwnedDisplayHandle {
201 fn eq(&self, other: &Self) -> bool {
202 match (self.display_handle(), other.display_handle()) {
203 (Ok(lhs), Ok(rhs)) => lhs == rhs,
204 _ => false,
205 }
206 }
207}
208
209impl Eq for OwnedDisplayHandle {}
210
211/// Set through [`ActiveEventLoop::set_control_flow()`].
212///
213/// Indicates the desired behavior of the event loop after [`about_to_wait`] is called.
214///
215/// Defaults to [`Wait`].
216///
217/// [`Wait`]: Self::Wait
218/// [`about_to_wait`]: crate::application::ApplicationHandler::about_to_wait
219#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
220pub enum ControlFlow {
221 /// When the current loop iteration finishes, immediately begin a new iteration regardless of
222 /// whether or not new events are available to process.
223 Poll,
224
225 /// When the current loop iteration finishes, suspend the thread until another event arrives.
226 #[default]
227 Wait,
228
229 /// When the current loop iteration finishes, suspend the thread until either another event
230 /// arrives or the given time is reached.
231 ///
232 /// Useful for implementing efficient timers. Applications which want to render at the
233 /// display's native refresh rate should instead use [`Poll`] and the VSync functionality
234 /// of a graphics API to reduce odds of missed frames.
235 ///
236 /// [`Poll`]: Self::Poll
237 WaitUntil(Instant),
238}
239
240impl ControlFlow {
241 /// Creates a [`ControlFlow`] that waits until a timeout has expired.
242 ///
243 /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is
244 /// instead set to [`Wait`].
245 ///
246 /// [`WaitUntil`]: Self::WaitUntil
247 /// [`Wait`]: Self::Wait
248 pub fn wait_duration(timeout: Duration) -> Self {
249 match Instant::now().checked_add(timeout) {
250 Some(instant) => Self::WaitUntil(instant),
251 None => Self::Wait,
252 }
253 }
254}
255
256/// Control when device events are captured.
257#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
258#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
259pub enum DeviceEvents {
260 /// Report device events regardless of window focus.
261 Always,
262 /// Only capture device events while the window is focused.
263 #[default]
264 WhenFocused,
265 /// Never capture device events.
266 Never,
267}
268
269/// A unique identifier of the winit's async request.
270///
271/// This could be used to identify the async request once it's done
272/// and a specific action must be taken.
273///
274/// One of the handling scenarios could be to maintain a working list
275/// containing [`AsyncRequestSerial`] and some closure associated with it.
276/// Then once event is arriving the working list is being traversed and a job
277/// executed and removed from the list.
278#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
279pub struct AsyncRequestSerial {
280 serial: usize,
281}
282
283impl AsyncRequestSerial {
284 pub fn get() -> Self {
285 static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0);
286 // NOTE: We rely on wrap around here, while the user may just request
287 // in the loop usize::MAX times that's issue is considered on them.
288 let serial = CURRENT_SERIAL.fetch_add(1, Ordering::Relaxed);
289 Self { serial }
290 }
291}