Skip to content

Commit

Permalink
Various Monitor/VideoModeHandle methods now return an Option
Browse files Browse the repository at this point in the history
`VideoModeHandle::refresh_rate_millihertz()` and `bit_depth()` now return a `Option<NonZero*>`.
`MonitorHandle::position()` now returns an `Option`.
On Orbital `MonitorHandle::name()` now returns `None` instead of a dummy name.
  • Loading branch information
daxpedda committed Aug 7, 2024
1 parent 0ffcfd8 commit 78e69d6
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 186 deletions.
33 changes: 16 additions & 17 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,31 +304,30 @@ impl Application {

if let Some(current_mode) = monitor.current_video_mode() {
let PhysicalSize { width, height } = current_mode.size();
info!(
" Current mode: {width}x{height}{}",
if let Some(m_hz) = current_mode.refresh_rate_millihertz() {
format!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000)
} else {
String::new()
}
);
let bits =
current_mode.bit_depth().map(|bits| format!("x{bits}")).unwrap_or_default();
let m_hz = current_mode
.refresh_rate_millihertz()
.map(|m_hz| format!(" @ {}.{} Hz", m_hz.get() / 1000, m_hz.get() % 1000))
.unwrap_or_default();
info!(" {width}x{height}{bits}{m_hz}");
}

let PhysicalPosition { x, y } = monitor.position();
info!(" Position: {x},{y}");
if let Some(PhysicalPosition { x, y }) = monitor.position() {
info!(" Position: {x},{y}");
}

info!(" Scale factor: {}", monitor.scale_factor());

info!(" Available modes (width x height x bit-depth):");
for mode in monitor.video_modes() {
let PhysicalSize { width, height } = mode.size();
let bits = mode.bit_depth();
let m_hz = if let Some(m_hz) = mode.refresh_rate_millihertz() {
format!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000)
} else {
String::new()
};
info!(" {width}x{height}x{bits}{m_hz}");
let bits = mode.bit_depth().map(|bits| format!("x{bits}")).unwrap_or_default();
let m_hz = mode
.refresh_rate_millihertz()
.map(|m_hz| format!(" @ {}.{} Hz", m_hz.get() / 1000, m_hz.get() % 1000))
.unwrap_or_default();
info!(" {width}x{height}{bits}{m_hz}");
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ changelog entry.
accelerated, if the browser supports it.
- `(Active)EventLoop::create_custom_cursor()` now returns a `Result<CustomCursor, ExternalError>`.
- Changed how `ModifiersState` is serialized by Serde.
- `VideoModeHandle::refresh_rate_millihertz()` now returns an `Option`.
- `VideoModeHandle::refresh_rate_millihertz()` and `bit_depth()` now return a `Option<NonZero*>`.
- `MonitorHandle::position()` now returns an `Option`.

### Removed

Expand Down Expand Up @@ -127,3 +128,4 @@ changelog entry.
- On Web, pen events are now routed through to `WindowEvent::Cursor*`.
- On macOS, fix panic when releasing not available monitor.
- On MacOS, return the system theme in `Window::theme()` if no theme override is set.
- On Orbital, `MonitorHandle::name()` now returns `None` instead of a dummy name.
32 changes: 19 additions & 13 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//! 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 crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::platform_impl;

Expand Down Expand Up @@ -44,7 +46,10 @@ impl Ord for VideoModeHandle {
}

impl VideoModeHandle {
/// Returns the resolution of this video mode.
/// Returns the resolution of this video mode. This **must not** be used to create your
/// rendering surface. Use [`Window::inner_size()`] instead.
///
/// [`Window::inner_size()`]: crate::window::Window::inner_size
#[inline]
pub fn size(&self) -> PhysicalSize<u32> {
self.video_mode.size()
Expand All @@ -53,19 +58,14 @@ impl VideoModeHandle {
/// 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.
///
/// ## Platform-specific
///
/// - **Wayland / Orbital:** Always returns 32.
/// - **iOS:** Always returns 32.
#[inline]
pub fn bit_depth(&self) -> u16 {
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<u32> {
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
self.video_mode.refresh_rate_millihertz()
}

Expand All @@ -81,11 +81,11 @@ impl std::fmt::Display for VideoModeHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}x{} {}({} bpp)",
"{}x{} {}{}",
self.size().width,
self.size().height,
self.refresh_rate_millihertz().map(|rate| format!("@ {rate} mHz ")).unwrap_or_default(),
self.bit_depth()
self.bit_depth().map(|bit_depth| format!("({bit_depth} bpp)")).unwrap_or_default(),
)
}
}
Expand All @@ -112,11 +112,17 @@ impl std::fmt::Display for VideoModeHandle {
/// to check.
///
/// [`Window`]: crate::window::Window
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MonitorHandle {
pub(crate) inner: platform_impl::MonitorHandle,
}

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

impl MonitorHandle {
/// Returns a human-readable name of the monitor.
///
Expand All @@ -140,14 +146,14 @@ impl MonitorHandle {
///
/// ## Platform-specific
///
/// **Web:** Always returns [`Default`] without
/// **Web:** Always returns [`None`] without
#[cfg_attr(
any(web_platform, docsrs),
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) -> PhysicalPosition<i32> {
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
self.inner.position()
}

Expand Down
19 changes: 7 additions & 12 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::any::Any;
use std::cell::Cell;
use std::collections::VecDeque;
use std::hash::Hash;
use std::num::{NonZeroU16, NonZeroU32};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -980,21 +981,16 @@ impl MonitorHandle {
Some("Android Device".to_owned())
}

pub fn position(&self) -> PhysicalPosition<i32> {
(0, 0).into()
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
None
}

pub fn scale_factor(&self) -> f64 {
self.app.config().density().map(|dpi| dpi as f64 / 160.0).unwrap_or(1.0)
}

pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
Some(VideoModeHandle {
size: screen_size(&self.app),
// FIXME: it is guaranteed to support 32 bit color though
bit_depth: 32,
monitor: self.clone(),
})
Some(VideoModeHandle { size: screen_size(&self.app), monitor: self.clone() })
}

pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
Expand All @@ -1005,7 +1001,6 @@ impl MonitorHandle {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct VideoModeHandle {
size: PhysicalSize<u32>,
bit_depth: u16,
monitor: MonitorHandle,
}

Expand All @@ -1014,11 +1009,11 @@ impl VideoModeHandle {
self.size
}

pub fn bit_depth(&self) -> u16 {
self.bit_depth
pub fn bit_depth(&self) -> Option<NonZeroU16> {
None
}

pub fn refresh_rate_millihertz(&self) -> Option<u32> {
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
None
}

Expand Down
31 changes: 17 additions & 14 deletions src/platform_impl/apple/appkit/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::VecDeque;
use std::fmt;
use std::num::{NonZeroU16, NonZeroU32};

use core_foundation::array::{CFArrayGetCount, CFArrayGetValueAtIndex};
use core_foundation::base::{CFRelease, TCFType};
Expand All @@ -20,8 +21,8 @@ use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
#[derive(Clone)]
pub struct VideoModeHandle {
size: PhysicalSize<u32>,
bit_depth: u16,
refresh_rate_millihertz: Option<u32>,
bit_depth: Option<NonZeroU16>,
refresh_rate_millihertz: Option<NonZeroU32>,
pub(crate) monitor: MonitorHandle,
pub(crate) native_mode: NativeDisplayMode,
}
Expand Down Expand Up @@ -83,7 +84,7 @@ impl VideoModeHandle {
fn new(
monitor: MonitorHandle,
mode: NativeDisplayMode,
refresh_rate_millihertz: Option<u32>,
refresh_rate_millihertz: Option<NonZeroU32>,
) -> Self {
unsafe {
let pixel_encoding =
Expand All @@ -105,7 +106,7 @@ impl VideoModeHandle {
ffi::CGDisplayModeGetPixelHeight(mode.0) as u32,
),
refresh_rate_millihertz,
bit_depth,
bit_depth: NonZeroU16::new(bit_depth),
monitor: monitor.clone(),
native_mode: mode,
}
Expand All @@ -116,11 +117,11 @@ impl VideoModeHandle {
self.size
}

pub fn bit_depth(&self) -> u16 {
pub fn bit_depth(&self) -> Option<NonZeroU16> {
self.bit_depth
}

pub fn refresh_rate_millihertz(&self) -> Option<u32> {
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
self.refresh_rate_millihertz
}

Expand Down Expand Up @@ -192,7 +193,6 @@ impl fmt::Debug for MonitorHandle {
.field("native_identifier", &self.native_identifier())
.field("position", &self.position())
.field("scale_factor", &self.scale_factor())
.field("refresh_rate_millihertz", &self.refresh_rate_millihertz())
.finish_non_exhaustive()
}
}
Expand All @@ -216,13 +216,13 @@ impl MonitorHandle {
}

#[inline]
pub fn position(&self) -> PhysicalPosition<i32> {
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
// This is already in screen coordinates. If we were using `NSScreen`,
// then a conversion would've been needed:
// flip_window_screen_coordinates(self.ns_screen(mtm)?.frame())
let bounds = unsafe { CGDisplayBounds(self.native_identifier()) };
let position = LogicalPosition::new(bounds.origin.x, bounds.origin.y);
position.to_physical(self.scale_factor())
Some(position.to_physical(self.scale_factor()))
}

pub fn scale_factor(&self) -> f64 {
Expand All @@ -234,7 +234,7 @@ impl MonitorHandle {
})
}

fn refresh_rate_millihertz(&self) -> Option<u32> {
fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
let current_display_mode =
NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) } as _);
refresh_rate_millihertz(self.0, &current_display_mode)
Expand Down Expand Up @@ -272,7 +272,7 @@ impl MonitorHandle {
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
// isn't a CRT
let refresh_rate_millihertz = if cg_refresh_rate_hertz > 0 {
Some((cg_refresh_rate_hertz * 1000) as u32)
NonZeroU32::new((cg_refresh_rate_hertz * 1000) as u32)
} else {
refresh_rate_millihertz
};
Expand Down Expand Up @@ -341,11 +341,11 @@ pub(crate) fn flip_window_screen_coordinates(frame: NSRect) -> NSPoint {
NSPoint::new(frame.origin.x, y)
}

fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option<u32> {
fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option<NonZeroU32> {
unsafe {
let refresh_rate = ffi::CGDisplayModeGetRefreshRate(mode.0);
if refresh_rate > 0.0 {
return Some((refresh_rate * 1000.0).round() as u32);
return NonZeroU32::new((refresh_rate * 1000.0).round() as u32);
}

let mut display_link = std::ptr::null_mut();
Expand All @@ -360,6 +360,9 @@ fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> O
return None;
}

(time.time_scale as i64).checked_div(time.time_value).map(|v| (v * 1000) as u32)
(time.time_scale as i64)
.checked_div(time.time_value)
.map(|v| (v * 1000) as u32)
.and_then(NonZeroU32::new)
}
}
Loading

0 comments on commit 78e69d6

Please sign in to comment.