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:
Kirill Chibisov 2022-07-08 13:25:56 +03:00 committed by GitHub
parent e289f30e5d
commit a06bb3f992
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 172 additions and 81 deletions

View file

@ -256,6 +256,11 @@ impl MonitorHandle {
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]
pub fn scale_factor(&self) -> f64 {
x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as f64)
@ -287,8 +292,8 @@ impl VideoMode {
}
#[inline]
pub fn refresh_rate(&self) -> u16 {
x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate())
pub fn refresh_rate_millihertz(&self) -> u32 {
x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate_millihertz())
}
#[inline]

View file

@ -167,6 +167,16 @@ impl MonitorHandle {
.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]
pub fn scale_factor(&self) -> i32 {
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 {
video_mode: PlatformVideoMode::Wayland(VideoMode {
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,
monitor: monitor.clone(),
}),
@ -194,7 +204,7 @@ impl MonitorHandle {
pub struct VideoMode {
pub(crate) size: PhysicalSize<u32>,
pub(crate) bit_depth: u16,
pub(crate) refresh_rate: u16,
pub(crate) refresh_rate_millihertz: u32,
pub(crate) monitor: MonitorHandle,
}
@ -210,8 +220,8 @@ impl VideoMode {
}
#[inline]
pub fn refresh_rate(&self) -> u16 {
self.refresh_rate
pub fn refresh_rate_millihertz(&self) -> u32 {
self.refresh_rate_millihertz
}
pub fn monitor(&self) -> RootMonitorHandle {

View file

@ -1,4 +1,5 @@
use std::os::raw::*;
use std::slice;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
@ -6,7 +7,7 @@ use parking_lot::Mutex;
use super::{
ffi::{
RRCrtc, RRCrtcChangeNotifyMask, RRMode, RROutputPropertyNotifyMask,
RRScreenChangeNotifyMask, True, Window, XRRCrtcInfo, XRRScreenResources,
RRScreenChangeNotifyMask, True, Window, XRRCrtcInfo, XRRModeInfo, XRRScreenResources,
},
util, XConnection, XError,
};
@ -30,7 +31,7 @@ pub fn invalidate_cached_monitor_list() -> Option<Vec<MonitorHandle>> {
pub struct VideoMode {
pub(crate) size: (u32, u32),
pub(crate) bit_depth: u16,
pub(crate) refresh_rate: u16,
pub(crate) refresh_rate_millihertz: u32,
pub(crate) native_mode: RRMode,
pub(crate) monitor: Option<MonitorHandle>,
}
@ -47,8 +48,8 @@ impl VideoMode {
}
#[inline]
pub fn refresh_rate(&self) -> u16 {
self.refresh_rate
pub fn refresh_rate_millihertz(&self) -> u32 {
self.refresh_rate_millihertz
}
#[inline]
@ -71,6 +72,8 @@ pub struct MonitorHandle {
position: (i32, i32),
/// If the monitor is the primary one
primary: bool,
/// The refresh rate used by monitor.
refresh_rate_millihertz: Option<u32>,
/// The DPI scale factor
pub(crate) scale_factor: f64,
/// 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 {
fn new(
xconn: &XConnection,
@ -116,10 +128,22 @@ impl MonitorHandle {
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 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);
Some(MonitorHandle {
id,
name,
refresh_rate_millihertz,
scale_factor,
dimensions,
position,
@ -136,6 +160,7 @@ impl MonitorHandle {
scale_factor: 1.0,
dimensions: (1, 1),
position: (0, 0),
refresh_rate_millihertz: None,
primary: true,
rect: util::AaRect::new((0, 0), (1, 1)),
video_modes: Vec::new(),
@ -164,6 +189,10 @@ impl MonitorHandle {
self.position.into()
}
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
self.refresh_rate_millihertz
}
#[inline]
pub fn scale_factor(&self) -> f64 {
self.scale_factor

View file

@ -4,6 +4,7 @@ use super::{
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};
/// Represents values of `WINIT_HIDPI_FACTOR`.
@ -80,18 +81,13 @@ impl XConnection {
// XRROutputInfo contains an array of mode ids that correspond to
// modes in the array in XRRScreenResources
.filter(|x| output_modes.iter().any(|id| x.id == *id))
.map(|x| {
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
};
.map(|mode| {
VideoMode {
size: (x.width, x.height),
refresh_rate: (refresh_rate as f32 / 1000.0).round() as u16,
size: (mode.width, mode.height),
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode)
.unwrap_or(0),
bit_depth: bit_depth as u16,
native_mode: x.id,
native_mode: mode.id,
// This is populated in `MonitorHandle::video_modes` as the
// video mode is returned to the user
monitor: None,