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
This commit is contained in:
Murarth 2019-09-23 11:45:29 -07:00 committed by Osspial
parent c0a7900341
commit 472eddcc1b
4 changed files with 38 additions and 11 deletions

View file

@ -17,6 +17,7 @@
- On macOS, fix events not being emitted during modal loops, such as when windows are being resized - On macOS, fix events not being emitted during modal loops, such as when windows are being resized
by the user. by the user.
- On Windows, fix hovering the mouse over the active window creating an endless stream of CursorMoved events. - 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. - On X11, prevent stealing input focus when creating a new window.
Only steal input focus when entering fullscreen mode. Only steal input focus when entering fullscreen mode.

View file

@ -389,7 +389,11 @@ impl<T: 'static> EventProcessor<T> {
let window_rect = util::AaRect::new(new_outer_position, new_inner_size); let window_rect = util::AaRect::new(new_outer_position, new_inner_size);
monitor = wt.xconn.get_monitor_for_window(Some(window_rect)); monitor = wt.xconn.get_monitor_for_window(Some(window_rect));
let new_hidpi_factor = monitor.hidpi_factor; 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 new_hidpi_factor
}; };
if last_hidpi_factor != new_hidpi_factor { if last_hidpi_factor != new_hidpi_factor {

View file

@ -130,6 +130,19 @@ impl MonitorHandle {
}) })
} }
fn dummy() -> Self {
MonitorHandle {
id: 0,
name: "<dummy monitor>".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<String> { pub fn name(&self) -> Option<String> {
Some(self.name.clone()) Some(self.name.clone())
} }
@ -167,9 +180,13 @@ impl MonitorHandle {
impl XConnection { impl XConnection {
pub fn get_monitor_for_window(&self, window_rect: Option<util::AaRect>) -> MonitorHandle { pub fn get_monitor_for_window(&self, window_rect: Option<util::AaRect>) -> MonitorHandle {
let monitors = self.available_monitors(); let monitors = self.available_monitors();
let default = monitors
.get(0) if monitors.is_empty() {
.expect("[winit] Failed to find any monitors using XRandR."); // Return a dummy monitor to avoid panicking
return MonitorHandle::dummy();
}
let default = monitors.get(0).unwrap();
let window_rect = match window_rect { let window_rect = match window_rect {
Some(rect) => rect, Some(rect) => rect,
@ -259,7 +276,7 @@ impl XConnection {
self.available_monitors() self.available_monitors()
.into_iter() .into_iter()
.find(|monitor| monitor.primary) .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<c_int, XError> { pub fn select_xrandr_input(&self, root: Window) -> Result<c_int, XError> {

View file

@ -119,7 +119,7 @@ impl UnownedWindow {
.unwrap_or(1.0) .unwrap_or(1.0)
}) })
} else { } else {
return Err(os_error!(OsError::XMisc("No monitors were detected."))); 1.0
}; };
info!("Guessed window DPI factor: {}", dpi_factor); info!("Guessed window DPI factor: {}", dpi_factor);
@ -637,6 +637,11 @@ impl UnownedWindow {
_ => unreachable!(), _ => unreachable!(),
}; };
// Don't set fullscreen on an invalid dummy monitor handle
if monitor.id == 0 {
return None;
}
if let Some(video_mode) = video_mode { if let Some(video_mode) = video_mode {
// FIXME: this is actually not correct if we're setting the // FIXME: this is actually not correct if we're setting the
// video mode to a resolution higher than the current // video mode to a resolution higher than the current
@ -704,11 +709,11 @@ impl UnownedWindow {
pub fn current_monitor(&self) -> X11MonitorHandle { pub fn current_monitor(&self) -> X11MonitorHandle {
let monitor = self.shared_state.lock().last_monitor.as_ref().cloned(); let monitor = self.shared_state.lock().last_monitor.as_ref().cloned();
monitor.unwrap_or_else(|| { monitor.unwrap_or_else(|| {
let monitor = self let monitor = self.xconn.get_monitor_for_window(Some(self.get_rect()));
.xconn // Avoid caching an invalid dummy monitor handle
.get_monitor_for_window(Some(self.get_rect())) if monitor.id != 0 {
.to_owned(); self.shared_state.lock().last_monitor = Some(monitor.clone());
self.shared_state.lock().last_monitor = Some(monitor.clone()); }
monitor monitor
}) })
} }