winit-core: move monitor handle

This commit is contained in:
Kirill Chibisov 2025-05-01 19:35:04 +09:00
parent 3493a20173
commit 3142355417
10 changed files with 43 additions and 32 deletions

View file

@ -77,6 +77,7 @@ changelog entry.
- Add `CustomCursorSource::Url`, `CustomCursorSource::from_animation`.
- Implement `CustomIconProvider` for `RgbaIcon`.
- Add `icon` module that exposes winit's icon API.
- `VideoMode::new` to create a `VideoMode`.
### Changed

View file

@ -306,7 +306,7 @@ pub mod event;
pub mod event_loop;
pub mod icon;
pub mod keyboard;
pub mod monitor;
pub use winit_core::monitor;
mod platform_impl;
use winit_core::as_any as utils;
pub mod window;

View file

@ -1,205 +0,0 @@
//! Types useful for interacting with a user's monitors.
//!
//! If you want to get basic information about a monitor, you can use the
//! [`MonitorHandle`] type. This is retrieved from one of the following
//! methods, which return an iterator of [`MonitorHandle`]:
//! - [`ActiveEventLoop::available_monitors`][crate::event_loop::ActiveEventLoop::available_monitors].
//! - [`Window::available_monitors`][crate::window::Window::available_monitors].
use std::borrow::Cow;
use std::fmt;
use std::num::{NonZeroU16, NonZeroU32};
use std::ops::Deref;
use std::sync::Arc;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::utils::{impl_dyn_casting, AsAny};
/// Handle to a monitor.
///
/// Allows you to retrieve basic information and metadata about a monitor.
///
/// Can be used in [`Window`] creation to place the window on a specific
/// monitor.
///
/// This can be retrieved from one of the following methods, which return an
/// iterator of [`MonitorHandle`]s:
/// - [`ActiveEventLoop::available_monitors`](crate::event_loop::ActiveEventLoop::available_monitors).
/// - [`Window::available_monitors`](crate::window::Window::available_monitors).
///
/// ## Platform-specific
///
/// **Web:** A [`MonitorHandle`] created without
#[cfg_attr(
web_platform,
doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")]
/// will always represent the current monitor the browser window is in instead of a specific
/// monitor. See
#[cfg_attr(
web_platform,
doc = "[`MonitorHandleExtWeb::is_detailed()`][crate::platform::web::MonitorHandleExtWeb::is_detailed]"
)]
#[cfg_attr(not(web_platform), doc = "`MonitorHandleExtWeb::is_detailed()`")]
/// to check.
///
/// [`Window`]: crate::window::Window
#[derive(Debug, Clone)]
pub struct MonitorHandle(pub(crate) Arc<dyn MonitorHandleProvider>);
impl Deref for MonitorHandle {
type Target = dyn MonitorHandleProvider;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl PartialEq for MonitorHandle {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref().eq(other.0.as_ref())
}
}
impl Eq for MonitorHandle {}
/// Provider of the [`MonitorHandle`].
pub trait MonitorHandleProvider: AsAny + fmt::Debug + Send + Sync {
/// Identifier for this monitor.
///
/// The representation of this modifier is not guaranteed and should be used only to compare
/// monitors.
fn id(&self) -> u128;
/// Native platform identifier of this monitor.
///
/// # Platform-specific
///
/// - **Windows**: This is `HMONITOR`.
/// - **macOS**: This is `CGDirectDisplayID`.
/// - **iOS**: This is `UIScreen*`.
/// - **Wayland**: This is the ID of the `wl_output` device.
/// - **X11**: This is the ID of the CRTC.
/// - **Web**: This is an internal ID not meant for consumption.
fn native_id(&self) -> u64;
/// Returns a human-readable name of the monitor.
///
/// Returns `None` if the monitor doesn't exist anymore or the name couldn't be obtained.
///
/// ## Platform-specific
///
/// **Web:** Always returns [`None`] without
#[cfg_attr(
web_platform,
doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")]
fn name(&self) -> Option<Cow<'_, str>>;
/// Returns the top-left corner position of the monitor in desktop coordinates.
///
/// This position is in the same coordinate system as [`Window::outer_position`].
///
/// [`Window::outer_position`]: crate::window::Window::outer_position
///
/// ## Platform-specific
///
/// **Web:** Always returns [`None`] without
#[cfg_attr(
web_platform,
doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")]
fn position(&self) -> Option<PhysicalPosition<i32>>;
/// Returns the scale factor of the underlying monitor. To map logical pixels to physical
/// pixels and vice versa, use [`Window::scale_factor`].
///
/// See the [`dpi`] module for more information.
///
/// ## Platform-specific
///
/// - **X11:** Can be overridden using the `WINIT_X11_SCALE_FACTOR` environment variable.
/// - **Wayland:** May differ from [`Window::scale_factor`].
/// - **Android:** Always returns 1.0.
/// - **Web:** Always returns `0.0` without
#[cfg_attr(
web_platform,
doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")]
///
#[rustfmt::skip]
/// [`Window::scale_factor`]: crate::window::Window::scale_factor
fn scale_factor(&self) -> f64;
fn current_video_mode(&self) -> Option<VideoMode>;
/// Returns all fullscreen video modes supported by this monitor.
fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>>;
}
impl PartialEq for dyn MonitorHandleProvider + '_ {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl Eq for dyn MonitorHandleProvider + '_ {}
impl_dyn_casting!(MonitorHandleProvider);
/// Describes a fullscreen video mode of a monitor.
///
/// Can be acquired with [`MonitorHandleProvider::video_modes`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VideoMode {
pub(crate) size: PhysicalSize<u32>,
pub(crate) bit_depth: Option<NonZeroU16>,
pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
}
impl VideoMode {
/// Returns the resolution of this video mode. This **must not** be used to create your
/// rendering surface. Use [`Window::surface_size()`] instead.
///
/// [`Window::surface_size()`]: crate::window::Window::surface_size
pub fn size(&self) -> PhysicalSize<u32> {
self.size
}
/// Returns the bit depth of this video mode, as in how many bits you have
/// available per color. This is generally 24 bits or 32 bits on modern
/// systems, depending on whether the alpha channel is counted or not.
pub fn bit_depth(&self) -> Option<NonZeroU16> {
self.bit_depth
}
/// Returns the refresh rate of this video mode in mHz.
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
self.refresh_rate_millihertz
}
}
impl fmt::Display for VideoMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}x{} {}{}",
self.size.width,
self.size.height,
self.refresh_rate_millihertz.map(|rate| format!("@ {rate} mHz ")).unwrap_or_default(),
self.bit_depth.map(|bit_depth| format!("({bit_depth} bpp)")).unwrap_or_default(),
)
}
}
/// Fullscreen modes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Fullscreen {
Exclusive(MonitorHandle, VideoMode),
/// Providing `None` to `Borderless` will fullscreen on the current monitor.
Borderless(Option<MonitorHandle>),
}

View file

@ -79,14 +79,14 @@ impl VideoModeHandle {
unimplemented!()
};
let mode = VideoMode {
size: PhysicalSize::new(
let mode = VideoMode::new(
PhysicalSize::new(
CGDisplayMode::pixel_width(Some(&native_mode.0)) as u32,
CGDisplayMode::pixel_height(Some(&native_mode.0)) as u32,
),
NonZeroU16::new(bit_depth),
refresh_rate_millihertz,
bit_depth: NonZeroU16::new(bit_depth),
};
);
VideoModeHandle { mode, monitor: monitor.clone(), native_mode }
}

View file

@ -55,11 +55,11 @@ impl VideoModeHandle {
) -> VideoModeHandle {
let refresh_rate_millihertz = refresh_rate_millihertz(&uiscreen);
let size = screen_mode.size();
let mode = VideoMode {
size: (size.width as u32, size.height as u32).into(),
bit_depth: None,
let mode = VideoMode::new(
(size.width as u32, size.height as u32).into(),
None,
refresh_rate_millihertz,
};
);
VideoModeHandle {
mode,

View file

@ -83,9 +83,9 @@ impl Eq for MonitorHandle {}
/// Convert the wayland's [`Mode`] to winit's [`VideoMode`].
fn wayland_mode_to_core_mode(mode: Mode) -> VideoMode {
VideoMode {
size: (mode.dimensions.0, mode.dimensions.1).into(),
bit_depth: None,
refresh_rate_millihertz: NonZeroU32::new(mode.refresh_rate as u32),
}
VideoMode::new(
(mode.dimensions.0, mode.dimensions.1).into(),
None,
NonZeroU32::new(mode.refresh_rate as u32),
)
}

View file

@ -85,11 +85,11 @@ impl XConnection {
.filter(|x| output_modes.iter().any(|id| x.id == *id))
.map(|mode| VideoModeHandle {
current: mode.id == current_mode,
mode: VideoMode {
size: (mode.width as u32, mode.height as u32).into(),
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode),
bit_depth: NonZeroU16::new(bit_depth as u16),
},
mode: VideoMode::new(
(mode.width as u32, mode.height as u32).into(),
NonZeroU16::new(bit_depth as u16),
monitor::mode_refresh_rate_millihertz(mode),
),
native_mode: mode.id,
})
.collect();

View file

@ -141,11 +141,11 @@ impl MonitorHandleProvider for MonitorHandle {
}
fn current_video_mode(&self) -> Option<VideoMode> {
Some(VideoMode {
size: self.inner.queue(|inner| inner.size()),
bit_depth: self.inner.queue(|inner| inner.bit_depth()),
refresh_rate_millihertz: None,
})
Some(VideoMode::new(
self.inner.queue(|inner| inner.size()),
self.inner.queue(|inner| inner.bit_depth()),
None,
))
}
fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {

View file

@ -50,11 +50,11 @@ impl VideoModeHandle {
DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
assert!(has_flag(native_video_mode.dmFields, REQUIRED_FIELDS));
let mode = VideoMode {
size: (native_video_mode.dmPelsWidth, native_video_mode.dmPelsHeight).into(),
bit_depth: NonZeroU16::new(native_video_mode.dmBitsPerPel as u16),
refresh_rate_millihertz: NonZeroU32::new(native_video_mode.dmDisplayFrequency * 1000),
};
let mode = VideoMode::new(
(native_video_mode.dmPelsWidth, native_video_mode.dmPelsHeight).into(),
NonZeroU16::new(native_video_mode.dmBitsPerPel as u16),
NonZeroU32::new(native_video_mode.dmDisplayFrequency * 1000),
);
VideoModeHandle { mode, native_video_mode: Box::new(native_video_mode) }
}