Skip to content

Commit

Permalink
monitor: refactor MonitorHandle to store dyn object
Browse files Browse the repository at this point in the history
This also alters `VideoMode` to be a regular object and not reference
the `MonitorHandle`, since it's a static data.

Given that `VideoMode` set may change during runtime keeping the
reference as a some sort of validity may not be idea and propagating
errors when changing video mode could be more reliable.
  • Loading branch information
kchibisov committed Sep 21, 2024
1 parent 4f1c5b6 commit 42cbaa6
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 365 deletions.
5 changes: 3 additions & 2 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use winit::error::RequestError;
use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent};
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::keyboard::{Key, ModifiersState};
use winit::monitor::Fullscreen;
#[cfg(macos_platform)]
use winit::platform::macos::{OptionAsAlt, WindowAttributesExtMacOS, WindowExtMacOS};
#[cfg(any(x11_platform, wayland_platform))]
Expand All @@ -30,8 +31,8 @@ use winit::platform::startup_notify::{
#[cfg(web_platform)]
use winit::platform::web::{ActiveEventLoopExtWeb, CustomCursorExtWeb, WindowAttributesExtWeb};
use winit::window::{
Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection,
Theme, Window, WindowAttributes, WindowId,
Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Icon, ResizeDirection, Theme, Window,
WindowAttributes, WindowId,
};

#[path = "util/tracing.rs"]
Expand Down
201 changes: 92 additions & 109 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,90 +5,14 @@
//! 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::num::{NonZeroU16, NonZeroU32};
use std::borrow::Cow;
use std::fmt;
use std::num::NonZeroU16;
use std::ops::Deref;
use std::sync::Arc;

use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::platform_impl;

/// Describes a fullscreen video mode of a monitor.
///
/// Can be acquired with [`MonitorHandle::video_modes`].
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct VideoModeHandle {
pub(crate) video_mode: platform_impl::VideoModeHandle,
}

impl std::fmt::Debug for VideoModeHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.video_mode.fmt(f)
}
}

impl PartialOrd for VideoModeHandle {
fn partial_cmp(&self, other: &VideoModeHandle) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for VideoModeHandle {
fn cmp(&self, other: &VideoModeHandle) -> std::cmp::Ordering {
self.monitor().cmp(&other.monitor()).then(
self.size()
.cmp(&other.size())
.then(
self.refresh_rate_millihertz()
.cmp(&other.refresh_rate_millihertz())
.then(self.bit_depth().cmp(&other.bit_depth())),
)
.reverse(),
)
}
}

impl VideoModeHandle {
/// 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
#[inline]
pub fn size(&self) -> PhysicalSize<u32> {
self.video_mode.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.
#[inline]
pub fn bit_depth(&self) -> Option<NonZeroU16> {
self.video_mode.bit_depth()
}

/// Returns the refresh rate of this video mode in mHz.
#[inline]
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
self.video_mode.refresh_rate_millihertz()
}

/// Returns the monitor that this video mode is valid for. Each monitor has
/// a separate set of valid video modes.
#[inline]
pub fn monitor(&self) -> MonitorHandle {
MonitorHandle { inner: self.video_mode.monitor() }
}
}

impl std::fmt::Display for VideoModeHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::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(),
)
}
}
use crate::utils::AsAny;

/// Handle to a monitor.
///
Expand All @@ -112,21 +36,33 @@ impl std::fmt::Display for VideoModeHandle {
/// to check.
///
/// [`Window`]: crate::window::Window
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MonitorHandle {
pub(crate) inner: platform_impl::MonitorHandle,
#[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 std::fmt::Debug for MonitorHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
impl PartialEq for MonitorHandle {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref().eq(other.0.as_ref())
}
}

impl MonitorHandle {
impl Eq for MonitorHandle {}

/// Provider of the [`MonitorHandle`].
pub trait MonitorHandleProvider: AsAny + fmt::Debug {
/// Native platform identifier of this monitor.
fn native_id(&self) -> u64;

/// Returns a human-readable name of the monitor.
///
/// Returns `None` if the monitor doesn't exist anymore.
/// Returns `None` if the monitor doesn't exist anymore or the name couldn't be obtained.
///
/// ## Platform-specific
///
Expand All @@ -136,10 +72,7 @@ impl MonitorHandle {
doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(any(web_platform, docsrs)), doc = "detailed monitor permissions.")]
#[inline]
pub fn name(&self) -> Option<String> {
self.inner.name()
}
fn name(&self) -> Option<Cow<'_, str>>;

/// Returns the top-left corner position of the monitor relative to the larger full
/// screen area.
Expand All @@ -152,10 +85,7 @@ impl MonitorHandle {
doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]."
)]
#[cfg_attr(not(any(web_platform, docsrs)), doc = "detailed monitor permissions.")]
#[inline]
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
self.inner.position()
}
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`].
Expand All @@ -176,20 +106,73 @@ impl MonitorHandle {
///
#[rustfmt::skip]
/// [`Window::scale_factor`]: crate::window::Window::scale_factor
#[inline]
pub fn scale_factor(&self) -> f64 {
self.inner.scale_factor()
}
fn scale_factor(&self) -> f64;

/// Returns the currently active video mode of this monitor.
#[inline]
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
self.inner.current_video_mode().map(|video_mode| VideoModeHandle { video_mode })
}
fn current_video_mode(&self) -> Option<VideoMode>;

/// Returns all fullscreen video modes supported by this monitor.
#[inline]
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
self.inner.video_modes().map(|video_mode| VideoModeHandle { video_mode })
fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>>;
}

impl PartialEq for dyn MonitorHandleProvider + '_ {
fn eq(&self, other: &Self) -> bool {
self.native_id() == other.native_id()
}
}

impl Eq for dyn MonitorHandleProvider + '_ {}

/// Describes a fullscreen video mode of a monitor.
///
/// Can be acquired with [`MonitorHandle::video_modes`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VideoMode {
pub(crate) size: PhysicalSize<u32>,
pub(crate) bit_depth: Option<NonZeroU16>,
pub(crate) refresh_rate_millihertz: Option<NonZeroU16>,
}

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<NonZeroU16> {
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)]
pub enum Fullscreen {
Exclusive(MonitorHandle, VideoMode),

/// Providing `None` to `Borderless` will fullscreen on the current monitor.
Borderless(Option<MonitorHandle>),
}
14 changes: 0 additions & 14 deletions src/platform/wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
//! * `wayland-csd-adwaita-crossfont`.
//! * `wayland-csd-adwaita-notitle`.
use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder};
use crate::monitor::MonitorHandle;
pub use crate::window::Theme;
use crate::window::{Window as CoreWindow, WindowAttributes};

Expand Down Expand Up @@ -97,16 +96,3 @@ impl WindowAttributesExtWayland for WindowAttributes {
self
}
}

/// Additional methods on `MonitorHandle` that are specific to Wayland.
pub trait MonitorHandleExtWayland {
/// Returns the inner identifier of the monitor.
fn native_id(&self) -> u32;
}

impl MonitorHandleExtWayland for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
}
4 changes: 2 additions & 2 deletions src/platform/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};

use crate::dpi::Size;
use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder};
use crate::monitor::MonitorHandle;
use crate::monitor::MonitorHandleProvider;
use crate::window::{Window as CoreWindow, WindowAttributes};

/// X window type. Maps directly to
Expand Down Expand Up @@ -249,7 +249,7 @@ pub trait MonitorHandleExtX11 {
fn native_id(&self) -> u32;
}

impl MonitorHandleExtX11 for MonitorHandle {
impl MonitorHandleExtX11 for MonitorHandleProvider {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
Expand Down
Loading

0 comments on commit 42cbaa6

Please sign in to comment.