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<ffi::XRandr>` that only contains
a value if version 1.5 functionality is present.

* x11: Document the xrandr* members of XConnection
This commit is contained in:
Johannes Hofmann 2018-02-03 11:18:51 +01:00 committed by Pierre Krieger
parent 150d2706f9
commit 107a1e7332
2 changed files with 12 additions and 10 deletions

View file

@ -25,16 +25,13 @@ pub fn get_available_monitors(x: &Arc<XConnection>) -> Vec<MonitorId> {
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<XConnection>) -> Vec<MonitorId> {
// 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<XConnection>) -> Vec<MonitorId> {
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

View file

@ -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<ffi::Xrandr>,
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,