mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Add refresh_rate_millihertz
for MonitorHandle
This also alters `VideoMode::refresh_rate` to `VideoMode::refresh_rate_millihertz` which now returns monitor refresh rate in mHz.
This commit is contained in:
parent
e289f30e5d
commit
a06bb3f992
|
@ -65,6 +65,8 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- Fix on macOS `WindowBuilder::with_disallow_hidpi`, setting true or false by the user no matter the SO default value.
|
- Fix on macOS `WindowBuilder::with_disallow_hidpi`, setting true or false by the user no matter the SO default value.
|
||||||
- `EventLoopBuilder::build` will now panic when the `EventLoop` is being created more than once.
|
- `EventLoopBuilder::build` will now panic when the `EventLoop` is being created more than once.
|
||||||
- Added `From<u64>` for `WindowId` and `From<WindowId>` for `u64`.
|
- Added `From<u64>` for `WindowId` and `From<WindowId>` for `u64`.
|
||||||
|
- Added `MonitorHandle::refresh_rate_millihertz` to get monitor's refresh rate.
|
||||||
|
- **Breaking**, Replaced `VideoMode::refresh_rate` with `VideoMode::refresh_rate_millihertz` providing better precision.
|
||||||
|
|
||||||
# 0.26.1 (2022-01-05)
|
# 0.26.1 (2022-01-05)
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ impl Ord for VideoMode {
|
||||||
self.monitor().cmp(&other.monitor()).then(
|
self.monitor().cmp(&other.monitor()).then(
|
||||||
size.cmp(&other_size)
|
size.cmp(&other_size)
|
||||||
.then(
|
.then(
|
||||||
self.refresh_rate()
|
self.refresh_rate_millihertz()
|
||||||
.cmp(&other.refresh_rate())
|
.cmp(&other.refresh_rate_millihertz())
|
||||||
.then(self.bit_depth().cmp(&other.bit_depth())),
|
.then(self.bit_depth().cmp(&other.bit_depth())),
|
||||||
)
|
)
|
||||||
.reverse(),
|
.reverse(),
|
||||||
|
@ -68,12 +68,10 @@ impl VideoMode {
|
||||||
self.video_mode.bit_depth()
|
self.video_mode.bit_depth()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the refresh rate of this video mode. **Note**: the returned
|
/// Returns the refresh rate of this video mode in mHz.
|
||||||
/// refresh rate is an integer approximation, and you shouldn't rely on this
|
|
||||||
/// value to be exact.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.video_mode.refresh_rate()
|
self.video_mode.refresh_rate_millihertz()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the monitor that this video mode is valid for. Each monitor has
|
/// Returns the monitor that this video mode is valid for. Each monitor has
|
||||||
|
@ -88,10 +86,10 @@ impl std::fmt::Display for VideoMode {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}x{} @ {} Hz ({} bpp)",
|
"{}x{} @ {} mHz ({} bpp)",
|
||||||
self.size().width,
|
self.size().width,
|
||||||
self.size().height,
|
self.size().height,
|
||||||
self.refresh_rate(),
|
self.refresh_rate_millihertz(),
|
||||||
self.bit_depth()
|
self.bit_depth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -141,6 +139,15 @@ impl MonitorHandle {
|
||||||
self.inner.position()
|
self.inner.position()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The monitor refresh rate used by the system.
|
||||||
|
///
|
||||||
|
/// When using exclusive fullscreen, the refresh rate of the [`VideoMode`] that was used to
|
||||||
|
/// enter fullscreen should be used instead.
|
||||||
|
#[inline]
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
self.inner.refresh_rate_millihertz()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
|
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
|
||||||
///
|
///
|
||||||
/// See the [`dpi`](crate::dpi) module for more information.
|
/// See the [`dpi`](crate::dpi) module for more information.
|
||||||
|
|
|
@ -857,6 +857,11 @@ impl MonitorHandle {
|
||||||
.unwrap_or(1.0)
|
.unwrap_or(1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
// FIXME no way to get real refrsh rate for now.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn video_modes(&self) -> impl Iterator<Item = monitor::VideoMode> {
|
pub fn video_modes(&self) -> impl Iterator<Item = monitor::VideoMode> {
|
||||||
let size = self.size().into();
|
let size = self.size().into();
|
||||||
// FIXME this is not the real refresh rate
|
// FIXME this is not the real refresh rate
|
||||||
|
@ -865,7 +870,7 @@ impl MonitorHandle {
|
||||||
video_mode: VideoMode {
|
video_mode: VideoMode {
|
||||||
size,
|
size,
|
||||||
bit_depth: 32,
|
bit_depth: 32,
|
||||||
refresh_rate: 60,
|
refresh_rate_millihertz: 60000,
|
||||||
monitor: self.clone(),
|
monitor: self.clone(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -876,7 +881,7 @@ impl MonitorHandle {
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
size: (u32, u32),
|
size: (u32, u32),
|
||||||
bit_depth: u16,
|
bit_depth: u16,
|
||||||
refresh_rate: u16,
|
refresh_rate_millihertz: u32,
|
||||||
monitor: MonitorHandle,
|
monitor: MonitorHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,8 +894,8 @@ impl VideoMode {
|
||||||
self.bit_depth
|
self.bit_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> monitor::MonitorHandle {
|
pub fn monitor(&self) -> monitor::MonitorHandle {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate_millihertz: u32,
|
||||||
pub(crate) screen_mode: NativeDisplayMode,
|
pub(crate) screen_mode: NativeDisplayMode,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ impl Clone for VideoMode {
|
||||||
VideoMode {
|
VideoMode {
|
||||||
size: self.size,
|
size: self.size,
|
||||||
bit_depth: self.bit_depth,
|
bit_depth: self.bit_depth,
|
||||||
refresh_rate: self.refresh_rate,
|
refresh_rate_millihertz: self.refresh_rate_millihertz,
|
||||||
screen_mode: self.screen_mode.clone(),
|
screen_mode: self.screen_mode.clone(),
|
||||||
monitor: self.monitor.clone(),
|
monitor: self.monitor.clone(),
|
||||||
}
|
}
|
||||||
|
@ -59,30 +59,14 @@ impl Clone for VideoMode {
|
||||||
impl VideoMode {
|
impl VideoMode {
|
||||||
unsafe fn retained_new(uiscreen: id, screen_mode: id) -> VideoMode {
|
unsafe fn retained_new(uiscreen: id, screen_mode: id) -> VideoMode {
|
||||||
assert_main_thread!("`VideoMode` can only be created on the main thread on iOS");
|
assert_main_thread!("`VideoMode` can only be created on the main thread on iOS");
|
||||||
let os_capabilities = app_state::os_capabilities();
|
let refresh_rate_millihertz = refresh_rate_millihertz(uiscreen);
|
||||||
let refresh_rate: NSInteger = if os_capabilities.maximum_frames_per_second {
|
|
||||||
msg_send![uiscreen, maximumFramesPerSecond]
|
|
||||||
} else {
|
|
||||||
// https://developer.apple.com/library/archive/technotes/tn2460/_index.html
|
|
||||||
// https://en.wikipedia.org/wiki/IPad_Pro#Model_comparison
|
|
||||||
//
|
|
||||||
// All iOS devices support 60 fps, and on devices where `maximumFramesPerSecond` is not
|
|
||||||
// supported, they are all guaranteed to have 60hz refresh rates. This does not
|
|
||||||
// correctly handle external displays. ProMotion displays support 120fps, but they were
|
|
||||||
// introduced at the same time as the `maximumFramesPerSecond` API.
|
|
||||||
//
|
|
||||||
// FIXME: earlier OSs could calculate the refresh rate using
|
|
||||||
// `-[CADisplayLink duration]`.
|
|
||||||
os_capabilities.maximum_frames_per_second_err_msg("defaulting to 60 fps");
|
|
||||||
60
|
|
||||||
};
|
|
||||||
let size: CGSize = msg_send![screen_mode, size];
|
let size: CGSize = msg_send![screen_mode, size];
|
||||||
let screen_mode: id = msg_send![screen_mode, retain];
|
let screen_mode: id = msg_send![screen_mode, retain];
|
||||||
let screen_mode = NativeDisplayMode(screen_mode);
|
let screen_mode = NativeDisplayMode(screen_mode);
|
||||||
VideoMode {
|
VideoMode {
|
||||||
size: (size.width as u32, size.height as u32),
|
size: (size.width as u32, size.height as u32),
|
||||||
bit_depth: 32,
|
bit_depth: 32,
|
||||||
refresh_rate: refresh_rate as u16,
|
refresh_rate_millihertz,
|
||||||
screen_mode,
|
screen_mode,
|
||||||
monitor: MonitorHandle::retained_new(uiscreen),
|
monitor: MonitorHandle::retained_new(uiscreen),
|
||||||
}
|
}
|
||||||
|
@ -96,8 +80,8 @@ impl VideoMode {
|
||||||
self.bit_depth
|
self.bit_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> RootMonitorHandle {
|
pub fn monitor(&self) -> RootMonitorHandle {
|
||||||
|
@ -239,6 +223,10 @@ impl Inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
Some(refresh_rate_millihertz(self.uiscreen))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn video_modes(&self) -> impl Iterator<Item = RootVideoMode> {
|
pub fn video_modes(&self) -> impl Iterator<Item = RootVideoMode> {
|
||||||
let mut modes = BTreeSet::new();
|
let mut modes = BTreeSet::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -257,6 +245,30 @@ impl Inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh_rate_millihertz(uiscreen: id) -> u32 {
|
||||||
|
let refresh_rate_millihertz: NSInteger = unsafe {
|
||||||
|
let os_capabilities = app_state::os_capabilities();
|
||||||
|
if os_capabilities.maximum_frames_per_second {
|
||||||
|
msg_send![uiscreen, maximumFramesPerSecond]
|
||||||
|
} else {
|
||||||
|
// https://developer.apple.com/library/archive/technotes/tn2460/_index.html
|
||||||
|
// https://en.wikipedia.org/wiki/IPad_Pro#Model_comparison
|
||||||
|
//
|
||||||
|
// All iOS devices support 60 fps, and on devices where `maximumFramesPerSecond` is not
|
||||||
|
// supported, they are all guaranteed to have 60hz refresh rates. This does not
|
||||||
|
// correctly handle external displays. ProMotion displays support 120fps, but they were
|
||||||
|
// introduced at the same time as the `maximumFramesPerSecond` API.
|
||||||
|
//
|
||||||
|
// FIXME: earlier OSs could calculate the refresh rate using
|
||||||
|
// `-[CADisplayLink duration]`.
|
||||||
|
os_capabilities.maximum_frames_per_second_err_msg("defaulting to 60 fps");
|
||||||
|
60
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
refresh_rate_millihertz as u32 * 1000
|
||||||
|
}
|
||||||
|
|
||||||
// MonitorHandleExtIOS
|
// MonitorHandleExtIOS
|
||||||
impl Inner {
|
impl Inner {
|
||||||
pub fn ui_screen(&self) -> id {
|
pub fn ui_screen(&self) -> id {
|
||||||
|
|
|
@ -256,6 +256,11 @@ impl MonitorHandle {
|
||||||
x11_or_wayland!(match self; MonitorHandle(m) => m.position())
|
x11_or_wayland!(match self; MonitorHandle(m) => m.position())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
x11_or_wayland!(match self; MonitorHandle(m) => m.refresh_rate_millihertz())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> f64 {
|
pub fn scale_factor(&self) -> f64 {
|
||||||
x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as f64)
|
x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as f64)
|
||||||
|
@ -287,8 +292,8 @@ impl VideoMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate())
|
x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate_millihertz())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -167,6 +167,16 @@ impl MonitorHandle {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
sctk::output::with_output_info(&self.proxy, |info| {
|
||||||
|
info.modes
|
||||||
|
.iter()
|
||||||
|
.find_map(|mode| mode.is_current.then(|| mode.refresh_rate as u32))
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> i32 {
|
pub fn scale_factor(&self) -> i32 {
|
||||||
sctk::output::with_output_info(&self.proxy, |info| info.scale_factor).unwrap_or(1)
|
sctk::output::with_output_info(&self.proxy, |info| info.scale_factor).unwrap_or(1)
|
||||||
|
@ -182,7 +192,7 @@ impl MonitorHandle {
|
||||||
modes.into_iter().map(move |mode| RootVideoMode {
|
modes.into_iter().map(move |mode| RootVideoMode {
|
||||||
video_mode: PlatformVideoMode::Wayland(VideoMode {
|
video_mode: PlatformVideoMode::Wayland(VideoMode {
|
||||||
size: (mode.dimensions.0 as u32, mode.dimensions.1 as u32).into(),
|
size: (mode.dimensions.0 as u32, mode.dimensions.1 as u32).into(),
|
||||||
refresh_rate: (mode.refresh_rate as f32 / 1000.0).round() as u16,
|
refresh_rate_millihertz: mode.refresh_rate as u32,
|
||||||
bit_depth: 32,
|
bit_depth: 32,
|
||||||
monitor: monitor.clone(),
|
monitor: monitor.clone(),
|
||||||
}),
|
}),
|
||||||
|
@ -194,7 +204,7 @@ impl MonitorHandle {
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: PhysicalSize<u32>,
|
pub(crate) size: PhysicalSize<u32>,
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate_millihertz: u32,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +220,8 @@ impl VideoMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> RootMonitorHandle {
|
pub fn monitor(&self) -> RootMonitorHandle {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -6,7 +7,7 @@ use parking_lot::Mutex;
|
||||||
use super::{
|
use super::{
|
||||||
ffi::{
|
ffi::{
|
||||||
RRCrtc, RRCrtcChangeNotifyMask, RRMode, RROutputPropertyNotifyMask,
|
RRCrtc, RRCrtcChangeNotifyMask, RRMode, RROutputPropertyNotifyMask,
|
||||||
RRScreenChangeNotifyMask, True, Window, XRRCrtcInfo, XRRScreenResources,
|
RRScreenChangeNotifyMask, True, Window, XRRCrtcInfo, XRRModeInfo, XRRScreenResources,
|
||||||
},
|
},
|
||||||
util, XConnection, XError,
|
util, XConnection, XError,
|
||||||
};
|
};
|
||||||
|
@ -30,7 +31,7 @@ pub fn invalidate_cached_monitor_list() -> Option<Vec<MonitorHandle>> {
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate_millihertz: u32,
|
||||||
pub(crate) native_mode: RRMode,
|
pub(crate) native_mode: RRMode,
|
||||||
pub(crate) monitor: Option<MonitorHandle>,
|
pub(crate) monitor: Option<MonitorHandle>,
|
||||||
}
|
}
|
||||||
|
@ -47,8 +48,8 @@ impl VideoMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -71,6 +72,8 @@ pub struct MonitorHandle {
|
||||||
position: (i32, i32),
|
position: (i32, i32),
|
||||||
/// If the monitor is the primary one
|
/// If the monitor is the primary one
|
||||||
primary: bool,
|
primary: bool,
|
||||||
|
/// The refresh rate used by monitor.
|
||||||
|
refresh_rate_millihertz: Option<u32>,
|
||||||
/// The DPI scale factor
|
/// The DPI scale factor
|
||||||
pub(crate) scale_factor: f64,
|
pub(crate) scale_factor: f64,
|
||||||
/// Used to determine which windows are on this monitor
|
/// Used to determine which windows are on this monitor
|
||||||
|
@ -105,6 +108,15 @@ impl std::hash::Hash for MonitorHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mode_refresh_rate_millihertz(mode: &XRRModeInfo) -> Option<u32> {
|
||||||
|
if mode.dotClock > 0 && mode.hTotal > 0 && mode.vTotal > 0 {
|
||||||
|
Some((mode.dotClock as u64 * 1000 / (mode.hTotal as u64 * mode.vTotal as u64)) as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MonitorHandle {
|
impl MonitorHandle {
|
||||||
fn new(
|
fn new(
|
||||||
xconn: &XConnection,
|
xconn: &XConnection,
|
||||||
|
@ -116,10 +128,22 @@ impl MonitorHandle {
|
||||||
let (name, scale_factor, video_modes) = unsafe { xconn.get_output_info(resources, crtc)? };
|
let (name, scale_factor, video_modes) = unsafe { xconn.get_output_info(resources, crtc)? };
|
||||||
let dimensions = unsafe { ((*crtc).width as u32, (*crtc).height as u32) };
|
let dimensions = unsafe { ((*crtc).width as u32, (*crtc).height as u32) };
|
||||||
let position = unsafe { ((*crtc).x as i32, (*crtc).y as i32) };
|
let position = unsafe { ((*crtc).x as i32, (*crtc).y as i32) };
|
||||||
|
|
||||||
|
// Get the refresh rate of the current video mode.
|
||||||
|
let current_mode = unsafe { (*crtc).mode };
|
||||||
|
let screen_modes =
|
||||||
|
unsafe { slice::from_raw_parts((*resources).modes, (*resources).nmode as usize) };
|
||||||
|
let refresh_rate_millihertz = screen_modes
|
||||||
|
.iter()
|
||||||
|
.find(|mode| mode.id == current_mode)
|
||||||
|
.and_then(mode_refresh_rate_millihertz);
|
||||||
|
|
||||||
let rect = util::AaRect::new(position, dimensions);
|
let rect = util::AaRect::new(position, dimensions);
|
||||||
|
|
||||||
Some(MonitorHandle {
|
Some(MonitorHandle {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
|
refresh_rate_millihertz,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
dimensions,
|
dimensions,
|
||||||
position,
|
position,
|
||||||
|
@ -136,6 +160,7 @@ impl MonitorHandle {
|
||||||
scale_factor: 1.0,
|
scale_factor: 1.0,
|
||||||
dimensions: (1, 1),
|
dimensions: (1, 1),
|
||||||
position: (0, 0),
|
position: (0, 0),
|
||||||
|
refresh_rate_millihertz: None,
|
||||||
primary: true,
|
primary: true,
|
||||||
rect: util::AaRect::new((0, 0), (1, 1)),
|
rect: util::AaRect::new((0, 0), (1, 1)),
|
||||||
video_modes: Vec::new(),
|
video_modes: Vec::new(),
|
||||||
|
@ -164,6 +189,10 @@ impl MonitorHandle {
|
||||||
self.position.into()
|
self.position.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
self.refresh_rate_millihertz
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> f64 {
|
pub fn scale_factor(&self) -> f64 {
|
||||||
self.scale_factor
|
self.scale_factor
|
||||||
|
|
|
@ -4,6 +4,7 @@ use super::{
|
||||||
ffi::{CurrentTime, RRCrtc, RRMode, Success, XRRCrtcInfo, XRRScreenResources},
|
ffi::{CurrentTime, RRCrtc, RRMode, Success, XRRCrtcInfo, XRRScreenResources},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
use crate::platform_impl::platform::x11::monitor;
|
||||||
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoMode};
|
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoMode};
|
||||||
|
|
||||||
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
||||||
|
@ -80,18 +81,13 @@ impl XConnection {
|
||||||
// XRROutputInfo contains an array of mode ids that correspond to
|
// XRROutputInfo contains an array of mode ids that correspond to
|
||||||
// modes in the array in XRRScreenResources
|
// modes in the array in XRRScreenResources
|
||||||
.filter(|x| output_modes.iter().any(|id| x.id == *id))
|
.filter(|x| output_modes.iter().any(|id| x.id == *id))
|
||||||
.map(|x| {
|
.map(|mode| {
|
||||||
let refresh_rate = if x.dotClock > 0 && x.hTotal > 0 && x.vTotal > 0 {
|
|
||||||
x.dotClock as u64 * 1000 / (x.hTotal as u64 * x.vTotal as u64)
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
VideoMode {
|
VideoMode {
|
||||||
size: (x.width, x.height),
|
size: (mode.width, mode.height),
|
||||||
refresh_rate: (refresh_rate as f32 / 1000.0).round() as u16,
|
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode)
|
||||||
|
.unwrap_or(0),
|
||||||
bit_depth: bit_depth as u16,
|
bit_depth: bit_depth as u16,
|
||||||
native_mode: x.id,
|
native_mode: mode.id,
|
||||||
// This is populated in `MonitorHandle::video_modes` as the
|
// This is populated in `MonitorHandle::video_modes` as the
|
||||||
// video mode is returned to the user
|
// video mode is returned to the user
|
||||||
monitor: None,
|
monitor: None,
|
||||||
|
|
|
@ -21,7 +21,7 @@ use core_graphics::display::{CGDirectDisplayID, CGDisplay, CGDisplayBounds};
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate_millihertz: u32,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
pub(crate) native_mode: NativeDisplayMode,
|
pub(crate) native_mode: NativeDisplayMode,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ impl PartialEq for VideoMode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.size == other.size
|
self.size == other.size
|
||||||
&& self.bit_depth == other.bit_depth
|
&& self.bit_depth == other.bit_depth
|
||||||
&& self.refresh_rate == other.refresh_rate
|
&& self.refresh_rate_millihertz == other.refresh_rate_millihertz
|
||||||
&& self.monitor == other.monitor
|
&& self.monitor == other.monitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ impl std::hash::Hash for VideoMode {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.size.hash(state);
|
self.size.hash(state);
|
||||||
self.bit_depth.hash(state);
|
self.bit_depth.hash(state);
|
||||||
self.refresh_rate.hash(state);
|
self.refresh_rate_millihertz.hash(state);
|
||||||
self.monitor.hash(state);
|
self.monitor.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ impl std::fmt::Debug for VideoMode {
|
||||||
f.debug_struct("VideoMode")
|
f.debug_struct("VideoMode")
|
||||||
.field("size", &self.size)
|
.field("size", &self.size)
|
||||||
.field("bit_depth", &self.bit_depth)
|
.field("bit_depth", &self.bit_depth)
|
||||||
.field("refresh_rate", &self.refresh_rate)
|
.field("refresh_rate_millihertz", &self.refresh_rate_millihertz)
|
||||||
.field("monitor", &self.monitor)
|
.field("monitor", &self.monitor)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -87,8 +87,8 @@ impl VideoMode {
|
||||||
self.bit_depth
|
self.bit_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> RootMonitorHandle {
|
pub fn monitor(&self) -> RootMonitorHandle {
|
||||||
|
@ -220,8 +220,8 @@ impl MonitorHandle {
|
||||||
unsafe { NSScreen::backingScaleFactor(screen) as f64 }
|
unsafe { NSScreen::backingScaleFactor(screen) as f64 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn video_modes(&self) -> impl Iterator<Item = RootVideoMode> {
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
let cv_refresh_rate = unsafe {
|
unsafe {
|
||||||
let mut display_link = std::ptr::null_mut();
|
let mut display_link = std::ptr::null_mut();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ffi::CVDisplayLinkCreateWithCGDisplay(self.0, &mut display_link),
|
ffi::CVDisplayLinkCreateWithCGDisplay(self.0, &mut display_link),
|
||||||
|
@ -233,9 +233,12 @@ impl MonitorHandle {
|
||||||
// This value is indefinite if an invalid display link was specified
|
// This value is indefinite if an invalid display link was specified
|
||||||
assert!(time.flags & ffi::kCVTimeIsIndefinite == 0);
|
assert!(time.flags & ffi::kCVTimeIsIndefinite == 0);
|
||||||
|
|
||||||
time.time_scale as i64 / time.time_value
|
Some((time.time_scale as i64 / time.time_value * 1000) as u32)
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn video_modes(&self) -> impl Iterator<Item = RootVideoMode> {
|
||||||
|
let refresh_rate_millihertz = self.refresh_rate_millihertz().unwrap_or(0);
|
||||||
let monitor = self.clone();
|
let monitor = self.clone();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -255,14 +258,15 @@ impl MonitorHandle {
|
||||||
};
|
};
|
||||||
|
|
||||||
modes.into_iter().map(move |mode| {
|
modes.into_iter().map(move |mode| {
|
||||||
let cg_refresh_rate = ffi::CGDisplayModeGetRefreshRate(mode).round() as i64;
|
let cg_refresh_rate_millihertz =
|
||||||
|
ffi::CGDisplayModeGetRefreshRate(mode).round() as i64;
|
||||||
|
|
||||||
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
||||||
// isn't a CRT
|
// isn't a CRT
|
||||||
let refresh_rate = if cg_refresh_rate > 0 {
|
let refresh_rate_millihertz = if cg_refresh_rate_millihertz > 0 {
|
||||||
cg_refresh_rate
|
(cg_refresh_rate_millihertz * 1000) as u32
|
||||||
} else {
|
} else {
|
||||||
cv_refresh_rate
|
refresh_rate_millihertz
|
||||||
};
|
};
|
||||||
|
|
||||||
let pixel_encoding =
|
let pixel_encoding =
|
||||||
|
@ -283,7 +287,7 @@ impl MonitorHandle {
|
||||||
ffi::CGDisplayModeGetPixelWidth(mode) as u32,
|
ffi::CGDisplayModeGetPixelWidth(mode) as u32,
|
||||||
ffi::CGDisplayModeGetPixelHeight(mode) as u32,
|
ffi::CGDisplayModeGetPixelHeight(mode) as u32,
|
||||||
),
|
),
|
||||||
refresh_rate: refresh_rate as u16,
|
refresh_rate_millihertz,
|
||||||
bit_depth,
|
bit_depth,
|
||||||
monitor: monitor.clone(),
|
monitor: monitor.clone(),
|
||||||
native_mode: NativeDisplayMode(mode),
|
native_mode: NativeDisplayMode(mode),
|
||||||
|
|
|
@ -17,6 +17,10 @@ impl MonitorHandle {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> PhysicalSize<u32> {
|
pub fn size(&self) -> PhysicalSize<u32> {
|
||||||
PhysicalSize {
|
PhysicalSize {
|
||||||
width: 0,
|
width: 0,
|
||||||
|
@ -41,8 +45,8 @@ impl VideoMode {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
32
|
32000
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> RootMonitorHandle {
|
pub fn monitor(&self) -> RootMonitorHandle {
|
||||||
|
|
|
@ -9,8 +9,8 @@ use windows_sys::Win32::{
|
||||||
Graphics::Gdi::{
|
Graphics::Gdi::{
|
||||||
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
|
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
|
||||||
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT,
|
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT,
|
||||||
DM_PELSWIDTH, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW, MONITOR_DEFAULTTONEAREST,
|
DM_PELSWIDTH, ENUM_CURRENT_SETTINGS, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW,
|
||||||
MONITOR_DEFAULTTOPRIMARY,
|
MONITOR_DEFAULTTONEAREST, MONITOR_DEFAULTTOPRIMARY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ use crate::{
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate_millihertz: u32,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
// DEVMODEW is huge so we box it to avoid blowing up the size of winit::window::Fullscreen
|
// DEVMODEW is huge so we box it to avoid blowing up the size of winit::window::Fullscreen
|
||||||
pub(crate) native_video_mode: Box<DEVMODEW>,
|
pub(crate) native_video_mode: Box<DEVMODEW>,
|
||||||
|
@ -39,7 +39,7 @@ impl PartialEq for VideoMode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.size == other.size
|
self.size == other.size
|
||||||
&& self.bit_depth == other.bit_depth
|
&& self.bit_depth == other.bit_depth
|
||||||
&& self.refresh_rate == other.refresh_rate
|
&& self.refresh_rate_millihertz == other.refresh_rate_millihertz
|
||||||
&& self.monitor == other.monitor
|
&& self.monitor == other.monitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ impl std::hash::Hash for VideoMode {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.size.hash(state);
|
self.size.hash(state);
|
||||||
self.bit_depth.hash(state);
|
self.bit_depth.hash(state);
|
||||||
self.refresh_rate.hash(state);
|
self.refresh_rate_millihertz.hash(state);
|
||||||
self.monitor.hash(state);
|
self.monitor.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ impl std::fmt::Debug for VideoMode {
|
||||||
f.debug_struct("VideoMode")
|
f.debug_struct("VideoMode")
|
||||||
.field("size", &self.size)
|
.field("size", &self.size)
|
||||||
.field("bit_depth", &self.bit_depth)
|
.field("bit_depth", &self.bit_depth)
|
||||||
.field("refresh_rate", &self.refresh_rate)
|
.field("refresh_rate_millihertz", &self.refresh_rate_millihertz)
|
||||||
.field("monitor", &self.monitor)
|
.field("monitor", &self.monitor)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,8 @@ impl VideoMode {
|
||||||
self.bit_depth
|
self.bit_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u16 {
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||||
self.refresh_rate
|
self.refresh_rate_millihertz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monitor(&self) -> RootMonitorHandle {
|
pub fn monitor(&self) -> RootMonitorHandle {
|
||||||
|
@ -192,6 +192,23 @@ impl MonitorHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||||
|
let monitor_info = get_monitor_info(self.0).unwrap();
|
||||||
|
let device_name = monitor_info.szDevice.as_ptr();
|
||||||
|
unsafe {
|
||||||
|
let mut mode: DEVMODEW = mem::zeroed();
|
||||||
|
mode.dmSize = mem::size_of_val(&mode) as u16;
|
||||||
|
if EnumDisplaySettingsExW(device_name, ENUM_CURRENT_SETTINGS, &mut mode, 0)
|
||||||
|
== false.into()
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(mode.dmDisplayFrequency * 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn position(&self) -> PhysicalPosition<i32> {
|
pub fn position(&self) -> PhysicalPosition<i32> {
|
||||||
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
|
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
|
||||||
|
@ -233,7 +250,7 @@ impl MonitorHandle {
|
||||||
video_mode: VideoMode {
|
video_mode: VideoMode {
|
||||||
size: (mode.dmPelsWidth, mode.dmPelsHeight),
|
size: (mode.dmPelsWidth, mode.dmPelsHeight),
|
||||||
bit_depth: mode.dmBitsPerPel as u16,
|
bit_depth: mode.dmBitsPerPel as u16,
|
||||||
refresh_rate: mode.dmDisplayFrequency as u16,
|
refresh_rate_millihertz: mode.dmDisplayFrequency as u32 * 1000,
|
||||||
monitor: self.clone(),
|
monitor: self.clone(),
|
||||||
native_video_mode: Box::new(mode),
|
native_video_mode: Box::new(mode),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue