From 107a1e7332992dc4fa5c9141c443c0635a007d9a Mon Sep 17 00:00:00 2001 From: Johannes Hofmann Date: Sat, 3 Feb 2018 11:18:51 +0100 Subject: [PATCH] x11: Support XRandR versions older than 1.5 (#394) * x11: Support XRandR versions older than 1.5 Fixes #392 Previously, initializing the member `xrandr` of `XConnection` resulted in a panic when symbols from XRandR version 1.5 were missing. There was already code to handle older versions of XRandR but it was never executed because of the panic. The member `XConnection.xrandr` now contains only functions that can safely be used with older versions. Additionally, this commit adds a new member to `XConnection` of type `Option` that only contains a value if version 1.5 functionality is present. * x11: Document the xrandr* members of XConnection --- src/platform/linux/x11/monitor.rs | 13 +++++-------- src/platform/linux/x11/xdisplay.rs | 9 +++++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/platform/linux/x11/monitor.rs b/src/platform/linux/x11/monitor.rs index c8db06b0..d285ac0a 100644 --- a/src/platform/linux/x11/monitor.rs +++ b/src/platform/linux/x11/monitor.rs @@ -25,16 +25,13 @@ pub fn get_available_monitors(x: &Arc) -> Vec { let root = (x.xlib.XDefaultRootWindow)(x.display); let resources = (x.xrandr.XRRGetScreenResources)(x.display, root); - let mut major = 0; - let mut minor = 0; - (x.xrandr.XRRQueryVersion)(x.display, &mut major, &mut minor); - if ((major as u64)<<32)+(minor as u64) >= (1<<32)+5 { + if let Some(ref xrandr_1_5) = x.xrandr_1_5 { // We're in XRandR >= 1.5, enumerate Monitors to handle things like MST and videowalls let mut nmonitors = 0; - let monitors = (x.xrandr.XRRGetMonitors)(x.display, root, 1, &mut nmonitors); + let monitors = (xrandr_1_5.XRRGetMonitors)(x.display, root, 1, &mut nmonitors); for i in 0..nmonitors { let monitor = *(monitors.offset(i as isize)); - let output = (x.xrandr.XRRGetOutputInfo)(x.display, resources, *(monitor.outputs.offset(0))); + let output = (xrandr_1_5.XRRGetOutputInfo)(x.display, resources, *(monitor.outputs.offset(0))); let nameslice = slice::from_raw_parts((*output).name as *mut u8, (*output).nameLen as usize); let name = String::from_utf8_lossy(nameslice).into_owned(); let hidpi_factor = { @@ -47,7 +44,7 @@ pub fn get_available_monitors(x: &Arc) -> Vec { // Quantize 1/12 step size ((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0) }; - (x.xrandr.XRRFreeOutputInfo)(output); + (xrandr_1_5.XRRFreeOutputInfo)(output); available.push(MonitorId{ id: i as u32, name, @@ -57,7 +54,7 @@ pub fn get_available_monitors(x: &Arc) -> Vec { primary: (monitor.primary != 0), }); } - (x.xrandr.XRRFreeMonitors)(monitors); + (xrandr_1_5.XRRFreeMonitors)(monitors); } else { // We're in XRandR < 1.5, enumerate CRTCs. Everything will work but MST and // videowall setups will show more monitors than the logical groups the user diff --git a/src/platform/linux/x11/xdisplay.rs b/src/platform/linux/x11/xdisplay.rs index 62d93295..ec325929 100644 --- a/src/platform/linux/x11/xdisplay.rs +++ b/src/platform/linux/x11/xdisplay.rs @@ -10,7 +10,10 @@ use super::ffi; /// A connection to an X server. pub struct XConnection { pub xlib: ffi::Xlib, - pub xrandr: ffi::Xrandr, + /// Exposes XRandR functions from version < 1.5 + pub xrandr: ffi::Xrandr_2_2_0, + /// Exposes XRandR functions from version = 1.5 + pub xrandr_1_5: Option, pub xcursor: ffi::Xcursor, pub xinput2: ffi::XInput2, pub xlib_xcb: ffi::Xlib_xcb, @@ -28,7 +31,8 @@ impl XConnection { // opening the libraries let xlib = try!(ffi::Xlib::open()); let xcursor = try!(ffi::Xcursor::open()); - let xrandr = try!(ffi::Xrandr::open()); + let xrandr = try!(ffi::Xrandr_2_2_0::open()); + let xrandr_1_5 = ffi::Xrandr::open().ok(); let xinput2 = try!(ffi::XInput2::open()); let xlib_xcb = try!(ffi::Xlib_xcb::open()); @@ -47,6 +51,7 @@ impl XConnection { Ok(XConnection { xlib: xlib, xrandr: xrandr, + xrandr_1_5: xrandr_1_5, xcursor: xcursor, xinput2: xinput2, xlib_xcb: xlib_xcb,