macOS: Remove unnecessary Mutex in window state (#3390)

This commit is contained in:
Mads Marquart 2024-01-14 04:44:10 +01:00 committed by GitHub
parent 40b61d2d92
commit c86b0daf7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 232 deletions

View file

@ -1,9 +1,8 @@
#![allow(clippy::unnecessary_cast)] #![allow(clippy::unnecessary_cast)]
use std::cell::{Cell, RefCell};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::f64; use std::f64;
use std::ops;
use std::sync::{Mutex, MutexGuard};
use core_graphics::display::{CGDisplay, CGPoint}; use core_graphics::display::{CGDisplay, CGPoint};
use icrate::AppKit::{ use icrate::AppKit::{
@ -23,7 +22,6 @@ use icrate::Foundation::{
CGFloat, MainThreadBound, MainThreadMarker, NSArray, NSCopying, NSObject, NSPoint, NSRect, CGFloat, MainThreadBound, MainThreadMarker, NSArray, NSCopying, NSObject, NSPoint, NSRect,
NSSize, NSString, NSSize, NSString,
}; };
use log::trace;
use objc2::rc::{autoreleasepool, Id}; use objc2::rc::{autoreleasepool, Id};
use objc2::{declare_class, msg_send, msg_send_id, mutability, sel, ClassType, DeclaredClass}; use objc2::{declare_class, msg_send, msg_send_id, mutability, sel, ClassType, DeclaredClass};
@ -185,7 +183,7 @@ declare_class!(
} }
impl DeclaredClass for WinitWindow { impl DeclaredClass for WinitWindow {
type Ivars = Mutex<SharedState>; type Ivars = State;
} }
unsafe impl WinitWindow { unsafe impl WinitWindow {
@ -204,81 +202,36 @@ declare_class!(
); );
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SharedState { pub struct State {
pub resizable: bool, resizable: Cell<bool>,
/// This field tracks the current fullscreen state of the window /// This field tracks the current fullscreen state of the window
/// (as seen by `WindowDelegate`). /// (as seen by `WindowDelegate`).
pub(crate) fullscreen: Option<Fullscreen>, pub(super) fullscreen: RefCell<Option<Fullscreen>>,
// This is true between windowWillEnterFullScreen and windowDidEnterFullScreen // This is true between windowWillEnterFullScreen and windowDidEnterFullScreen
// or windowWillExitFullScreen and windowDidExitFullScreen. // or windowWillExitFullScreen and windowDidExitFullScreen.
// We must not toggle fullscreen when this is true. // We must not toggle fullscreen when this is true.
pub in_fullscreen_transition: bool, pub(super) in_fullscreen_transition: Cell<bool>,
// If it is attempted to toggle fullscreen when in_fullscreen_transition is true, // If it is attempted to toggle fullscreen when in_fullscreen_transition is true,
// Set target_fullscreen and do after fullscreen transition is end. // Set target_fullscreen and do after fullscreen transition is end.
pub(crate) target_fullscreen: Option<Option<Fullscreen>>, pub(crate) target_fullscreen: RefCell<Option<Option<Fullscreen>>>,
pub maximized: bool, pub(super) maximized: Cell<bool>,
pub standard_frame: Option<NSRect>, standard_frame: Cell<Option<NSRect>>,
pub(crate) is_simple_fullscreen: bool, pub(crate) is_simple_fullscreen: Cell<bool>,
pub saved_style: Option<NSWindowStyleMask>, pub(super) saved_style: Cell<Option<NSWindowStyleMask>>,
/// Presentation options saved before entering `set_simple_fullscreen`, and /// Presentation options saved before entering `set_simple_fullscreen`, and
/// restored upon exiting it. Also used when transitioning from Borderless to /// restored upon exiting it. Also used when transitioning from Borderless to
/// Exclusive fullscreen in `set_fullscreen` because we need to disable the menu /// Exclusive fullscreen in `set_fullscreen` because we need to disable the menu
/// bar in exclusive fullscreen but want to restore the original options when /// bar in exclusive fullscreen but want to restore the original options when
/// transitioning back to borderless fullscreen. /// transitioning back to borderless fullscreen.
save_presentation_opts: Option<NSApplicationPresentationOptions>, save_presentation_opts: Cell<Option<NSApplicationPresentationOptions>>,
pub current_theme: Option<Theme>, pub(super) current_theme: Cell<Option<Theme>>,
/// The current resize incerments for the window content. /// The current resize increments for the window content.
pub(crate) resize_increments: NSSize, pub(crate) resize_increments: Cell<NSSize>,
/// The state of the `Option` as `Alt`. /// The state of the `Option` as `Alt`.
pub(crate) option_as_alt: OptionAsAlt, option_as_alt: Cell<OptionAsAlt>,
/// Whether the window is showing decorations.
decorations: bool, decorations: Cell<bool>,
}
impl SharedState {
pub fn saved_standard_frame(&self) -> NSRect {
self.standard_frame
.unwrap_or_else(|| NSRect::new(NSPoint::new(50.0, 50.0), NSSize::new(800.0, 600.0)))
}
}
pub(crate) struct SharedStateMutexGuard<'a> {
guard: MutexGuard<'a, SharedState>,
called_from_fn: &'static str,
}
impl<'a> SharedStateMutexGuard<'a> {
#[inline]
fn new(guard: MutexGuard<'a, SharedState>, called_from_fn: &'static str) -> Self {
trace!("Locked shared state in `{}`", called_from_fn);
Self {
guard,
called_from_fn,
}
}
}
impl ops::Deref for SharedStateMutexGuard<'_> {
type Target = SharedState;
#[inline]
fn deref(&self) -> &Self::Target {
self.guard.deref()
}
}
impl ops::DerefMut for SharedStateMutexGuard<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.guard.deref_mut()
}
}
impl Drop for SharedStateMutexGuard<'_> {
#[inline]
fn drop(&mut self) {
trace!("Unlocked shared state in `{}`", self.called_from_fn);
}
} }
impl WinitWindow { impl WinitWindow {
@ -360,14 +313,12 @@ impl WinitWindow {
masks |= NSWindowStyleMaskFullSizeContentView; masks |= NSWindowStyleMaskFullSizeContentView;
} }
let state = SharedState { let this = mtm.alloc().set_ivars(State {
resizable: attrs.resizable, resizable: Cell::new(attrs.resizable),
maximized: attrs.maximized, maximized: Cell::new(attrs.maximized),
decorations: attrs.decorations, decorations: Cell::new(attrs.decorations),
..Default::default() ..Default::default()
}; });
let this = mtm.alloc().set_ivars(Mutex::new(state));
let this: Option<Id<Self>> = unsafe { let this: Option<Id<Self>> = unsafe {
msg_send_id![ msg_send_id![
super(this), super(this),
@ -394,7 +345,7 @@ impl WinitWindow {
_ => NSSize::new(1., 1.), _ => NSSize::new(1., 1.),
}; };
this.lock_shared_state("init").resize_increments = resize_increments; this.ivars().resize_increments.set(resize_increments);
this.setTitle(&NSString::from_str(&attrs.title)); this.setTitle(&NSString::from_str(&attrs.title));
this.setAcceptsMouseMovedEvents(true); this.setAcceptsMouseMovedEvents(true);
@ -517,13 +468,10 @@ impl WinitWindow {
match attrs.preferred_theme { match attrs.preferred_theme {
Some(theme) => { Some(theme) => {
set_ns_theme(Some(theme), mtm); this.ivars().current_theme.set(Some(theme));
let mut state = this.lock_shared_state("WinitWindow::new");
state.current_theme = Some(theme);
} }
None => { None => {
let mut state = this.lock_shared_state("WinitWindow::new"); this.ivars().current_theme.set(Some(get_ns_theme(mtm)));
state.current_theme = Some(get_ns_theme(mtm));
} }
} }
@ -563,14 +511,6 @@ impl WinitWindow {
unsafe { Id::cast(self.contentView().unwrap()) } unsafe { Id::cast(self.contentView().unwrap()) }
} }
#[track_caller]
pub(crate) fn lock_shared_state(
&self,
called_from_fn: &'static str,
) -> SharedStateMutexGuard<'_> {
SharedStateMutexGuard::new(self.ivars().lock().unwrap(), called_from_fn)
}
fn set_style_mask(&self, mask: NSWindowStyleMask) { fn set_style_mask(&self, mask: NSWindowStyleMask) {
self.setStyleMask(mask); self.setStyleMask(mask);
// If we don't do this, key handling will break // If we don't do this, key handling will break
@ -708,9 +648,7 @@ impl WinitWindow {
} }
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> { pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
let increments = self let increments = self.ivars().resize_increments.get();
.lock_shared_state("set_resize_increments")
.resize_increments;
let (w, h) = (increments.width, increments.height); let (w, h) = (increments.width, increments.height);
if w > 1.0 || h > 1.0 { if w > 1.0 || h > 1.0 {
Some(LogicalSize::new(w, h).to_physical(self.scale_factor())) Some(LogicalSize::new(w, h).to_physical(self.scale_factor()))
@ -721,13 +659,14 @@ impl WinitWindow {
pub fn set_resize_increments(&self, increments: Option<Size>) { pub fn set_resize_increments(&self, increments: Option<Size>) {
// XXX the resize increments are only used during live resizes. // XXX the resize increments are only used during live resizes.
let mut shared_state_lock = self.lock_shared_state("set_resize_increments"); self.ivars().resize_increments.set(
shared_state_lock.resize_increments = increments increments
.map(|increments| { .map(|increments| {
let logical = increments.to_logical::<f64>(self.scale_factor()); let logical = increments.to_logical::<f64>(self.scale_factor());
NSSize::new(logical.width.max(1.0), logical.height.max(1.0)) NSSize::new(logical.width.max(1.0), logical.height.max(1.0))
}) })
.unwrap_or_else(|| NSSize::new(1.0, 1.0)); .unwrap_or_else(|| NSSize::new(1.0, 1.0)),
);
} }
pub(crate) fn set_resize_increments_inner(&self, size: NSSize) { pub(crate) fn set_resize_increments_inner(&self, size: NSSize) {
@ -740,11 +679,8 @@ impl WinitWindow {
#[inline] #[inline]
pub fn set_resizable(&self, resizable: bool) { pub fn set_resizable(&self, resizable: bool) {
let fullscreen = { self.ivars().resizable.set(resizable);
let mut shared_state_lock = self.lock_shared_state("set_resizable"); let fullscreen = self.ivars().fullscreen.borrow().is_some();
shared_state_lock.resizable = resizable;
shared_state_lock.fullscreen.is_some()
};
if !fullscreen { if !fullscreen {
let mut mask = self.styleMask(); let mut mask = self.styleMask();
if resizable { if resizable {
@ -917,12 +853,13 @@ impl WinitWindow {
is_zoomed is_zoomed
} }
fn saved_style(&self, shared_state: &mut SharedState) -> NSWindowStyleMask { fn saved_style(&self) -> NSWindowStyleMask {
let base_mask = shared_state let base_mask = self
.ivars()
.saved_style .saved_style
.take() .take()
.unwrap_or_else(|| self.styleMask()); .unwrap_or_else(|| self.styleMask());
if shared_state.resizable { if self.ivars().resizable.get() {
base_mask | NSWindowStyleMaskResizable base_mask | NSWindowStyleMaskResizable
} else { } else {
base_mask & !NSWindowStyleMaskResizable base_mask & !NSWindowStyleMaskResizable
@ -933,14 +870,10 @@ impl WinitWindow {
/// user clicking on the green fullscreen button or programmatically by /// user clicking on the green fullscreen button or programmatically by
/// `toggleFullScreen:` /// `toggleFullScreen:`
pub(crate) fn restore_state_from_fullscreen(&self) { pub(crate) fn restore_state_from_fullscreen(&self) {
let mut shared_state_lock = self.lock_shared_state("restore_state_from_fullscreen"); self.ivars().fullscreen.replace(None);
shared_state_lock.fullscreen = None; let maximized = self.ivars().maximized.get();
let mask = self.saved_style();
let maximized = shared_state_lock.maximized;
let mask = self.saved_style(&mut shared_state_lock);
drop(shared_state_lock);
self.set_style_mask(mask); self.set_style_mask(mask);
self.set_maximized(maximized); self.set_maximized(maximized);
@ -973,21 +906,19 @@ impl WinitWindow {
return; return;
}; };
let mut shared_state = self.lock_shared_state("set_maximized");
// Save the standard frame sized if it is not zoomed // Save the standard frame sized if it is not zoomed
if !is_zoomed { if !is_zoomed {
shared_state.standard_frame = Some(self.frame()); self.ivars().standard_frame.set(Some(self.frame()));
} }
shared_state.maximized = maximized; self.ivars().maximized.set(maximized);
if shared_state.fullscreen.is_some() { if self.ivars().fullscreen.borrow().is_some() {
// Handle it in window_did_exit_fullscreen // Handle it in window_did_exit_fullscreen
return; return;
} }
if mask_contains(self.styleMask(), NSWindowStyleMaskResizable) { if mask_contains(self.styleMask(), NSWindowStyleMaskResizable) {
drop(shared_state);
// Just use the native zoom if resizable // Just use the native zoom if resizable
self.zoom(None); self.zoom(None);
} else { } else {
@ -996,17 +927,18 @@ impl WinitWindow {
let screen = NSScreen::mainScreen(mtm).expect("no screen found"); let screen = NSScreen::mainScreen(mtm).expect("no screen found");
screen.visibleFrame() screen.visibleFrame()
} else { } else {
shared_state.saved_standard_frame() self.ivars()
.standard_frame
.get()
.unwrap_or(DEFAULT_STANDARD_FRAME)
}; };
drop(shared_state);
self.setFrame_display(new_rect, false); self.setFrame_display(new_rect, false);
} }
} }
#[inline] #[inline]
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> { pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
let shared_state_lock = self.lock_shared_state("fullscreen"); self.ivars().fullscreen.borrow().clone()
shared_state_lock.fullscreen.clone()
} }
#[inline] #[inline]
@ -1019,21 +951,19 @@ impl WinitWindow {
let mtm = MainThreadMarker::from(self); let mtm = MainThreadMarker::from(self);
let app = NSApplication::sharedApplication(mtm); let app = NSApplication::sharedApplication(mtm);
let mut shared_state_lock = self.lock_shared_state("set_fullscreen"); if self.ivars().is_simple_fullscreen.get() {
if shared_state_lock.is_simple_fullscreen {
return; return;
} }
if shared_state_lock.in_fullscreen_transition { if self.ivars().in_fullscreen_transition.get() {
// We can't set fullscreen here. // We can't set fullscreen here.
// Set fullscreen after transition. // Set fullscreen after transition.
shared_state_lock.target_fullscreen = Some(fullscreen); self.ivars().target_fullscreen.replace(Some(fullscreen));
return; return;
} }
let old_fullscreen = shared_state_lock.fullscreen.clone(); let old_fullscreen = self.ivars().fullscreen.borrow().clone();
if fullscreen == old_fullscreen { if fullscreen == old_fullscreen {
return; return;
} }
drop(shared_state_lock);
// If the fullscreen is on a different monitor, we must move the window // If the fullscreen is on a different monitor, we must move the window
// to that monitor before we toggle fullscreen (as `toggleFullScreen` // to that monitor before we toggle fullscreen (as `toggleFullScreen`
@ -1077,8 +1007,9 @@ impl WinitWindow {
let mut fade_token = ffi::kCGDisplayFadeReservationInvalidToken; let mut fade_token = ffi::kCGDisplayFadeReservationInvalidToken;
if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) { if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) {
let mut shared_state_lock = self.lock_shared_state("set_fullscreen"); self.ivars()
shared_state_lock.save_presentation_opts = Some(app.presentationOptions()); .save_presentation_opts
.replace(Some(app.presentationOptions()));
} }
unsafe { unsafe {
@ -1128,7 +1059,7 @@ impl WinitWindow {
} }
} }
self.lock_shared_state("set_fullscreen").fullscreen = fullscreen.clone(); self.ivars().fullscreen.replace(fullscreen.clone());
fn toggle_fullscreen(window: &WinitWindow) { fn toggle_fullscreen(window: &WinitWindow) {
// Window level must be restored from `CGShieldingWindowLevel() // Window level must be restored from `CGShieldingWindowLevel()
@ -1147,7 +1078,7 @@ impl WinitWindow {
let required = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable; let required = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable;
if !mask_contains(curr_mask, required) { if !mask_contains(curr_mask, required) {
self.set_style_mask(required); self.set_style_mask(required);
self.lock_shared_state("set_fullscreen").saved_style = Some(curr_mask); self.ivars().saved_style.set(Some(curr_mask));
} }
toggle_fullscreen(self); toggle_fullscreen(self);
} }
@ -1174,8 +1105,9 @@ impl WinitWindow {
// of the menu bar, and this looks broken, so we must make sure // of the menu bar, and this looks broken, so we must make sure
// that the menu bar is disabled. This is done in the window // that the menu bar is disabled. This is done in the window
// delegate in `window:willUseFullScreenPresentationOptions:`. // delegate in `window:willUseFullScreenPresentationOptions:`.
self.lock_shared_state("set_fullscreen") self.ivars()
.save_presentation_opts = Some(app.presentationOptions()); .save_presentation_opts
.set(Some(app.presentationOptions()));
let presentation_options = NSApplicationPresentationFullScreen let presentation_options = NSApplicationPresentationFullScreen
| NSApplicationPresentationHideDock | NSApplicationPresentationHideDock
@ -1186,14 +1118,11 @@ impl WinitWindow {
self.setLevel(window_level); self.setLevel(window_level);
} }
(Some(Fullscreen::Exclusive(ref video_mode)), Some(Fullscreen::Borderless(_))) => { (Some(Fullscreen::Exclusive(ref video_mode)), Some(Fullscreen::Borderless(_))) => {
let presentation_options = self let presentation_options = self.ivars().save_presentation_opts.get().unwrap_or(
.lock_shared_state("set_fullscreen") NSApplicationPresentationFullScreen
.save_presentation_opts | NSApplicationPresentationAutoHideDock
.unwrap_or( | NSApplicationPresentationAutoHideMenuBar,
NSApplicationPresentationFullScreen );
| NSApplicationPresentationAutoHideDock
| NSApplicationPresentationAutoHideMenuBar,
);
app.setPresentationOptions(presentation_options); app.setPresentationOptions(presentation_options);
unsafe { unsafe {
@ -1214,17 +1143,14 @@ impl WinitWindow {
#[inline] #[inline]
pub fn set_decorations(&self, decorations: bool) { pub fn set_decorations(&self, decorations: bool) {
let mut shared_state_lock = self.lock_shared_state("set_decorations"); if decorations == self.ivars().decorations.get() {
if decorations == shared_state_lock.decorations {
return; return;
} }
shared_state_lock.decorations = decorations; self.ivars().decorations.set(decorations);
let fullscreen = shared_state_lock.fullscreen.is_some(); let fullscreen = self.ivars().fullscreen.borrow().is_some();
let resizable = shared_state_lock.resizable; let resizable = self.ivars().resizable.get();
drop(shared_state_lock);
// If we're in fullscreen mode, we wait to apply decoration changes // If we're in fullscreen mode, we wait to apply decoration changes
// until we're in `window_did_exit_fullscreen`. // until we're in `window_did_exit_fullscreen`.
@ -1251,7 +1177,7 @@ impl WinitWindow {
#[inline] #[inline]
pub fn is_decorated(&self) -> bool { pub fn is_decorated(&self) -> bool {
self.lock_shared_state("is_decorated").decorations self.ivars().decorations.get()
} }
#[inline] #[inline]
@ -1389,7 +1315,7 @@ impl WinitWindow {
#[inline] #[inline]
pub fn theme(&self) -> Option<Theme> { pub fn theme(&self) -> Option<Theme> {
self.lock_shared_state("theme").current_theme self.ivars().current_theme.get()
} }
#[inline] #[inline]
@ -1400,8 +1326,9 @@ impl WinitWindow {
pub fn set_theme(&self, theme: Option<Theme>) { pub fn set_theme(&self, theme: Option<Theme>) {
let mtm = MainThreadMarker::from(self); let mtm = MainThreadMarker::from(self);
set_ns_theme(theme, mtm); set_ns_theme(theme, mtm);
self.lock_shared_state("set_theme").current_theme = self.ivars()
theme.or_else(|| Some(get_ns_theme(mtm))); .current_theme
.set(theme.or_else(|| Some(get_ns_theme(mtm))));
} }
#[inline] #[inline]
@ -1426,18 +1353,16 @@ impl WinitWindow {
impl WindowExtMacOS for WinitWindow { impl WindowExtMacOS for WinitWindow {
#[inline] #[inline]
fn simple_fullscreen(&self) -> bool { fn simple_fullscreen(&self) -> bool {
self.lock_shared_state("simple_fullscreen") self.ivars().is_simple_fullscreen.get()
.is_simple_fullscreen
} }
#[inline] #[inline]
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool { fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
let mtm = MainThreadMarker::from(self); let mtm = MainThreadMarker::from(self);
let mut shared_state_lock = self.lock_shared_state("set_simple_fullscreen");
let app = NSApplication::sharedApplication(mtm); let app = NSApplication::sharedApplication(mtm);
let is_native_fullscreen = shared_state_lock.fullscreen.is_some(); let is_native_fullscreen = self.ivars().fullscreen.borrow().is_some();
let is_simple_fullscreen = shared_state_lock.is_simple_fullscreen; let is_simple_fullscreen = self.ivars().is_simple_fullscreen.get();
// Do nothing if native fullscreen is active. // Do nothing if native fullscreen is active.
if is_native_fullscreen if is_native_fullscreen
@ -1450,16 +1375,16 @@ impl WindowExtMacOS for WinitWindow {
if fullscreen { if fullscreen {
// Remember the original window's settings // Remember the original window's settings
// Exclude title bar // Exclude title bar
shared_state_lock.standard_frame = Some(self.contentRectForFrameRect(self.frame())); self.ivars()
shared_state_lock.saved_style = Some(self.styleMask()); .standard_frame
shared_state_lock.save_presentation_opts = Some(app.presentationOptions()); .set(Some(self.contentRectForFrameRect(self.frame())));
self.ivars().saved_style.set(Some(self.styleMask()));
self.ivars()
.save_presentation_opts
.set(Some(app.presentationOptions()));
// Tell our window's state that we're in fullscreen // Tell our window's state that we're in fullscreen
shared_state_lock.is_simple_fullscreen = true; self.ivars().is_simple_fullscreen.set(true);
// Drop shared state lock before calling app.setPresentationOptions, because
// it will call our windowDidChangeScreen listener which reacquires the lock
drop(shared_state_lock);
// Simulate pre-Lion fullscreen by hiding the dock and menu bar // Simulate pre-Lion fullscreen by hiding the dock and menu bar
let presentation_options = let presentation_options =
@ -1480,16 +1405,16 @@ impl WindowExtMacOS for WinitWindow {
true true
} else { } else {
let new_mask = self.saved_style(&mut shared_state_lock); let new_mask = self.saved_style();
self.set_style_mask(new_mask); self.set_style_mask(new_mask);
shared_state_lock.is_simple_fullscreen = false; self.ivars().is_simple_fullscreen.set(false);
let save_presentation_opts = shared_state_lock.save_presentation_opts; let save_presentation_opts = self.ivars().save_presentation_opts.get();
let frame = shared_state_lock.saved_standard_frame(); let frame = self
.ivars()
// Drop shared state lock before calling app.setPresentationOptions, because .standard_frame
// it will call our windowDidChangeScreen listener which reacquires the lock .get()
drop(shared_state_lock); .unwrap_or(DEFAULT_STANDARD_FRAME);
if let Some(presentation_opts) = save_presentation_opts { if let Some(presentation_opts) = save_presentation_opts {
app.setPresentationOptions(presentation_opts); app.setPresentationOptions(presentation_opts);
@ -1559,13 +1484,11 @@ impl WindowExtMacOS for WinitWindow {
} }
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) { fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
let mut shared_state_lock = self.lock_shared_state("set_option_as_alt"); self.ivars().option_as_alt.set(option_as_alt);
shared_state_lock.option_as_alt = option_as_alt;
} }
fn option_as_alt(&self) -> OptionAsAlt { fn option_as_alt(&self) -> OptionAsAlt {
let shared_state_lock = self.lock_shared_state("option_as_alt"); self.ivars().option_as_alt.get()
shared_state_lock.option_as_alt
} }
} }
@ -1606,3 +1529,6 @@ fn set_ns_theme(theme: Option<Theme>, mtm: MainThreadMarker) {
app.setAppearance(appearance.as_ref().map(|a| a.as_ref())); app.setAppearance(appearance.as_ref().map(|a| a.as_ref()));
} }
} }
const DEFAULT_STANDARD_FRAME: NSRect =
NSRect::new(NSPoint::new(50.0, 50.0), NSSize::new(800.0, 600.0));

View file

@ -90,11 +90,7 @@ declare_class!(
fn window_will_start_live_resize(&self, _: Option<&AnyObject>) { fn window_will_start_live_resize(&self, _: Option<&AnyObject>) {
trace_scope!("windowWillStartLiveResize:"); trace_scope!("windowWillStartLiveResize:");
let increments = self let increments = self.ivars().window.ivars().resize_increments.get();
.ivars()
.window
.lock_shared_state("window_will_enter_fullscreen")
.resize_increments;
self.ivars().window.set_resize_increments_inner(increments); self.ivars().window.set_resize_increments_inner(increments);
} }
@ -147,13 +143,10 @@ declare_class!(
fn window_will_enter_fullscreen(&self, _: Option<&AnyObject>) { fn window_will_enter_fullscreen(&self, _: Option<&AnyObject>) {
trace_scope!("windowWillEnterFullScreen:"); trace_scope!("windowWillEnterFullScreen:");
let mut shared_state = self let window_ivars = self.ivars().window.ivars();
.ivars() window_ivars.maximized.set(self.ivars().window.is_zoomed());
.window let mut fullscreen = window_ivars.fullscreen.borrow_mut();
.lock_shared_state("window_will_enter_fullscreen"); match &*fullscreen {
shared_state.maximized = self.ivars().window.is_zoomed();
let fullscreen = shared_state.fullscreen.as_ref();
match fullscreen {
// Exclusive mode sets the state in `set_fullscreen` as the user // Exclusive mode sets the state in `set_fullscreen` as the user
// can't enter exclusive mode by other means (like the // can't enter exclusive mode by other means (like the
// fullscreen button on the window decorations) // fullscreen button on the window decorations)
@ -166,10 +159,10 @@ declare_class!(
// on the green fullscreen button. Update state! // on the green fullscreen button. Update state!
None => { None => {
let current_monitor = self.ivars().window.current_monitor_inner(); let current_monitor = self.ivars().window.current_monitor_inner();
shared_state.fullscreen = Some(Fullscreen::Borderless(current_monitor)) *fullscreen = Some(Fullscreen::Borderless(current_monitor));
} }
} }
shared_state.in_fullscreen_transition = true; window_ivars.in_fullscreen_transition.set(true);
} }
/// Invoked when before exit fullscreen /// Invoked when before exit fullscreen
@ -177,11 +170,11 @@ declare_class!(
fn window_will_exit_fullscreen(&self, _: Option<&AnyObject>) { fn window_will_exit_fullscreen(&self, _: Option<&AnyObject>) {
trace_scope!("windowWillExitFullScreen:"); trace_scope!("windowWillExitFullScreen:");
let mut shared_state = self self.ivars()
.ivars()
.window .window
.lock_shared_state("window_will_exit_fullscreen"); .ivars()
shared_state.in_fullscreen_transition = true; .in_fullscreen_transition
.set(true);
} }
#[method(window:willUseFullScreenPresentationOptions:)] #[method(window:willUseFullScreenPresentationOptions:)]
@ -200,11 +193,8 @@ declare_class!(
// we don't, for consistency. If we do, it should be documented that the // we don't, for consistency. If we do, it should be documented that the
// user-provided options are ignored in exclusive fullscreen. // user-provided options are ignored in exclusive fullscreen.
let mut options = proposed_options; let mut options = proposed_options;
let shared_state = self let fullscreen = self.ivars().window.ivars().fullscreen.borrow();
.ivars() if let Some(Fullscreen::Exclusive(_)) = &*fullscreen {
.window
.lock_shared_state("window_will_use_fullscreen_presentation_options");
if let Some(Fullscreen::Exclusive(_)) = shared_state.fullscreen {
options = NSApplicationPresentationFullScreen options = NSApplicationPresentationFullScreen
| NSApplicationPresentationHideDock | NSApplicationPresentationHideDock
| NSApplicationPresentationHideMenuBar; | NSApplicationPresentationHideMenuBar;
@ -218,14 +208,9 @@ declare_class!(
fn window_did_enter_fullscreen(&self, _: Option<&AnyObject>) { fn window_did_enter_fullscreen(&self, _: Option<&AnyObject>) {
trace_scope!("windowDidEnterFullScreen:"); trace_scope!("windowDidEnterFullScreen:");
self.ivars().initial_fullscreen.set(false); self.ivars().initial_fullscreen.set(false);
let mut shared_state = self let window_ivars = self.ivars().window.ivars();
.ivars() window_ivars.in_fullscreen_transition.set(false);
.window if let Some(target_fullscreen) = window_ivars.target_fullscreen.take() {
.lock_shared_state("window_did_enter_fullscreen");
shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take();
drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen {
self.ivars().window.set_fullscreen(target_fullscreen); self.ivars().window.set_fullscreen(target_fullscreen);
} }
} }
@ -236,14 +221,9 @@ declare_class!(
trace_scope!("windowDidExitFullScreen:"); trace_scope!("windowDidExitFullScreen:");
self.ivars().window.restore_state_from_fullscreen(); self.ivars().window.restore_state_from_fullscreen();
let mut shared_state = self let window_ivars = self.ivars().window.ivars();
.ivars() window_ivars.in_fullscreen_transition.set(false);
.window if let Some(target_fullscreen) = window_ivars.target_fullscreen.take() {
.lock_shared_state("window_did_exit_fullscreen");
shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take();
drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen {
self.ivars().window.set_fullscreen(target_fullscreen); self.ivars().window.set_fullscreen(target_fullscreen);
} }
} }
@ -267,12 +247,9 @@ declare_class!(
#[method(windowDidFailToEnterFullScreen:)] #[method(windowDidFailToEnterFullScreen:)]
fn window_did_fail_to_enter_fullscreen(&self, _: Option<&AnyObject>) { fn window_did_fail_to_enter_fullscreen(&self, _: Option<&AnyObject>) {
trace_scope!("windowDidFailToEnterFullScreen:"); trace_scope!("windowDidFailToEnterFullScreen:");
let mut shared_state = self let window_ivars = self.ivars().window.ivars();
.ivars() window_ivars.in_fullscreen_transition.set(false);
.window window_ivars.target_fullscreen.replace(None);
.lock_shared_state("window_did_fail_to_enter_fullscreen");
shared_state.in_fullscreen_transition = false;
shared_state.target_fullscreen = None;
if self.ivars().initial_fullscreen.get() { if self.ivars().initial_fullscreen.get() {
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
unsafe { unsafe {
@ -300,11 +277,7 @@ declare_class!(
#[method(windowDidChangeScreen:)] #[method(windowDidChangeScreen:)]
fn window_did_change_screen(&self, _: Option<&AnyObject>) { fn window_did_change_screen(&self, _: Option<&AnyObject>) {
trace_scope!("windowDidChangeScreen:"); trace_scope!("windowDidChangeScreen:");
let is_simple_fullscreen = self let is_simple_fullscreen = self.ivars().window.ivars().is_simple_fullscreen.get();
.ivars()
.window
.lock_shared_state("window_did_change_screen")
.is_simple_fullscreen;
if is_simple_fullscreen { if is_simple_fullscreen {
if let Some(screen) = self.ivars().window.screen() { if let Some(screen) = self.ivars().window.screen() {
self.ivars().window.setFrame_display(screen.frame(), true); self.ivars().window.setFrame_display(screen.frame(), true);
@ -396,14 +369,13 @@ declare_class!(
fn effective_appearance_did_changed_on_main_thread(&self, _: Option<&AnyObject>) { fn effective_appearance_did_changed_on_main_thread(&self, _: Option<&AnyObject>) {
let mtm = MainThreadMarker::from(self); let mtm = MainThreadMarker::from(self);
let theme = get_ns_theme(mtm); let theme = get_ns_theme(mtm);
let mut shared_state = self let old_theme = self
.ivars() .ivars()
.window .window
.lock_shared_state("effective_appearance_did_change"); .ivars()
let current_theme = shared_state.current_theme; .current_theme
shared_state.current_theme = Some(theme); .replace(Some(theme));
drop(shared_state); if old_theme != Some(theme) {
if current_theme != Some(theme) {
self.queue_event(WindowEvent::ThemeChanged(theme)); self.queue_event(WindowEvent::ThemeChanged(theme));
} }
} }