diff --git a/CHANGELOG.md b/CHANGELOG.md index cc52579c..7b66db57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - On Windows, catch panics in event loop child thread and forward them to the parent thread. This prevents an invocation of undefined behavior due to unwinding into foreign code. - On Windows, fix issue where resizing or moving window combined with grabbing the cursor would freeze program. - On Windows, fix issue where resizing or moving window would eat `Awakened` events. +- On X11, fixed a segfault when using virtual monitors with XRandR. # Version 0.18.0 (2018-11-07) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 01233354..cf302caa 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -382,7 +382,7 @@ unsafe extern "C" fn x_error_callback( minor_code: (*event).minor_code, }; - eprintln!("[winit X11 error] {:#?}", error); + error!("X11 error: {:#?}", error); *xconn.latest_error.lock() = Some(error); } diff --git a/src/platform/linux/x11/monitor.rs b/src/platform/linux/x11/monitor.rs index 5912d772..d6309f63 100644 --- a/src/platform/linux/x11/monitor.rs +++ b/src/platform/linux/x11/monitor.rs @@ -65,11 +65,11 @@ impl MonitorId { id: u32, repr: util::MonitorRepr, primary: bool, - ) -> Self { - let (name, hidpi_factor) = unsafe { xconn.get_output_info(resources, &repr) }; + ) -> Option { + let (name, hidpi_factor) = unsafe { xconn.get_output_info(resources, &repr)? }; let (dimensions, position) = unsafe { (repr.get_dimensions(), repr.get_position()) }; let rect = util::AaRect::new(position, dimensions); - MonitorId { + Some(MonitorId { id, name, hidpi_factor, @@ -77,7 +77,7 @@ impl MonitorId { position, primary, rect, - } + }) } pub fn get_name(&self) -> Option { @@ -153,13 +153,13 @@ impl XConnection { let monitor = monitors.offset(monitor_index as isize); let is_primary = (*monitor).primary != 0; has_primary |= is_primary; - available.push(MonitorId::from_repr( + MonitorId::from_repr( self, resources, monitor_index as u32, monitor.into(), is_primary, - )); + ).map(|monitor_id| available.push(monitor_id)); } (xrandr_1_5.XRRFreeMonitors)(monitors); } else { @@ -176,13 +176,13 @@ impl XConnection { let crtc = util::MonitorRepr::from(crtc); let is_primary = crtc.get_output() == primary; has_primary |= is_primary; - available.push(MonitorId::from_repr( + MonitorId::from_repr( self, resources, crtc_id as u32, crtc, is_primary, - )); + ).map(|monitor_id| available.push(monitor_id)); } (self.xrandr.XRRFreeCrtcInfo)(crtc); } diff --git a/src/platform/linux/x11/util/randr.rs b/src/platform/linux/x11/util/randr.rs index f0b69d9b..e730469b 100644 --- a/src/platform/linux/x11/util/randr.rs +++ b/src/platform/linux/x11/util/randr.rs @@ -79,12 +79,23 @@ impl From<*mut ffi::XRRCrtcInfo> for MonitorRepr { } impl XConnection { - pub unsafe fn get_output_info(&self, resources: *mut ffi::XRRScreenResources, repr: &MonitorRepr) -> (String, f64) { + pub unsafe fn get_output_info( + &self, + resources: *mut ffi::XRRScreenResources, + repr: &MonitorRepr, + ) -> Option<(String, f64)> { let output_info = (self.xrandr.XRRGetOutputInfo)( self.display, resources, repr.get_output(), ); + if output_info.is_null() { + // When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display) + // it's possible for it to return null. + // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=816596 + let _ = self.check_errors(); // discard `BadRROutput` error + return None; + } let name_slice = slice::from_raw_parts( (*output_info).name as *mut u8, (*output_info).nameLen as usize, @@ -95,6 +106,6 @@ impl XConnection { ((*output_info).mm_width as u64, (*output_info).mm_height as u64), ); (self.xrandr.XRRFreeOutputInfo)(output_info); - (name, hidpi_factor) + Some((name, hidpi_factor)) } }