Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macos fullscreen & dialog support with run_return #1581

Merged
merged 15 commits into from
Jun 9, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,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)

Expand Down
61 changes: 43 additions & 18 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand Down Expand Up @@ -223,6 +224,8 @@ impl Handler {
}
}

pub static INTERRUPT_EVENT_LOOP_EXIT: AtomicBool = AtomicBool::new(false);

pub enum AppState {}

impl AppState {
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 4 additions & 1 deletion src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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),
}
}

Expand Down
13 changes: 12 additions & 1 deletion src/platform_impl/macos/window_delegate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
f64,
os::raw::c_void,
sync::{Arc, Weak},
sync::{atomic::Ordering, Arc, Weak},
};

use cocoa::{
Expand All @@ -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,
Expand Down Expand Up @@ -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`");
Expand Down Expand Up @@ -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`");
Expand Down Expand Up @@ -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;
Expand All @@ -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| {
Expand Down