2023-08-29 14:01:25 -07:00
|
|
|
use super::{util, X11Error, XConnection};
|
2019-06-21 11:33:15 -04:00
|
|
|
use crate::{
|
|
|
|
|
dpi::{PhysicalPosition, PhysicalSize},
|
2023-12-26 22:12:33 +01:00
|
|
|
platform_impl::VideoModeHandle as PlatformVideoModeHandle,
|
2018-05-14 08:14:57 -04:00
|
|
|
};
|
2023-08-29 14:01:25 -07:00
|
|
|
use x11rb::{
|
|
|
|
|
connection::RequestConnection,
|
|
|
|
|
protocol::{
|
|
|
|
|
randr::{self, ConnectionExt as _},
|
|
|
|
|
xproto,
|
|
|
|
|
},
|
|
|
|
|
};
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2019-07-29 21:16:14 +03:00
|
|
|
// Used for testing. This should always be committed as false.
|
2018-05-14 08:14:57 -04:00
|
|
|
const DISABLE_MONITOR_LIST_CACHING: bool = false;
|
|
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
impl XConnection {
|
|
|
|
|
pub fn invalidate_cached_monitor_list(&self) -> Option<Vec<MonitorHandle>> {
|
|
|
|
|
// We update this lazily.
|
|
|
|
|
self.monitor_handles.lock().unwrap().take()
|
|
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-29 21:16:14 +03:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
2023-12-26 22:12:33 +01:00
|
|
|
pub struct VideoModeHandle {
|
2019-07-29 21:16:14 +03:00
|
|
|
pub(crate) size: (u32, u32),
|
|
|
|
|
pub(crate) bit_depth: u16,
|
2022-07-08 13:25:56 +03:00
|
|
|
pub(crate) refresh_rate_millihertz: u32,
|
2023-08-29 14:01:25 -07:00
|
|
|
pub(crate) native_mode: randr::Mode,
|
2019-07-29 21:16:14 +03:00
|
|
|
pub(crate) monitor: Option<MonitorHandle>,
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-26 22:12:33 +01:00
|
|
|
impl VideoModeHandle {
|
2019-07-29 21:16:14 +03:00
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
2019-07-29 21:16:14 +03:00
|
|
|
self.size.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn bit_depth(&self) -> u16 {
|
|
|
|
|
self.bit_depth
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-07-08 13:25:56 +03:00
|
|
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
|
|
|
|
self.refresh_rate_millihertz
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn monitor(&self) -> MonitorHandle {
|
|
|
|
|
self.monitor.clone().unwrap()
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-14 08:14:57 -04:00
|
|
|
#[derive(Debug, Clone)]
|
2019-02-05 10:30:33 -05:00
|
|
|
pub struct MonitorHandle {
|
2017-09-07 09:33:46 +01:00
|
|
|
/// The actual id
|
2023-08-29 14:01:25 -07:00
|
|
|
pub(crate) id: randr::Crtc,
|
2017-09-07 09:33:46 +01:00
|
|
|
/// The name of the monitor
|
2018-06-14 19:42:18 -04:00
|
|
|
pub(crate) name: String,
|
2017-09-07 09:33:46 +01:00
|
|
|
/// The size of the monitor
|
|
|
|
|
dimensions: (u32, u32),
|
|
|
|
|
/// The position of the monitor in the X screen
|
2017-10-19 20:08:05 +03:00
|
|
|
position: (i32, i32),
|
2017-09-07 09:33:46 +01:00
|
|
|
/// If the monitor is the primary one
|
|
|
|
|
primary: bool,
|
2022-07-08 13:25:56 +03:00
|
|
|
/// The refresh rate used by monitor.
|
|
|
|
|
refresh_rate_millihertz: Option<u32>,
|
2018-05-14 08:14:57 -04:00
|
|
|
/// The DPI scale factor
|
2020-01-03 14:52:27 -05:00
|
|
|
pub(crate) scale_factor: f64,
|
2018-05-14 08:14:57 -04:00
|
|
|
/// Used to determine which windows are on this monitor
|
2018-07-01 11:01:46 -04:00
|
|
|
pub(crate) rect: util::AaRect,
|
2019-06-12 21:07:25 +03:00
|
|
|
/// Supported video modes on this monitor
|
2023-12-26 22:12:33 +01:00
|
|
|
video_modes: Vec<VideoModeHandle>,
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
2015-05-07 13:14:09 +02:00
|
|
|
|
2019-07-29 21:16:14 +03:00
|
|
|
impl PartialEq for MonitorHandle {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
self.id == other.id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Eq for MonitorHandle {}
|
|
|
|
|
|
|
|
|
|
impl PartialOrd for MonitorHandle {
|
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
2022-01-01 13:00:11 +11:00
|
|
|
Some(self.cmp(other))
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Ord for MonitorHandle {
|
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
|
self.id.cmp(&other.id)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::hash::Hash for MonitorHandle {
|
|
|
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
|
self.id.hash(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 13:25:56 +03:00
|
|
|
#[inline]
|
2023-08-29 14:01:25 -07:00
|
|
|
pub fn mode_refresh_rate_millihertz(mode: &randr::ModeInfo) -> Option<u32> {
|
|
|
|
|
if mode.dot_clock > 0 && mode.htotal > 0 && mode.vtotal > 0 {
|
2022-12-22 21:35:33 +02:00
|
|
|
#[allow(clippy::unnecessary_cast)]
|
2023-08-29 14:01:25 -07:00
|
|
|
Some((mode.dot_clock as u64 * 1000 / (mode.htotal as u64 * mode.vtotal as u64)) as u32)
|
2022-07-08 13:25:56 +03:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 10:30:33 -05:00
|
|
|
impl MonitorHandle {
|
2019-07-29 21:16:14 +03:00
|
|
|
fn new(
|
2018-06-14 19:42:18 -04:00
|
|
|
xconn: &XConnection,
|
2023-08-29 14:01:25 -07:00
|
|
|
resources: &ScreenResources,
|
|
|
|
|
id: randr::Crtc,
|
|
|
|
|
crtc: &randr::GetCrtcInfoReply,
|
2018-05-14 08:14:57 -04:00
|
|
|
primary: bool,
|
2018-11-17 15:51:39 -05:00
|
|
|
) -> Option<Self> {
|
2023-08-29 14:01:25 -07:00
|
|
|
let (name, scale_factor, video_modes) = xconn.get_output_info(resources, crtc)?;
|
|
|
|
|
let dimensions = (crtc.width as u32, crtc.height as u32);
|
|
|
|
|
let position = (crtc.x as i32, crtc.y as i32);
|
2022-07-08 13:25:56 +03:00
|
|
|
|
|
|
|
|
// Get the refresh rate of the current video mode.
|
2023-08-29 14:01:25 -07:00
|
|
|
let current_mode = crtc.mode;
|
|
|
|
|
let screen_modes = resources.modes();
|
2022-07-08 13:25:56 +03:00
|
|
|
let refresh_rate_millihertz = screen_modes
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|mode| mode.id == current_mode)
|
|
|
|
|
.and_then(mode_refresh_rate_millihertz);
|
|
|
|
|
|
2018-07-01 11:01:46 -04:00
|
|
|
let rect = util::AaRect::new(position, dimensions);
|
2022-07-08 13:25:56 +03:00
|
|
|
|
2019-02-05 10:30:33 -05:00
|
|
|
Some(MonitorHandle {
|
2018-05-14 08:14:57 -04:00
|
|
|
id,
|
|
|
|
|
name,
|
2022-07-08 13:25:56 +03:00
|
|
|
refresh_rate_millihertz,
|
2020-01-03 14:52:27 -05:00
|
|
|
scale_factor,
|
2018-05-14 08:14:57 -04:00
|
|
|
dimensions,
|
|
|
|
|
position,
|
|
|
|
|
primary,
|
|
|
|
|
rect,
|
2019-06-12 21:07:25 +03:00
|
|
|
video_modes,
|
2018-11-17 15:51:39 -05:00
|
|
|
})
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
2014-09-19 15:42:47 +02:00
|
|
|
|
2019-11-10 13:55:29 -07:00
|
|
|
pub fn dummy() -> Self {
|
2019-09-23 11:45:29 -07:00
|
|
|
MonitorHandle {
|
|
|
|
|
id: 0,
|
|
|
|
|
name: "<dummy monitor>".into(),
|
2020-01-03 14:52:27 -05:00
|
|
|
scale_factor: 1.0,
|
2019-09-23 11:45:29 -07:00
|
|
|
dimensions: (1, 1),
|
|
|
|
|
position: (0, 0),
|
2022-07-08 13:25:56 +03:00
|
|
|
refresh_rate_millihertz: None,
|
2019-09-23 11:45:29 -07:00
|
|
|
primary: true,
|
|
|
|
|
rect: util::AaRect::new((0, 0), (1, 1)),
|
|
|
|
|
video_modes: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 10:18:20 -07:00
|
|
|
pub(crate) fn is_dummy(&self) -> bool {
|
|
|
|
|
// Zero is an invalid XID value; no real monitor will have it
|
|
|
|
|
self.id == 0
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn name(&self) -> Option<String> {
|
2017-09-07 09:33:46 +01:00
|
|
|
Some(self.name.clone())
|
2014-09-19 15:42:47 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 14:42:05 +02:00
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn native_identifier(&self) -> u32 {
|
2022-12-22 21:35:33 +02:00
|
|
|
self.id as _
|
2015-03-16 13:52:58 -07:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
2018-06-14 19:42:18 -04:00
|
|
|
self.dimensions.into()
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn position(&self) -> PhysicalPosition<i32> {
|
2018-06-14 19:42:18 -04:00
|
|
|
self.position.into()
|
2014-09-19 15:42:47 +02:00
|
|
|
}
|
2017-10-17 14:56:38 +03:00
|
|
|
|
2022-07-08 13:25:56 +03:00
|
|
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
|
|
|
|
self.refresh_rate_millihertz
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 14:56:38 +03:00
|
|
|
#[inline]
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
|
|
|
|
self.scale_factor
|
2017-10-17 14:56:38 +03:00
|
|
|
}
|
2019-06-12 21:07:25 +03:00
|
|
|
|
|
|
|
|
#[inline]
|
2023-12-26 22:12:33 +01:00
|
|
|
pub fn video_modes(&self) -> impl Iterator<Item = PlatformVideoModeHandle> {
|
2019-07-29 21:16:14 +03:00
|
|
|
let monitor = self.clone();
|
|
|
|
|
self.video_modes.clone().into_iter().map(move |mut x| {
|
|
|
|
|
x.monitor = Some(monitor.clone());
|
2023-12-26 22:12:33 +01:00
|
|
|
PlatformVideoModeHandle::X(x)
|
2019-07-29 21:16:14 +03:00
|
|
|
})
|
2019-06-12 21:07:25 +03:00
|
|
|
}
|
2014-09-19 15:42:47 +02:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2018-06-14 19:42:18 -04:00
|
|
|
impl XConnection {
|
2023-08-29 14:01:25 -07:00
|
|
|
pub fn get_monitor_for_window(
|
|
|
|
|
&self,
|
|
|
|
|
window_rect: Option<util::AaRect>,
|
|
|
|
|
) -> Result<MonitorHandle, X11Error> {
|
|
|
|
|
let monitors = self.available_monitors()?;
|
2019-09-23 11:45:29 -07:00
|
|
|
|
|
|
|
|
if monitors.is_empty() {
|
|
|
|
|
// Return a dummy monitor to avoid panicking
|
2023-08-29 14:01:25 -07:00
|
|
|
return Ok(MonitorHandle::dummy());
|
2019-09-23 11:45:29 -07:00
|
|
|
}
|
|
|
|
|
|
2023-10-27 00:56:23 +04:00
|
|
|
let default = monitors.first().unwrap();
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2018-06-14 19:42:18 -04:00
|
|
|
let window_rect = match window_rect {
|
|
|
|
|
Some(rect) => rect,
|
2023-08-29 14:01:25 -07:00
|
|
|
None => return Ok(default.to_owned()),
|
2018-06-14 19:42:18 -04:00
|
|
|
};
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2018-06-14 19:42:18 -04:00
|
|
|
let mut largest_overlap = 0;
|
|
|
|
|
let mut matched_monitor = default;
|
|
|
|
|
for monitor in &monitors {
|
|
|
|
|
let overlapping_area = window_rect.get_overlapping_area(&monitor.rect);
|
|
|
|
|
if overlapping_area > largest_overlap {
|
|
|
|
|
largest_overlap = overlapping_area;
|
2022-01-01 13:00:11 +11:00
|
|
|
matched_monitor = monitor;
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
}
|
|
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
Ok(matched_monitor.to_owned())
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
fn query_monitor_list(&self) -> Result<Vec<MonitorHandle>, X11Error> {
|
|
|
|
|
let root = self.default_root();
|
|
|
|
|
let resources = ScreenResources::from_connection(self.xcb_connection(), root)?;
|
|
|
|
|
|
|
|
|
|
// Pipeline all of the get-crtc requests.
|
|
|
|
|
let mut crtc_cookies = Vec::with_capacity(resources.crtcs().len());
|
|
|
|
|
for &crtc in resources.crtcs() {
|
|
|
|
|
crtc_cookies.push(
|
|
|
|
|
self.xcb_connection()
|
|
|
|
|
.randr_get_crtc_info(crtc, x11rb::CURRENT_TIME)?,
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
// Do this here so we do all of our requests in one shot.
|
|
|
|
|
let primary = self
|
|
|
|
|
.xcb_connection()
|
|
|
|
|
.randr_get_output_primary(root.root)?
|
|
|
|
|
.reply()?
|
|
|
|
|
.output;
|
|
|
|
|
|
|
|
|
|
let mut crtc_infos = Vec::with_capacity(crtc_cookies.len());
|
|
|
|
|
for cookie in crtc_cookies {
|
|
|
|
|
let reply = cookie.reply()?;
|
|
|
|
|
crtc_infos.push(reply);
|
|
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
let mut has_primary = false;
|
|
|
|
|
let mut available_monitors = Vec::with_capacity(resources.crtcs().len());
|
|
|
|
|
for (crtc_id, crtc) in resources.crtcs().iter().zip(crtc_infos.iter()) {
|
|
|
|
|
if crtc.width == 0 || crtc.height == 0 || crtc.outputs.is_empty() {
|
|
|
|
|
continue;
|
2018-05-22 09:07:46 -04:00
|
|
|
}
|
|
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
let is_primary = crtc.outputs[0] == primary;
|
|
|
|
|
has_primary |= is_primary;
|
|
|
|
|
let monitor = MonitorHandle::new(self, &resources, *crtc_id, crtc, is_primary);
|
|
|
|
|
available_monitors.extend(monitor);
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2023-08-29 14:01:25 -07:00
|
|
|
|
|
|
|
|
// If we don't have a primary monitor, just pick one ourselves!
|
|
|
|
|
if !has_primary {
|
|
|
|
|
if let Some(ref mut fallback) = available_monitors.first_mut() {
|
|
|
|
|
// Setting this here will come in handy if we ever add an `is_primary` method.
|
|
|
|
|
fallback.primary = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(available_monitors)
|
2018-05-14 08:14:57 -04:00
|
|
|
}
|
|
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
pub fn available_monitors(&self) -> Result<Vec<MonitorHandle>, X11Error> {
|
|
|
|
|
let mut monitors_lock = self.monitor_handles.lock().unwrap();
|
2023-12-24 19:27:02 +01:00
|
|
|
match *monitors_lock {
|
|
|
|
|
Some(ref monitors) => Ok(monitors.clone()),
|
|
|
|
|
None => {
|
|
|
|
|
let monitors = self.query_monitor_list()?;
|
|
|
|
|
if !DISABLE_MONITOR_LIST_CACHING {
|
|
|
|
|
*monitors_lock = Some(monitors.clone());
|
|
|
|
|
}
|
|
|
|
|
Ok(monitors)
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2018-06-14 19:42:18 -04:00
|
|
|
#[inline]
|
2023-08-29 14:01:25 -07:00
|
|
|
pub fn primary_monitor(&self) -> Result<MonitorHandle, X11Error> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.available_monitors()?
|
2018-06-14 19:42:18 -04:00
|
|
|
.into_iter()
|
|
|
|
|
.find(|monitor| monitor.primary)
|
2023-08-29 14:01:25 -07:00
|
|
|
.unwrap_or_else(MonitorHandle::dummy))
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
pub fn select_xrandr_input(&self, root: xproto::Window) -> Result<u8, X11Error> {
|
|
|
|
|
use randr::NotifyMask;
|
|
|
|
|
|
|
|
|
|
// Get extension info.
|
|
|
|
|
let info = self
|
|
|
|
|
.xcb_connection()
|
|
|
|
|
.extension_information(randr::X11_EXTENSION_NAME)?
|
|
|
|
|
.ok_or_else(|| X11Error::MissingExtension(randr::X11_EXTENSION_NAME))?;
|
|
|
|
|
|
|
|
|
|
// Select input data.
|
|
|
|
|
let event_mask =
|
|
|
|
|
NotifyMask::CRTC_CHANGE | NotifyMask::OUTPUT_PROPERTY | NotifyMask::SCREEN_CHANGE;
|
|
|
|
|
self.xcb_connection().randr_select_input(root, event_mask)?;
|
|
|
|
|
|
|
|
|
|
Ok(info.first_event)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) struct ScreenResources {
|
|
|
|
|
/// List of attached modes.
|
|
|
|
|
modes: Vec<randr::ModeInfo>,
|
|
|
|
|
|
|
|
|
|
/// List of attached CRTCs.
|
|
|
|
|
crtcs: Vec<randr::Crtc>,
|
|
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
impl ScreenResources {
|
|
|
|
|
pub(crate) fn modes(&self) -> &[randr::ModeInfo] {
|
|
|
|
|
&self.modes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn crtcs(&self) -> &[randr::Crtc] {
|
|
|
|
|
&self.crtcs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn from_connection(
|
|
|
|
|
conn: &impl x11rb::connection::Connection,
|
|
|
|
|
root: &x11rb::protocol::xproto::Screen,
|
|
|
|
|
) -> Result<Self, X11Error> {
|
On X11, query for higher Xrandr version
This appears to be the solution for the elusive #3335 issue. Previously,
in the Xlib backend, we used the "XRRQueryVersion" function to query for
the Xrandr version, and used that to determine whether we should use the
"GetScreenResources" call or the "GetScreenResourcesCurrent" call.
However, we passed the version "0, 0" into "XRRQueryVersion".
Previously with Xlib this wasn't a problem, as Xlib ignores the version
you pass in and substitutes it with the version of RandR it expects.
https://gitlab.freedesktop.org/xorg/lib/libxrandr/-/blob/master/src/Xrandr.c?ref_type=heads#L386-387
The way that "XRRQueryVersion" is implemented on the server end, it
compares the version passed into the request with the version supported
by the server. If the server's version is greater than the client
version, it just returns the client version. If the client's version is
greater, it passes the server's version. Since we were passing in "0, 0"
this means that the server returned "0, 0".
https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/randr/rrdispatch.c?ref_type=heads#L50-59
To determine whether we use "GetScreenResources" or
"GetScreenResourcesCurrent", we compare the version returned by the
server against "1, 3". Since we got "0, 0"- a version of XRandR so old
it doesn't even exist- we use "GetScreenResources".
The problem manifests in that "GetScreenResources" can take several
seconds to query the screen state based on the current hardware
configuration. On the other hand, "GetScreenResourcesCurrent" is fast;
it uses the server's hardware cache if it is available.
This problem is visible in XTrace. On the latest `master`:
```
000:<:00c2: 12: RANDR-Request(140,0): QueryVersion major-version=0 minor-version=0
000:>:00c2:32: Reply to QueryVersion: major-version=0 minor-version=0
000:<:00c3: 8: RANDR-Request(140,8): GetScreenResources window=0x0000076e
000:>:00c3:1600: Reply to GetScreenResources:
```
On the `v0.28.0` tag:
```
000:<:0019: 12: RANDR-Request(140,0): QueryVersion major-version=1 minor-version=6
000:>:0019:32: Reply to QueryVersion: major-version=1 minor-version=6
...later
000:<:002d: 8: RANDR-Request(140,25): GetScreenResourcesCurrent window=0x0000076e
000:>:002d:1600: Reply to GetScreenResourcesCurrent
```
This commit fixes this issue by requesting "1, 3" instead. This returns
the version we expect, where we can now use "GetScreenResourcesCurrent"
properly.
Fixes #3335
Signed-off-by: John Nunley <dev@notgull.net>
2023-12-29 08:13:06 -08:00
|
|
|
let version = conn.randr_query_version(1, 3)?.reply()?;
|
2023-08-29 14:01:25 -07:00
|
|
|
|
|
|
|
|
if (version.major_version == 1 && version.minor_version >= 3) || version.major_version > 1 {
|
|
|
|
|
let reply = conn
|
|
|
|
|
.randr_get_screen_resources_current(root.root)?
|
|
|
|
|
.reply()?;
|
|
|
|
|
Ok(Self::from_get_screen_resources_current_reply(reply))
|
|
|
|
|
} else {
|
|
|
|
|
let reply = conn.randr_get_screen_resources(root.root)?.reply()?;
|
|
|
|
|
Ok(Self::from_get_screen_resources_reply(reply))
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2023-08-29 14:01:25 -07:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
pub(crate) fn from_get_screen_resources_reply(reply: randr::GetScreenResourcesReply) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
modes: reply.modes,
|
|
|
|
|
crtcs: reply.crtcs,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
|
2023-08-29 14:01:25 -07:00
|
|
|
pub(crate) fn from_get_screen_resources_current_reply(
|
|
|
|
|
reply: randr::GetScreenResourcesCurrentReply,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
modes: reply.modes,
|
|
|
|
|
crtcs: reply.crtcs,
|
|
|
|
|
}
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2018-05-14 08:14:57 -04:00
|
|
|
}
|