Make 'current_monitor' return 'Option<MonitorHandle>'

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<MonitorHandle>' will give an ability to
handle such situations gracefully by properly indicating that
there's no current monitor.

Fixes #793.
This commit is contained in:
Kirill Chibisov 2020-09-07 20:09:24 +03:00 committed by GitHub
parent e2cf2a5754
commit cac627ed05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 65 additions and 29 deletions

View file

@ -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<MonitorHandle>`.
# 0.22.2 (2020-05-16)

View file

@ -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(),

View file

@ -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)));
}
}

View file

@ -391,10 +391,10 @@ impl Window {
v
}
pub fn current_monitor(&self) -> monitor::MonitorHandle {
monitor::MonitorHandle {
pub fn current_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
}
})
}
pub fn scale_factor(&self) -> f64 {

View file

@ -224,7 +224,7 @@ impl Inner {
pub fn fullscreen(&self) -> Option<Fullscreen> {
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<RootMonitorHandle> {
Some(self.current_monitor_inner())
}
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
unsafe { monitor::uiscreens() }
}

View file

@ -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<RootMonitorHandle> {
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,
})
}
}
}

View file

@ -334,8 +334,10 @@ impl Window {
pub fn fullscreen(&self) -> Option<Fullscreen> {
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<MonitorHandle> {
let output = get_outputs(&self.surface).last()?.clone();
Some(MonitorHandle {
proxy: output,
mgr: self.outputs.clone(),
}
})
}
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {

View file

@ -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<RootMonitorHandle> {
Some(self.current_monitor_inner())
}
#[inline]
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
monitor::available_monitors()

View file

@ -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;

View file

@ -201,7 +201,7 @@ impl Window {
#[inline]
pub fn fullscreen(&self) -> Option<Fullscreen> {
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<RootMH> {
Some(self.current_monitor_inner())
}
#[inline]
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
VecDeque::new().into_iter()

View file

@ -577,10 +577,10 @@ impl Window {
}
#[inline]
pub fn current_monitor(&self) -> RootMonitorHandle {
RootMonitorHandle {
pub fn current_monitor(&self) -> Option<RootMonitorHandle> {
Some(RootMonitorHandle {
inner: monitor::current_monitor(self.window.0),
}
})
}
#[inline]

View file

@ -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<MonitorHandle> {
self.window.current_monitor()
}