Support listing available video modes for a monitor (#896)
* Support listing available video modes for a monitor * Use derivative for Windows `MonitorHandle` * Update FEATURES.md * Fix multiline if statement * Add documentation for `VideoMode` type
This commit is contained in:
parent
2b89ddec15
commit
47b5dfa034
13 changed files with 254 additions and 23 deletions
|
|
@ -14,7 +14,7 @@ use icon::Icon;
|
|||
use error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use event::Event;
|
||||
use event_loop::{EventLoopClosed, ControlFlow, EventLoopWindowTarget as RootELW};
|
||||
use monitor::MonitorHandle as RootMonitorHandle;
|
||||
use monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
||||
use window::{WindowAttributes, CursorIcon};
|
||||
use self::x11::{XConnection, XError};
|
||||
use self::x11::ffi::XVisualInfo;
|
||||
|
|
@ -142,6 +142,14 @@ impl MonitorHandle {
|
|||
&MonitorHandle::Wayland(ref m) => m.hidpi_factor() as f64,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {
|
||||
match self {
|
||||
MonitorHandle::X(m) => Box::new(m.video_modes()),
|
||||
MonitorHandle::Wayland(m) => Box::new(m.video_modes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}
|
|||
use event::ModifiersState;
|
||||
use dpi::{PhysicalPosition, PhysicalSize};
|
||||
use platform_impl::platform::sticky_exit_callback;
|
||||
use monitor::VideoMode;
|
||||
|
||||
use super::window::WindowStore;
|
||||
use super::WindowId;
|
||||
|
|
@ -584,6 +585,20 @@ impl MonitorHandle {
|
|||
.with_info(&self.proxy, |_, info| info.scale_factor)
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode>
|
||||
{
|
||||
self.mgr
|
||||
.with_info(&self.proxy, |_, info| info.modes.clone())
|
||||
.unwrap_or(vec![])
|
||||
.into_iter()
|
||||
.map(|x| VideoMode {
|
||||
dimensions: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: 32
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn primary_monitor(outputs: &OutputMgr) -> MonitorHandle {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::os::raw::*;
|
|||
use parking_lot::Mutex;
|
||||
|
||||
use dpi::{PhysicalPosition, PhysicalSize};
|
||||
use monitor::VideoMode;
|
||||
use super::{util, XConnection, XError};
|
||||
use super::ffi::{
|
||||
RRCrtcChangeNotifyMask,
|
||||
|
|
@ -56,6 +57,8 @@ pub struct MonitorHandle {
|
|||
pub(crate) hidpi_factor: f64,
|
||||
/// Used to determine which windows are on this monitor
|
||||
pub(crate) rect: util::AaRect,
|
||||
/// Supported video modes on this monitor
|
||||
video_modes: Vec<VideoMode>,
|
||||
}
|
||||
|
||||
impl MonitorHandle {
|
||||
|
|
@ -66,7 +69,7 @@ impl MonitorHandle {
|
|||
repr: util::MonitorRepr,
|
||||
primary: bool,
|
||||
) -> Option<Self> {
|
||||
let (name, hidpi_factor) = unsafe { xconn.get_output_info(resources, &repr)? };
|
||||
let (name, hidpi_factor, video_modes) = unsafe { xconn.get_output_info(resources, &repr)? };
|
||||
let (dimensions, position) = unsafe { (repr.dimensions(), repr.position()) };
|
||||
let rect = util::AaRect::new(position, dimensions);
|
||||
Some(MonitorHandle {
|
||||
|
|
@ -77,6 +80,7 @@ impl MonitorHandle {
|
|||
position,
|
||||
primary,
|
||||
rect,
|
||||
video_modes,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +105,11 @@ impl MonitorHandle {
|
|||
pub fn hidpi_factor(&self) -> f64 {
|
||||
self.hidpi_factor
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.video_modes.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl XConnection {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{env, slice};
|
||||
use std::str::FromStr;
|
||||
|
||||
use monitor::VideoMode;
|
||||
use dpi::validate_hidpi_factor;
|
||||
use super::*;
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ impl XConnection {
|
|||
&self,
|
||||
resources: *mut ffi::XRRScreenResources,
|
||||
repr: &MonitorRepr,
|
||||
) -> Option<(String, f64)> {
|
||||
) -> Option<(String, f64, Vec<VideoMode>)> {
|
||||
let output_info = (self.xrandr.XRRGetOutputInfo)(
|
||||
self.display,
|
||||
resources,
|
||||
|
|
@ -114,6 +115,33 @@ impl XConnection {
|
|||
let _ = self.check_errors(); // discard `BadRROutput` error
|
||||
return None;
|
||||
}
|
||||
|
||||
let screen = (self.xlib.XDefaultScreen)(self.display);
|
||||
let bit_depth = (self.xlib.XDefaultDepth)(self.display, screen);
|
||||
|
||||
let output_modes =
|
||||
slice::from_raw_parts((*output_info).modes, (*output_info).nmode as usize);
|
||||
let resource_modes = slice::from_raw_parts((*resources).modes, (*resources).nmode as usize);
|
||||
|
||||
let modes = resource_modes
|
||||
.iter()
|
||||
// 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
|
||||
};
|
||||
|
||||
VideoMode {
|
||||
dimensions: (x.width, x.height),
|
||||
refresh_rate: (refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: bit_depth as u16,
|
||||
}
|
||||
});
|
||||
|
||||
let name_slice = slice::from_raw_parts(
|
||||
(*output_info).name as *mut u8,
|
||||
(*output_info).nameLen as usize,
|
||||
|
|
@ -129,6 +157,6 @@ impl XConnection {
|
|||
};
|
||||
|
||||
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
||||
Some((name, hidpi_factor))
|
||||
Some((name, hidpi_factor, modes.collect()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue