Fix freeze upon exiting exclusive fullscreen on macOS 10.15 (#1127)

This commit is contained in:
Aleksi Juvani 2019-09-16 02:59:37 +03:00 committed by Osspial
parent 57a53bda74
commit 28a5feef28
3 changed files with 53 additions and 47 deletions

View file

@ -9,6 +9,7 @@
- On macOS, differentiate between `CursorIcon::Grab` and `CursorIcon::Grabbing`.
- On Wayland, fix event processing sometimes stalling when using OpenGL with vsync.
- Officially remove the Emscripten backend
- On macOS 10.15, fix freeze upon exiting exclusive fullscreen mode.
# 0.20.0 Alpha 3 (2019-08-14)

View file

@ -231,6 +231,21 @@ pub unsafe fn toggle_full_screen_async(
);
}
extern "C" fn restore_display_mode_callback(screen: *mut c_void) {
unsafe {
let screen = Box::from_raw(screen as *mut u32);
ffi::CGRestorePermanentDisplayConfiguration();
assert_eq!(ffi::CGDisplayRelease(*screen), ffi::kCGErrorSuccess);
}
}
pub unsafe fn restore_display_mode_async(ns_screen: u32) {
dispatch_async_f(
dispatch_get_main_queue(),
Box::into_raw(Box::new(ns_screen)) as *mut _,
restore_display_mode_callback,
);
}
struct SetMaximizedData {
ns_window: id,
is_zoomed: bool,

View file

@ -617,25 +617,6 @@ impl UnownedWindow {
self.set_maximized(maximized);
}
fn restore_display_mode(&self) {
trace!("Locked shared state in `restore_display_mode`");
let shared_state_lock = self.shared_state.lock().unwrap();
if let Some(Fullscreen::Exclusive(RootVideoMode { ref video_mode })) =
shared_state_lock.fullscreen
{
unsafe {
ffi::CGRestorePermanentDisplayConfiguration();
assert_eq!(
ffi::CGDisplayRelease(video_mode.monitor().inner.native_identifier()),
ffi::kCGErrorSuccess
);
}
}
trace!("Unlocked shared state in `restore_display_mode`");
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
let is_zoomed = self.is_zoomed();
@ -763,7 +744,39 @@ impl UnownedWindow {
}
}
trace!("Locked shared state in `set_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.fullscreen = fullscreen.clone();
trace!("Unlocked shared state in `set_fullscreen`");
match (&old_fullscreen, &fullscreen) {
(&None, &Some(_)) => unsafe {
util::toggle_full_screen_async(
*self.ns_window,
*self.ns_view,
old_fullscreen.is_none(),
Arc::downgrade(&self.shared_state),
);
},
(&Some(Fullscreen::Borderless(_)), &None) => unsafe {
// State is restored by `window_did_exit_fullscreen`
util::toggle_full_screen_async(
*self.ns_window,
*self.ns_view,
old_fullscreen.is_none(),
Arc::downgrade(&self.shared_state),
);
},
(&Some(Fullscreen::Exclusive(RootVideoMode { ref video_mode })), &None) => unsafe {
util::restore_display_mode_async(video_mode.monitor().inner.native_identifier());
// Rest of the state is restored by `window_did_exit_fullscreen`
util::toggle_full_screen_async(
*self.ns_window,
*self.ns_view,
old_fullscreen.is_none(),
Arc::downgrade(&self.shared_state),
);
},
(&Some(Fullscreen::Borderless(_)), &Some(Fullscreen::Exclusive(_))) => unsafe {
// If we're already in fullscreen mode, calling
// `CGDisplayCapture` will place the shielding window on top of
@ -775,37 +788,14 @@ impl UnownedWindow {
// delegate in `window:willUseFullScreenPresentationOptions:`.
msg_send![*self.ns_window, setLevel: ffi::CGShieldingWindowLevel() + 1];
},
(&Some(Fullscreen::Exclusive(_)), &None) => unsafe {
self.restore_display_mode();
util::toggle_full_screen_async(
*self.ns_window,
*self.ns_view,
old_fullscreen.is_none(),
Arc::downgrade(&self.shared_state),
);
},
(&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
self.restore_display_mode();
}
(&None, &Some(Fullscreen::Exclusive(_)))
| (&None, &Some(Fullscreen::Borderless(_)))
| (&Some(Fullscreen::Borderless(_)), &None) => unsafe {
// Wish it were this simple for all cases
util::toggle_full_screen_async(
*self.ns_window,
*self.ns_view,
old_fullscreen.is_none(),
Arc::downgrade(&self.shared_state),
);
(
&Some(Fullscreen::Exclusive(RootVideoMode { ref video_mode })),
&Some(Fullscreen::Borderless(_)),
) => unsafe {
util::restore_display_mode_async(video_mode.monitor().inner.native_identifier());
},
_ => (),
}
trace!("Locked shared state in `set_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.fullscreen = fullscreen.clone();
trace!("Unlocked shared state in `set_fullscreen`");
}
#[inline]