From cac627ed05588ef6cbbce7a1e837a0b4016e61fe Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Mon, 7 Sep 2020 20:09:24 +0300 Subject: [PATCH] Make 'current_monitor' return 'Option' On certain platforms window couldn't be on any monitor resulting in failures of 'current_monitor' function. Such issue was happening on Wayland, since the window isn't on any monitor, unless the user has drawn something into it. Returning 'Option' will give an ability to handle such situations gracefully by properly indicating that there's no current monitor. Fixes #793. --- CHANGELOG.md | 5 +++-- examples/multithreaded.rs | 6 +++--- examples/window_debug.rs | 4 ++-- src/platform_impl/android/mod.rs | 6 +++--- src/platform_impl/ios/window.rs | 9 +++++++-- src/platform_impl/linux/mod.rs | 19 ++++++++++++++++--- src/platform_impl/linux/wayland/window.rs | 12 +++++++----- src/platform_impl/macos/window.rs | 8 +++++++- src/platform_impl/macos/window_delegate.rs | 3 ++- src/platform_impl/web/window.rs | 10 ++++++++-- src/platform_impl/windows/window.rs | 6 +++--- src/window.rs | 6 ++++-- 12 files changed, 65 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3658c23d..3acb79f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,9 +25,10 @@ - **Breaking:** On Web, `set_cursor_position` and `set_cursor_grab` will now always return an error. - **Breaking:** `PixelDelta` scroll events now return a `PhysicalPosition`. - On NetBSD, fixed crash due to incorrect detection of the main thread. -- **Breaking:** The virtual key code `Subtract` has been renamed to `NumpadSubtract` -- **Breaking:** On X11, `-` key is mapped to the `Minus` virtual key code, instead of `Subtract` +- **Breaking:** The virtual key code `Subtract` has been renamed to `NumpadSubtract`. +- **Breaking:** On X11, `-` key is mapped to the `Minus` virtual key code, instead of `Subtract`. - On macOS, fix inverted horizontal scroll. +- **Breaking:** `current_monitor` now returns `Option`. # 0.22.2 (2020-05-16) diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index 60f9d802..4141775e 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -21,7 +21,7 @@ fn main() { .build(&event_loop) .unwrap(); - let mut video_modes: Vec<_> = window.current_monitor().video_modes().collect(); + let mut video_modes: Vec<_> = window.current_monitor().unwrap().video_modes().collect(); let mut video_mode_id = 0usize; let (tx, rx) = mpsc::channel(); @@ -34,7 +34,7 @@ fn main() { // was moved to an another monitor, so that the window // appears on this monitor instead when we go fullscreen let previous_video_mode = video_modes.iter().cloned().nth(video_mode_id); - video_modes = window.current_monitor().video_modes().collect(); + video_modes = window.current_monitor().unwrap().video_modes().collect(); video_mode_id = video_mode_id.min(video_modes.len()); let video_mode = video_modes.iter().nth(video_mode_id); @@ -83,7 +83,7 @@ fn main() { } F => window.set_fullscreen(match (state, modifiers.alt()) { (true, false) => { - Some(Fullscreen::Borderless(window.current_monitor())) + Some(Fullscreen::Borderless(window.current_monitor().unwrap())) } (true, true) => Some(Fullscreen::Exclusive( video_modes.iter().nth(video_mode_id).unwrap().clone(), diff --git a/examples/window_debug.rs b/examples/window_debug.rs index f6e960a7..e8de3cf0 100644 --- a/examples/window_debug.rs +++ b/examples/window_debug.rs @@ -70,7 +70,7 @@ fn main() { size.width * size.height } - let monitor = window.current_monitor(); + let monitor = window.current_monitor().unwrap(); if let Some(mode) = monitor .video_modes() .max_by(|a, b| area(a.size()).cmp(&area(b.size()))) @@ -84,7 +84,7 @@ fn main() { if window.fullscreen().is_some() { window.set_fullscreen(None); } else { - let monitor = window.current_monitor(); + let monitor = window.current_monitor().unwrap(); window.set_fullscreen(Some(Fullscreen::Borderless(monitor))); } } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 453815d8..db759ed5 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -391,10 +391,10 @@ impl Window { v } - pub fn current_monitor(&self) -> monitor::MonitorHandle { - monitor::MonitorHandle { + pub fn current_monitor(&self) -> Option { + Some(monitor::MonitorHandle { inner: MonitorHandle, - } + }) } pub fn scale_factor(&self) -> f64 { diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 5fa83e90..2be710e2 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -224,7 +224,7 @@ impl Inner { pub fn fullscreen(&self) -> Option { unsafe { - let monitor = self.current_monitor(); + let monitor = self.current_monitor_inner(); let uiscreen = monitor.inner.ui_screen(); let screen_space_bounds = self.screen_frame(); let screen_bounds: CGRect = msg_send![uiscreen, bounds]; @@ -258,7 +258,8 @@ impl Inner { warn!("`Window::set_ime_position` is ignored on iOS") } - pub fn current_monitor(&self) -> RootMonitorHandle { + // Allow directly accessing the current monitor internally without unwrapping. + fn current_monitor_inner(&self) -> RootMonitorHandle { unsafe { let uiscreen: id = msg_send![self.window, screen]; RootMonitorHandle { @@ -267,6 +268,10 @@ impl Inner { } } + pub fn current_monitor(&self) -> Option { + Some(self.current_monitor_inner()) + } + pub fn available_monitors(&self) -> VecDeque { unsafe { monitor::uiscreens() } } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 73b84777..c2214ace 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -425,9 +425,22 @@ impl Window { } #[inline] - pub fn current_monitor(&self) -> RootMonitorHandle { - RootMonitorHandle { - inner: x11_or_wayland!(match self; Window(window) => window.current_monitor(); as MonitorHandle), + pub fn current_monitor(&self) -> Option { + match self { + #[cfg(feature = "x11")] + &Window::X(ref window) => { + let current_monitor = MonitorHandle::X(window.current_monitor()); + Some(RootMonitorHandle { + inner: current_monitor, + }) + } + #[cfg(feature = "wayland")] + &Window::Wayland(ref window) => { + let current_monitor = MonitorHandle::Wayland(window.current_monitor()?); + Some(RootMonitorHandle { + inner: current_monitor, + }) + } } } diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index a0be1e9d..11c38466 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -334,8 +334,10 @@ impl Window { pub fn fullscreen(&self) -> Option { if *(self.fullscreen.lock().unwrap()) { + // If the monitor cannot be determined, we cannot report any fullscreen mode. + let current_monitor = self.current_monitor()?; Some(Fullscreen::Borderless(RootMonitorHandle { - inner: PlatformMonitorHandle::Wayland(self.current_monitor()), + inner: PlatformMonitorHandle::Wayland(current_monitor), })) } else { None @@ -396,12 +398,12 @@ impl Window { &self.surface } - pub fn current_monitor(&self) -> MonitorHandle { - let output = get_outputs(&self.surface).last().unwrap().clone(); - MonitorHandle { + pub fn current_monitor(&self) -> Option { + let output = get_outputs(&self.surface).last()?.clone(); + Some(MonitorHandle { proxy: output, mgr: self.outputs.clone(), - } + }) } pub fn available_monitors(&self) -> VecDeque { diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 175cf733..919fc2c7 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -972,7 +972,8 @@ impl UnownedWindow { } #[inline] - pub fn current_monitor(&self) -> RootMonitorHandle { + // Allow directly accessing the current monitor internally without unwrapping. + pub(crate) fn current_monitor_inner(&self) -> RootMonitorHandle { unsafe { let screen: id = msg_send![*self.ns_window, screen]; let desc = NSScreen::deviceDescription(screen); @@ -985,6 +986,11 @@ impl UnownedWindow { } } + #[inline] + pub fn current_monitor(&self) -> Option { + Some(self.current_monitor_inner()) + } + #[inline] pub fn available_monitors(&self) -> VecDeque { monitor::available_monitors() diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index 8c49e773..9d106e15 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -450,7 +450,8 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { // Otherwise, we must've reached fullscreen by the user clicking // on the green fullscreen button. Update state! None => { - shared_state.fullscreen = Some(Fullscreen::Borderless(window.current_monitor())) + let current_monitor = window.current_monitor_inner(); + shared_state.fullscreen = Some(Fullscreen::Borderless(current_monitor)) } } shared_state.in_fullscreen_transition = true; diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index bcf70116..5f2cae62 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -201,7 +201,7 @@ impl Window { #[inline] pub fn fullscreen(&self) -> Option { if self.canvas.is_fullscreen() { - Some(Fullscreen::Borderless(self.current_monitor())) + Some(Fullscreen::Borderless(self.current_monitor_inner())) } else { None } @@ -237,12 +237,18 @@ impl Window { } #[inline] - pub fn current_monitor(&self) -> RootMH { + // Allow directly accessing the current monitor internally without unwrapping. + fn current_monitor_inner(&self) -> RootMH { RootMH { inner: monitor::Handle, } } + #[inline] + pub fn current_monitor(&self) -> Option { + Some(self.current_monitor_inner()) + } + #[inline] pub fn available_monitors(&self) -> VecDequeIter { VecDeque::new().into_iter() diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 3b8dc98f..34406310 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -577,10 +577,10 @@ impl Window { } #[inline] - pub fn current_monitor(&self) -> RootMonitorHandle { - RootMonitorHandle { + pub fn current_monitor(&self) -> Option { + Some(RootMonitorHandle { inner: monitor::current_monitor(self.window.0), - } + }) } #[inline] diff --git a/src/window.rs b/src/window.rs index a00cd7c0..b8bec50b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -736,13 +736,15 @@ impl Window { /// Monitor info functions. impl Window { - /// Returns the monitor on which the window currently resides + /// Returns the monitor on which the window currently resides. + /// + /// Returns `None` if current monitor can't be detected. /// /// ## Platform-specific /// /// **iOS:** Can only be called on the main thread. #[inline] - pub fn current_monitor(&self) -> MonitorHandle { + pub fn current_monitor(&self) -> Option { self.window.current_monitor() }