macOS: Remove unnecessary Mutex in window state (#3390)
This commit is contained in:
parent
40b61d2d92
commit
c86b0daf7f
2 changed files with 130 additions and 232 deletions
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue