winit_core/monitor.rs
1//! Types useful for interacting with a user's monitors.
2//!
3//! If you want to get basic information about a monitor, you can use the
4//! [`MonitorHandle`] type. This is retrieved from one of the following
5//! methods, which return an iterator of [`MonitorHandle`]:
6//! - [`ActiveEventLoop::available_monitors`][crate::event_loop::ActiveEventLoop::available_monitors].
7//! - [`Window::available_monitors`][crate::window::Window::available_monitors].
8use std::borrow::Cow;
9use std::fmt;
10use std::num::{NonZeroU16, NonZeroU32};
11use std::ops::Deref;
12use std::sync::Arc;
13
14use dpi::{PhysicalPosition, PhysicalSize};
15
16use crate::as_any::AsAny;
17
18/// Handle to a monitor.
19///
20/// Allows you to retrieve basic information and metadata about a monitor.
21///
22/// Can be used in [`Window`] creation to place the window on a specific
23/// monitor.
24///
25/// This can be retrieved from one of the following methods, which return an
26/// iterator of [`MonitorHandle`]s:
27/// - [`ActiveEventLoop::available_monitors`](crate::event_loop::ActiveEventLoop::available_monitors).
28/// - [`Window::available_monitors`](crate::window::Window::available_monitors).
29///
30/// ## Platform-specific
31///
32/// **Web:** A [`MonitorHandle`] created without `detailed monitor permissions`
33/// will always represent the current monitor the browser window is in instead of a specific
34/// monitor.
35///
36/// [`Window`]: crate::window::Window
37#[derive(Debug, Clone)]
38pub struct MonitorHandle(pub Arc<dyn MonitorHandleProvider>);
39
40impl Deref for MonitorHandle {
41 type Target = dyn MonitorHandleProvider;
42
43 fn deref(&self) -> &Self::Target {
44 self.0.as_ref()
45 }
46}
47
48impl PartialEq for MonitorHandle {
49 fn eq(&self, other: &Self) -> bool {
50 self.0.as_ref().eq(other.0.as_ref())
51 }
52}
53
54impl Eq for MonitorHandle {}
55
56/// Provider of the [`MonitorHandle`].
57pub trait MonitorHandleProvider: AsAny + fmt::Debug + Send + Sync {
58 /// Identifier for this monitor.
59 ///
60 /// The representation of this modifier is not guaranteed and should be used only to compare
61 /// monitors.
62 fn id(&self) -> u128;
63
64 /// Native platform identifier of this monitor.
65 ///
66 /// # Platform-specific
67 ///
68 /// - **Windows**: This is `HMONITOR`.
69 /// - **macOS**: This is `CGDirectDisplayID`.
70 /// - **iOS**: This is `UIScreen*`.
71 /// - **Wayland**: This is the ID of the `wl_output` device.
72 /// - **X11**: This is the ID of the CRTC.
73 /// - **Web**: This is an internal ID not meant for consumption.
74 fn native_id(&self) -> u64;
75
76 /// Returns a human-readable name of the monitor.
77 ///
78 /// Returns `None` if the monitor doesn't exist anymore or the name couldn't be obtained.
79 ///
80 ///
81 /// ## Platform-specific
82 ///
83 /// **Web:** Always returns [`None`] without `detailed monitor permissions`.
84 fn name(&self) -> Option<Cow<'_, str>>;
85
86 /// Returns the top-left corner position of the monitor in desktop coordinates.
87 ///
88 /// This position is in the same coordinate system as [`Window::outer_position`].
89 ///
90 /// [`Window::outer_position`]: crate::window::Window::outer_position
91 ///
92 /// ## Platform-specific
93 ///
94 /// **Web:** Always returns [`None`] without `detailed monitor permissions`.
95 fn position(&self) -> Option<PhysicalPosition<i32>>;
96
97 /// Returns the scale factor of the underlying monitor. To map logical pixels to physical
98 /// pixels and vice versa, use [`Window::scale_factor`].
99 ///
100 /// See the [`dpi`] module for more information.
101 ///
102 /// - **Wayland:** May differ from [`Window::scale_factor`].
103 /// - **Web:** Always returns `0.0` without `detailed_monitor_permissions`.
104 ///
105 /// [`Window::scale_factor`]: crate::window::Window::scale_factor
106 fn scale_factor(&self) -> f64;
107
108 fn current_video_mode(&self) -> Option<VideoMode>;
109
110 /// Returns all fullscreen video modes supported by this monitor.
111 fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>>;
112}
113
114impl PartialEq for dyn MonitorHandleProvider + '_ {
115 fn eq(&self, other: &Self) -> bool {
116 self.id() == other.id()
117 }
118}
119
120impl Eq for dyn MonitorHandleProvider + '_ {}
121
122impl_dyn_casting!(MonitorHandleProvider);
123
124/// Describes a fullscreen video mode of a monitor.
125///
126/// Can be acquired with [`MonitorHandleProvider::video_modes`].
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub struct VideoMode {
129 pub(crate) size: PhysicalSize<u32>,
130 pub(crate) bit_depth: Option<NonZeroU16>,
131 pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
132}
133
134impl VideoMode {
135 pub fn new(
136 size: PhysicalSize<u32>,
137 bit_depth: Option<NonZeroU16>,
138 refresh_rate_millihertz: Option<NonZeroU32>,
139 ) -> Self {
140 Self { size, bit_depth, refresh_rate_millihertz }
141 }
142
143 /// Returns the resolution of this video mode. This **must not** be used to create your
144 /// rendering surface. Use [`Window::surface_size()`] instead.
145 ///
146 /// [`Window::surface_size()`]: crate::window::Window::surface_size
147 pub fn size(&self) -> PhysicalSize<u32> {
148 self.size
149 }
150
151 /// Returns the bit depth of this video mode, as in how many bits you have
152 /// available per color. This is generally 24 bits or 32 bits on modern
153 /// systems, depending on whether the alpha channel is counted or not.
154 ///
155 /// # Platform-specific
156 ///
157 /// - **macOS**: Video modes do not control the bit depth of the monitor, so this often defaults
158 /// to 32.
159 /// - **iOS**: Always returns `None`.
160 /// - **Wayland**: Always returns `None`.
161 pub fn bit_depth(&self) -> Option<NonZeroU16> {
162 self.bit_depth
163 }
164
165 /// Returns the refresh rate of this video mode in mHz.
166 pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
167 self.refresh_rate_millihertz
168 }
169}
170
171impl fmt::Display for VideoMode {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 write!(
174 f,
175 "{}x{} {}{}",
176 self.size.width,
177 self.size.height,
178 self.refresh_rate_millihertz.map(|rate| format!("@ {rate} mHz ")).unwrap_or_default(),
179 self.bit_depth.map(|bit_depth| format!("({bit_depth} bpp)")).unwrap_or_default(),
180 )
181 }
182}
183
184/// Fullscreen modes.
185#[derive(Clone, Debug, PartialEq, Eq)]
186pub enum Fullscreen {
187 Exclusive(MonitorHandle, VideoMode),
188
189 /// Providing `None` to `Borderless` will fullscreen on the current monitor.
190 Borderless(Option<MonitorHandle>),
191}