macOS: Don't change fullscreen state during fullscreen transition (#1331)

* Register windowWillExitFullScreen

* On macOS: Do not toggle fullscreen during fullscreen transition

* Add CHANGELOG

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
This commit is contained in:
hatoo 2019-12-25 03:56:56 +09:00 committed by Freya Gentz
parent d59eec4633
commit 5d99316c96
3 changed files with 62 additions and 2 deletions

View file

@ -1,5 +1,6 @@
# Unreleased # Unreleased
- On macOS, fix error when `set_fullscreen` is called during fullscreen transition.
- On all platforms except mobile and WASM, implement `Window::set_minimized`. - On all platforms except mobile and WASM, implement `Window::set_minimized`.
- On X11, fix `CursorEntered` event being generated for non-winit windows. - On X11, fix `CursorEntered` event being generated for non-winit windows.
- On macOS, fix crash when starting maximized without decorations. - On macOS, fix crash when starting maximized without decorations.

View file

@ -243,6 +243,13 @@ lazy_static! {
pub struct SharedState { pub struct SharedState {
pub resizable: bool, pub resizable: bool,
pub fullscreen: Option<Fullscreen>, pub fullscreen: Option<Fullscreen>,
// This is true between windowWillEnterFullScreen and windowDidEnterFullScreen
// or windowWillExitFullScreen and windowDidExitFullScreen.
// We must not toggle fullscreen when this is true.
pub in_fullscreen_transition: bool,
// If it is attempted to toggle fullscreen when in_fullscreen_transition is true,
// Set target_fullscreen and do after fullscreen transition is end.
pub target_fullscreen: Option<Option<Fullscreen>>,
pub maximized: bool, pub maximized: bool,
pub standard_frame: Option<NSRect>, pub standard_frame: Option<NSRect>,
is_simple_fullscreen: bool, is_simple_fullscreen: bool,
@ -661,11 +668,18 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) { pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
trace!("Locked shared state in `set_fullscreen`"); trace!("Locked shared state in `set_fullscreen`");
let shared_state_lock = self.shared_state.lock().unwrap(); let mut shared_state_lock = self.shared_state.lock().unwrap();
if shared_state_lock.is_simple_fullscreen { if shared_state_lock.is_simple_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`"); trace!("Unlocked shared state in `set_fullscreen`");
return; return;
} }
if shared_state_lock.in_fullscreen_transition {
// We can't set fullscreen here.
// Set fullscreen after transition.
shared_state_lock.target_fullscreen = Some(fullscreen);
trace!("Unlocked shared state in `set_fullscreen`");
return;
}
let old_fullscreen = shared_state_lock.fullscreen.clone(); let old_fullscreen = shared_state_lock.fullscreen.clone();
if fullscreen == old_fullscreen { if fullscreen == old_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`"); trace!("Unlocked shared state in `set_fullscreen`");

View file

@ -195,6 +195,10 @@ lazy_static! {
sel!(windowDidExitFullScreen:), sel!(windowDidExitFullScreen:),
window_did_exit_fullscreen as extern "C" fn(&Object, Sel, id), window_did_exit_fullscreen as extern "C" fn(&Object, Sel, id),
); );
decl.add_method(
sel!(windowWillExitFullScreen:),
window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method( decl.add_method(
sel!(windowDidFailToEnterFullScreen:), sel!(windowDidFailToEnterFullScreen:),
window_did_fail_to_enter_fullscreen as extern "C" fn(&Object, Sel, id), window_did_fail_to_enter_fullscreen as extern "C" fn(&Object, Sel, id),
@ -419,13 +423,27 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
shared_state.fullscreen = Some(Fullscreen::Borderless(window.current_monitor())) shared_state.fullscreen = Some(Fullscreen::Borderless(window.current_monitor()))
} }
} }
shared_state.in_fullscreen_transition = true;
trace!("Unlocked shared state in `window_will_enter_fullscreen`"); trace!("Unlocked shared state in `window_will_enter_fullscreen`");
}) })
}); });
trace!("Completed `windowWillEnterFullscreen:`"); trace!("Completed `windowWillEnterFullscreen:`");
} }
/// Invoked when before exit fullscreen
extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillExitFullScreen:`");
with_state(this, |state| {
state.with_window(|window| {
trace!("Locked shared state in `window_will_exit_fullscreen`");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = true;
trace!("Unlocked shared state in `window_will_exit_fullscreen`");
});
});
trace!("Completed `windowWillExitFullScreen:`");
}
extern "C" fn window_will_use_fullscreen_presentation_options( extern "C" fn window_will_use_fullscreen_presentation_options(
_this: &Object, _this: &Object,
_: Sel, _: Sel,
@ -451,6 +469,17 @@ extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidEnterFullscreen:`"); trace!("Triggered `windowDidEnterFullscreen:`");
with_state(this, |state| { with_state(this, |state| {
state.initial_fullscreen = false; state.initial_fullscreen = false;
state.with_window(|window| {
trace!("Locked shared state in `window_did_enter_fullscreen`");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take();
trace!("Unlocked shared state in `window_did_enter_fullscreen`");
drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen {
window.set_fullscreen(target_fullscreen);
}
});
}); });
trace!("Completed `windowDidEnterFullscreen:`"); trace!("Completed `windowDidEnterFullscreen:`");
} }
@ -461,6 +490,15 @@ extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
window.restore_state_from_fullscreen(); window.restore_state_from_fullscreen();
trace!("Locked shared state in `window_did_exit_fullscreen`");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take();
trace!("Unlocked shared state in `window_did_exit_fullscreen`");
drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen {
window.set_fullscreen(target_fullscreen);
}
}) })
}); });
trace!("Completed `windowDidExitFullscreen:`"); trace!("Completed `windowDidExitFullscreen:`");
@ -485,6 +523,13 @@ extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) { extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidFailToEnterFullscreen:`"); trace!("Triggered `windowDidFailToEnterFullscreen:`");
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| {
trace!("Locked shared state in `window_did_fail_to_enter_fullscreen`");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false;
shared_state.target_fullscreen = None;
trace!("Unlocked shared state in `window_did_fail_to_enter_fullscreen`");
});
if state.initial_fullscreen { if state.initial_fullscreen {
let _: () = unsafe { let _: () = unsafe {
msg_send![*state.ns_window, msg_send![*state.ns_window,