From 472eddcc1bf93e30953da692f43b37e6814199eb Mon Sep 17 00:00:00 2001 From: Murarth Date: Mon, 23 Sep 2019 11:45:29 -0700 Subject: [PATCH] X11: Fix panic when no monitors are available (#1158) * X11: Fix panic when no monitors are available * Set dummy monitor's dimensions to `(1, 1)` * X11: Avoid panicking when there are no monitors in Window::new --- CHANGELOG.md | 1 + .../linux/x11/event_processor.rs | 6 ++++- src/platform_impl/linux/x11/monitor.rs | 25 ++++++++++++++++--- src/platform_impl/linux/x11/window.rs | 17 ++++++++----- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34af8f51..adc5a793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - On macOS, fix events not being emitted during modal loops, such as when windows are being resized by the user. - On Windows, fix hovering the mouse over the active window creating an endless stream of CursorMoved events. +- On X11, return dummy monitor data to avoid panicking when no monitors exist. - On X11, prevent stealing input focus when creating a new window. Only steal input focus when entering fullscreen mode. diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index d65a0133..3ca469df 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -389,7 +389,11 @@ impl EventProcessor { let window_rect = util::AaRect::new(new_outer_position, new_inner_size); monitor = wt.xconn.get_monitor_for_window(Some(window_rect)); let new_hidpi_factor = monitor.hidpi_factor; - shared_state_lock.last_monitor = Some(monitor.clone()); + + // Avoid caching an invalid dummy monitor handle + if monitor.id != 0 { + shared_state_lock.last_monitor = Some(monitor.clone()); + } new_hidpi_factor }; if last_hidpi_factor != new_hidpi_factor { diff --git a/src/platform_impl/linux/x11/monitor.rs b/src/platform_impl/linux/x11/monitor.rs index 33a694e0..bb75e806 100644 --- a/src/platform_impl/linux/x11/monitor.rs +++ b/src/platform_impl/linux/x11/monitor.rs @@ -130,6 +130,19 @@ impl MonitorHandle { }) } + fn dummy() -> Self { + MonitorHandle { + id: 0, + name: "".into(), + hidpi_factor: 1.0, + dimensions: (1, 1), + position: (0, 0), + primary: true, + rect: util::AaRect::new((0, 0), (1, 1)), + video_modes: Vec::new(), + } + } + pub fn name(&self) -> Option { Some(self.name.clone()) } @@ -167,9 +180,13 @@ impl MonitorHandle { impl XConnection { pub fn get_monitor_for_window(&self, window_rect: Option) -> MonitorHandle { let monitors = self.available_monitors(); - let default = monitors - .get(0) - .expect("[winit] Failed to find any monitors using XRandR."); + + if monitors.is_empty() { + // Return a dummy monitor to avoid panicking + return MonitorHandle::dummy(); + } + + let default = monitors.get(0).unwrap(); let window_rect = match window_rect { Some(rect) => rect, @@ -259,7 +276,7 @@ impl XConnection { self.available_monitors() .into_iter() .find(|monitor| monitor.primary) - .expect("[winit] Failed to find any monitors using XRandR.") + .unwrap_or_else(MonitorHandle::dummy) } pub fn select_xrandr_input(&self, root: Window) -> Result { diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 335e529f..cf7759ec 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -119,7 +119,7 @@ impl UnownedWindow { .unwrap_or(1.0) }) } else { - return Err(os_error!(OsError::XMisc("No monitors were detected."))); + 1.0 }; info!("Guessed window DPI factor: {}", dpi_factor); @@ -637,6 +637,11 @@ impl UnownedWindow { _ => unreachable!(), }; + // Don't set fullscreen on an invalid dummy monitor handle + if monitor.id == 0 { + return None; + } + if let Some(video_mode) = video_mode { // FIXME: this is actually not correct if we're setting the // video mode to a resolution higher than the current @@ -704,11 +709,11 @@ impl UnownedWindow { pub fn current_monitor(&self) -> X11MonitorHandle { let monitor = self.shared_state.lock().last_monitor.as_ref().cloned(); monitor.unwrap_or_else(|| { - let monitor = self - .xconn - .get_monitor_for_window(Some(self.get_rect())) - .to_owned(); - self.shared_state.lock().last_monitor = Some(monitor.clone()); + let monitor = self.xconn.get_monitor_for_window(Some(self.get_rect())); + // Avoid caching an invalid dummy monitor handle + if monitor.id != 0 { + self.shared_state.lock().last_monitor = Some(monitor.clone()); + } monitor }) }