Macos fullscreen & dialog support with run_return (#1581)

* Fix for fullscreen with run_return on mac

* Cleanup

* Removed a comment

* fmt

* This doesn't break exiting run_return anymore

* Now you can also transition from code

* Fmt & cleanup

* Now using a atomic instead of a static bool

* reinserted a line

* Fmt

* Added support for dialogs and child windows

* Cargo fmt

* Dialogs are now being shutdown properly

* Cargo fmt

* Update CHANGELOG.md
This commit is contained in:
Viktor Zoutman 2020-06-09 23:46:33 +02:00 committed by GitHub
parent a4121a2c2e
commit 5a6cfc314e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 20 deletions

View file

@ -4,6 +4,7 @@
- On Wayland, fix deadlock when calling to `set_inner_size` from a callback.
- On macOS, add `hide__other_applications` to `EventLoopWindowTarget` via existing `EventLoopWindowTargetExtMacOS` trait. `hide_other_applications` will hide other applications by calling `-[NSApplication hideOtherApplications: nil]`.
- On MacOS, Fixed fullscreen and dialog support for `run_return`.
# 0.22.2 (2020-05-16)

View file

@ -92,6 +92,7 @@ impl<T> EventHandler for EventLoopHandler<T> {
struct Handler {
ready: AtomicBool,
in_callback: AtomicBool,
dialog_is_closing: AtomicBool,
control_flow: Mutex<ControlFlow>,
control_flow_prev: Mutex<ControlFlow>,
start_time: Mutex<Option<Instant>>,
@ -223,6 +224,8 @@ impl Handler {
}
}
pub static INTERRUPT_EVENT_LOOP_EXIT: AtomicBool = AtomicBool::new(false);
pub enum AppState {}
impl AppState {
@ -336,29 +339,51 @@ impl AppState {
}
if HANDLER.should_exit() {
unsafe {
let _: () = msg_send![NSApp(), stop: nil];
let pool = NSAutoreleasePool::new(nil);
let windows: id = msg_send![NSApp(), windows];
let app: id = NSApp();
let windows: id = msg_send![app, windows];
let window: id = msg_send![windows, objectAtIndex:0];
let window_count: usize = msg_send![windows, count];
assert_ne!(window, nil);
let dummy_event: id = msg_send![class!(NSEvent),
otherEventWithType: NSApplicationDefined
location: NSPoint::new(0.0, 0.0)
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: 0
data1: 0
data2: 0
];
// To stop event loop immediately, we need to post some event here.
let _: () = msg_send![window, postEvent: dummy_event atStart: YES];
let dialog_open = if window_count > 1 {
let dialog: id = msg_send![windows, lastObject];
let is_main_window: bool = msg_send![dialog, isMainWindow];
msg_send![dialog, isVisible] && !is_main_window
} else {
false
};
let dialog_is_closing = HANDLER.dialog_is_closing.load(Ordering::SeqCst);
let pool = NSAutoreleasePool::new(nil);
if !INTERRUPT_EVENT_LOOP_EXIT.load(Ordering::SeqCst)
&& !dialog_open
&& !dialog_is_closing
{
let _: () = msg_send![app, stop: nil];
let dummy_event: id = msg_send![class!(NSEvent),
otherEventWithType: NSApplicationDefined
location: NSPoint::new(0.0, 0.0)
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: 0
data1: 0
data2: 0
];
// To stop event loop immediately, we need to post some event here.
let _: () = msg_send![window, postEvent: dummy_event atStart: YES];
}
pool.drain();
let window_has_focus = msg_send![window, isKeyWindow];
if !dialog_open && window_has_focus && dialog_is_closing {
HANDLER.dialog_is_closing.store(false, Ordering::SeqCst);
}
if dialog_open {
HANDLER.dialog_is_closing.store(true, Ordering::SeqCst);
}
};
}
HANDLER.update_start_time();

View file

@ -19,6 +19,7 @@ use crate::{
platform::macos::{ActivationPolicy, RequestUserAttentionType, WindowExtMacOS},
platform_impl::platform::{
app_state::AppState,
app_state::INTERRUPT_EVENT_LOOP_EXIT,
ffi,
monitor::{self, MonitorHandle, VideoMode},
util::{self, IdRef},
@ -820,6 +821,8 @@ impl UnownedWindow {
shared_state_lock.fullscreen = fullscreen.clone();
trace!("Unlocked shared state in `set_fullscreen`");
INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
match (&old_fullscreen, &fullscreen) {
(&None, &Some(_)) => unsafe {
util::toggle_full_screen_async(
@ -865,7 +868,7 @@ impl UnownedWindow {
) => unsafe {
util::restore_display_mode_async(video_mode.monitor().inner.native_identifier());
},
_ => (),
_ => INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst),
}
}

View file

@ -1,7 +1,7 @@
use std::{
f64,
os::raw::c_void,
sync::{Arc, Weak},
sync::{atomic::Ordering, Arc, Weak},
};
use cocoa::{
@ -19,6 +19,7 @@ use crate::{
event::{Event, ModifiersState, WindowEvent},
platform_impl::platform::{
app_state::AppState,
app_state::INTERRUPT_EVENT_LOOP_EXIT,
event::{EventProxy, EventWrapper},
util::{self, IdRef},
view::ViewState,
@ -429,6 +430,9 @@ extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) {
/// Invoked when before enter fullscreen
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillEnterFullscreen:`");
INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
with_state(this, |state| {
state.with_window(|window| {
trace!("Locked shared state in `window_will_enter_fullscreen`");
@ -459,6 +463,9 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
/// Invoked when before exit fullscreen
extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillExitFullScreen:`");
INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
with_state(this, |state| {
state.with_window(|window| {
trace!("Locked shared state in `window_will_exit_fullscreen`");
@ -492,6 +499,8 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
/// Invoked when entered fullscreen
extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidEnterFullscreen:`");
with_state(this, |state| {
state.initial_fullscreen = false;
@ -512,6 +521,8 @@ extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
/// Invoked when exited fullscreen
extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidExitFullscreen:`");
with_state(this, |state| {
state.with_window(|window| {