macOS RAII trace guards (#2150)

* Add TraceGuard to make tracing simpler

* Add SharedStateMutexGuard to make tracing simpler

* Add trace_scope macro

* Add missing let binding in trace_scope!
This commit is contained in:
Mads Marquart 2022-01-23 21:35:26 +01:00 committed by GitHub
parent 51bb6b751e
commit 9229e2d88b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 176 additions and 135 deletions

View file

@ -75,7 +75,6 @@ extern "C" fn dealloc(this: &Object, _: Sel) {
}
extern "C" fn did_finish_launching(this: &Object, _: Sel, _: id) {
trace!("Triggered `applicationDidFinishLaunching`");
trace_scope!("applicationDidFinishLaunching:");
AppState::launched(this);
trace!("Completed `applicationDidFinishLaunching`");
}

View file

@ -1,5 +1,8 @@
#![cfg(target_os = "macos")]
#[macro_use]
mod util;
mod app;
mod app_delegate;
mod app_state;
@ -9,7 +12,6 @@ mod ffi;
mod menu;
mod monitor;
mod observer;
mod util;
mod view;
mod window;
mod window_delegate;

View file

@ -14,7 +14,11 @@ use objc::runtime::{BOOL, NO};
use crate::{
dpi::LogicalSize,
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
platform_impl::platform::{
ffi,
util::IdRef,
window::{SharedState, SharedStateMutexGuard},
},
};
// Unsafe wrapper type that allows us to dispatch things that aren't Send.
@ -111,10 +115,11 @@ pub unsafe fn toggle_full_screen_async(
if !curr_mask.contains(required) {
set_style_mask(*ns_window, *ns_view, required);
if let Some(shared_state) = shared_state.upgrade() {
trace!("Locked shared state in `toggle_full_screen_callback`");
let mut shared_state_lock = shared_state.lock().unwrap();
let mut shared_state_lock = SharedStateMutexGuard::new(
shared_state.lock().unwrap(),
"toggle_full_screen_callback",
);
(*shared_state_lock).saved_style = Some(curr_mask);
trace!("Unlocked shared state in `toggle_full_screen_callback`");
}
}
}
@ -144,8 +149,8 @@ pub unsafe fn set_maximized_async(
let shared_state = MainThreadSafe(shared_state);
Queue::main().exec_async(move || {
if let Some(shared_state) = shared_state.upgrade() {
trace!("Locked shared state in `set_maximized`");
let mut shared_state_lock = shared_state.lock().unwrap();
let mut shared_state_lock =
SharedStateMutexGuard::new(shared_state.lock().unwrap(), "set_maximized");
// Save the standard frame sized if it is not zoomed
if !is_zoomed {
@ -171,8 +176,6 @@ pub unsafe fn set_maximized_async(
};
ns_window.setFrame_display_(new_rect, NO);
}
trace!("Unlocked shared state in `set_maximized`");
}
});
}

View file

@ -11,7 +11,7 @@ use cocoa::{
foundation::{NSPoint, NSRect, NSString, NSUInteger},
};
use core_graphics::display::CGDisplay;
use objc::runtime::{Class, Object, Sel, BOOL, YES};
use objc::runtime::{Class, Object};
use crate::dpi::LogicalPosition;
use crate::platform_impl::platform::ffi;
@ -79,6 +79,35 @@ impl Clone for IdRef {
}
}
macro_rules! trace_scope {
($s:literal) => {
let _crate = $crate::platform_impl::platform::util::TraceGuard::new(module_path!(), $s);
};
}
pub(crate) struct TraceGuard {
module_path: &'static str,
called_from_fn: &'static str,
}
impl TraceGuard {
#[inline]
pub(crate) fn new(module_path: &'static str, called_from_fn: &'static str) -> Self {
trace!(target: module_path, "Triggered `{}`", called_from_fn);
Self {
module_path,
called_from_fn,
}
}
}
impl Drop for TraceGuard {
#[inline]
fn drop(&mut self) {
trace!(target: self.module_path, "Completed `{}`", self.called_from_fn);
}
}
// For consistency with other platforms, this will...
// 1. translate the bottom-left window corner into the top-left window corner
// 2. translate the coordinate from a bottom-left origin coordinate system to a top-left one
@ -129,10 +158,6 @@ pub unsafe fn open_emoji_picker() {
let () = msg_send![NSApp(), orderFrontCharacterPalette: nil];
}
pub extern "C" fn yes(_: &Object, _: Sel) -> BOOL {
YES
}
pub unsafe fn toggle_style_mask(window: id, view: id, mask: NSWindowStyleMask, on: bool) {
use cocoa::appkit::NSWindow;

View file

@ -301,7 +301,7 @@ extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> i
}
extern "C" fn view_did_move_to_window(this: &Object, _sel: Sel) {
trace!("Triggered `viewDidMoveToWindow`");
trace_scope!("viewDidMoveToWindow");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -319,10 +319,10 @@ extern "C" fn view_did_move_to_window(this: &Object, _sel: Sel) {
];
state.tracking_rect = Some(tracking_rect);
}
trace!("Completed `viewDidMoveToWindow`");
}
extern "C" fn frame_did_change(this: &Object, _sel: Sel, _event: id) {
trace_scope!("frameDidChange:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -344,6 +344,7 @@ extern "C" fn frame_did_change(this: &Object, _sel: Sel, _event: id) {
}
extern "C" fn draw_rect(this: &Object, _sel: Sel, rect: NSRect) {
trace_scope!("drawRect:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -356,6 +357,7 @@ extern "C" fn draw_rect(this: &Object, _sel: Sel, rect: NSRect) {
}
extern "C" fn accepts_first_responder(_this: &Object, _sel: Sel) -> BOOL {
trace_scope!("acceptsFirstResponder");
YES
}
@ -363,10 +365,12 @@ extern "C" fn accepts_first_responder(_this: &Object, _sel: Sel) -> BOOL {
// IMKInputSession [0x7fc573576ff0 presentFunctionRowItemTextInputViewWithEndpoint:completionHandler:] : [self textInputContext]=0x7fc573558e10 *NO* NSRemoteViewController to client, NSError=Error Domain=NSCocoaErrorDomain Code=4099 "The connection from pid 0 was invalidated from this process." UserInfo={NSDebugDescription=The connection from pid 0 was invalidated from this process.}, com.apple.inputmethod.EmojiFunctionRowItem
// TODO: Add an API extension for using `NSTouchBar`
extern "C" fn touch_bar(_this: &Object, _sel: Sel) -> BOOL {
trace_scope!("touchBar");
NO
}
extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
trace_scope!("resetCursorRects");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -386,20 +390,18 @@ extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
}
extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL {
trace_scope!("hasMarkedText");
unsafe {
trace!("Triggered `hasMarkedText`");
let marked_text: id = *this.get_ivar("markedText");
trace!("Completed `hasMarkedText`");
(marked_text.length() > 0) as BOOL
}
}
extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange {
trace_scope!("markedRange");
unsafe {
trace!("Triggered `markedRange`");
let marked_text: id = *this.get_ivar("markedText");
let length = marked_text.length();
trace!("Completed `markedRange`");
if length > 0 {
NSRange::new(0, length - 1)
} else {
@ -409,8 +411,7 @@ extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange {
}
extern "C" fn selected_range(_this: &Object, _sel: Sel) -> NSRange {
trace!("Triggered `selectedRange`");
trace!("Completed `selectedRange`");
trace_scope!("selectedRange");
util::EMPTY_RANGE
}
@ -421,7 +422,7 @@ extern "C" fn set_marked_text(
_selected_range: NSRange,
_replacement_range: NSRange,
) {
trace!("Triggered `setMarkedText`");
trace_scope!("setMarkedText:selectedRange:replacementRange:");
unsafe {
let marked_text_ref: &mut id = this.get_mut_ivar("markedText");
let _: () = msg_send![(*marked_text_ref), release];
@ -434,11 +435,10 @@ extern "C" fn set_marked_text(
};
*marked_text_ref = marked_text;
}
trace!("Completed `setMarkedText`");
}
extern "C" fn unmark_text(this: &Object, _sel: Sel) {
trace!("Triggered `unmarkText`");
trace_scope!("unmarkText");
unsafe {
let marked_text: id = *this.get_ivar("markedText");
let mutable_string = marked_text.mutableString();
@ -448,12 +448,10 @@ extern "C" fn unmark_text(this: &Object, _sel: Sel) {
let input_context: id = msg_send![this, inputContext];
let _: () = msg_send![input_context, discardMarkedText];
}
trace!("Completed `unmarkText`");
}
extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id {
trace!("Triggered `validAttributesForMarkedText`");
trace!("Completed `validAttributesForMarkedText`");
trace_scope!("validAttributesForMarkedText");
unsafe { msg_send![class!(NSArray), array] }
}
@ -463,14 +461,12 @@ extern "C" fn attributed_substring_for_proposed_range(
_range: NSRange,
_actual_range: *mut c_void, // *mut NSRange
) -> id {
trace!("Triggered `attributedSubstringForProposedRange`");
trace!("Completed `attributedSubstringForProposedRange`");
trace_scope!("attributedSubstringForProposedRange:actualRange:");
nil
}
extern "C" fn character_index_for_point(_this: &Object, _sel: Sel, _point: NSPoint) -> NSUInteger {
trace!("Triggered `characterIndexForPoint`");
trace!("Completed `characterIndexForPoint`");
trace_scope!("characterIndexForPoint:");
0
}
@ -480,8 +476,8 @@ extern "C" fn first_rect_for_character_range(
_range: NSRange,
_actual_range: *mut c_void, // *mut NSRange
) -> NSRect {
trace_scope!("firstRectForCharacterRange:actualRange:");
unsafe {
trace!("Triggered `firstRectForCharacterRange`");
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
let (x, y) = state.ime_spot.unwrap_or_else(|| {
@ -493,13 +489,12 @@ extern "C" fn first_rect_for_character_range(
let y = util::bottom_left_to_top_left(content_rect);
(x, y)
});
trace!("Completed `firstRectForCharacterRange`");
NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0))
}
}
extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: NSRange) {
trace!("Triggered `insertText`");
trace_scope!("insertText:replacementRange:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -530,11 +525,10 @@ extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_ran
AppState::queue_events(events);
}
trace!("Completed `insertText`");
}
extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
trace!("Triggered `doCommandBySelector`");
trace_scope!("doCommandBySelector:");
// Basically, we're sent this message whenever a keyboard event that doesn't generate a "human readable" character
// happens, i.e. newlines, tabs, and Ctrl+C.
unsafe {
@ -567,7 +561,6 @@ extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
AppState::queue_events(events);
}
trace!("Completed `doCommandBySelector`");
}
fn get_characters(event: id, ignore_modifiers: bool) -> String {
@ -639,7 +632,7 @@ fn update_potentially_stale_modifiers(state: &mut ViewState, event: id) {
}
extern "C" fn key_down(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `keyDown`");
trace_scope!("keyDown:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -694,11 +687,10 @@ extern "C" fn key_down(this: &Object, _sel: Sel, event: id) {
let _: () = msg_send![this, interpretKeyEvents: array];
}
}
trace!("Completed `keyDown`");
}
extern "C" fn key_up(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `keyUp`");
trace_scope!("keyUp:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -725,11 +717,10 @@ extern "C" fn key_up(this: &Object, _sel: Sel, event: id) {
AppState::queue_event(EventWrapper::StaticEvent(window_event));
}
trace!("Completed `keyUp`");
}
extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `flagsChanged`");
trace_scope!("flagsChanged:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -786,10 +777,10 @@ extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) {
event: WindowEvent::ModifiersChanged(state.modifiers),
}));
}
trace!("Completed `flagsChanged`");
}
extern "C" fn insert_tab(this: &Object, _sel: Sel, _sender: id) {
trace_scope!("insertTab:");
unsafe {
let window: id = msg_send![this, window];
let first_responder: id = msg_send![window, firstResponder];
@ -801,6 +792,7 @@ extern "C" fn insert_tab(this: &Object, _sel: Sel, _sender: id) {
}
extern "C" fn insert_back_tab(this: &Object, _sel: Sel, _sender: id) {
trace_scope!("insertBackTab:");
unsafe {
let window: id = msg_send![this, window];
let first_responder: id = msg_send![window, firstResponder];
@ -814,7 +806,7 @@ extern "C" fn insert_back_tab(this: &Object, _sel: Sel, _sender: id) {
// Allows us to receive Cmd-. (the shortcut for closing a dialog)
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
trace!("Triggered `cancelOperation`");
trace_scope!("cancelOperation:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -844,7 +836,6 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
AppState::queue_event(EventWrapper::StaticEvent(window_event));
}
trace!("Completed `cancelOperation`");
}
fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: ElementState) {
@ -869,31 +860,37 @@ fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: Elem
}
extern "C" fn mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("mouseDown:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Left, ElementState::Pressed);
}
extern "C" fn mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("mouseUp:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Left, ElementState::Released);
}
extern "C" fn right_mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("rightMouseDown:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Right, ElementState::Pressed);
}
extern "C" fn right_mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("rightMouseUp:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Right, ElementState::Released);
}
extern "C" fn other_mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("otherMouseDown:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Middle, ElementState::Pressed);
}
extern "C" fn other_mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("otherMouseUp:");
mouse_motion(this, event);
mouse_click(this, event, MouseButton::Middle, ElementState::Released);
}
@ -941,6 +938,8 @@ fn mouse_motion(this: &Object, event: id) {
}
}
// No tracing on these because that would be overly verbose
extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
mouse_motion(this, event);
}
@ -958,7 +957,7 @@ extern "C" fn other_mouse_dragged(this: &Object, _sel: Sel, event: id) {
}
extern "C" fn mouse_entered(this: &Object, _sel: Sel, _event: id) {
trace!("Triggered `mouseEntered`");
trace_scope!("mouseEntered:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -972,11 +971,10 @@ extern "C" fn mouse_entered(this: &Object, _sel: Sel, _event: id) {
AppState::queue_event(EventWrapper::StaticEvent(enter_event));
}
trace!("Completed `mouseEntered`");
}
extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
trace!("Triggered `mouseExited`");
trace_scope!("mouseExited:");
unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
@ -990,11 +988,10 @@ extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
AppState::queue_event(EventWrapper::StaticEvent(window_event));
}
trace!("Completed `mouseExited`");
}
extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `scrollWheel`");
trace_scope!("scrollWheel:");
mouse_motion(this, event);
@ -1043,11 +1040,10 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
AppState::queue_event(EventWrapper::StaticEvent(device_event));
AppState::queue_event(EventWrapper::StaticEvent(window_event));
}
trace!("Completed `scrollWheel`");
}
extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `pressureChangeWithEvent`");
trace_scope!("pressureChangeWithEvent:");
mouse_motion(this, event);
@ -1069,16 +1065,17 @@ extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {
AppState::queue_event(EventWrapper::StaticEvent(window_event));
}
trace!("Completed `pressureChangeWithEvent`");
}
// Allows us to receive Ctrl-Tab and Ctrl-Esc.
// Note that this *doesn't* help with any missing Cmd inputs.
// https://github.com/chromium/chromium/blob/a86a8a6bcfa438fa3ac2eba6f02b3ad1f8e0756f/ui/views/cocoa/bridged_content_view.mm#L816
extern "C" fn wants_key_down_for_event(_this: &Object, _sel: Sel, _event: id) -> BOOL {
trace_scope!("_wantsKeyDownForEvent:");
YES
}
extern "C" fn accepts_first_mouse(_this: &Object, _sel: Sel, _event: id) -> BOOL {
trace_scope!("acceptsFirstMouse:");
YES
}

View file

@ -2,11 +2,11 @@ use raw_window_handle::{AppKitHandle, RawWindowHandle};
use std::{
collections::VecDeque,
convert::TryInto,
f64,
f64, ops,
os::raw::c_void,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, Weak,
Arc, Mutex, MutexGuard, Weak,
},
};
@ -251,13 +251,24 @@ lazy_static! {
static ref WINDOW_CLASS: WindowClass = unsafe {
let window_superclass = class!(NSWindow);
let mut decl = ClassDecl::new("WinitWindow", window_superclass).unwrap();
pub extern "C" fn can_become_main_window(_: &Object, _: Sel) -> BOOL {
trace_scope!("canBecomeMainWindow");
YES
}
pub extern "C" fn can_become_key_window(_: &Object, _: Sel) -> BOOL {
trace_scope!("canBecomeKeyWindow");
YES
}
decl.add_method(
sel!(canBecomeMainWindow),
util::yes as extern "C" fn(&Object, Sel) -> BOOL,
can_become_main_window as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(canBecomeKeyWindow),
util::yes as extern "C" fn(&Object, Sel) -> BOOL,
can_become_key_window as extern "C" fn(&Object, Sel) -> BOOL,
);
WindowClass(decl.register())
};
@ -311,11 +322,49 @@ impl From<WindowAttributes> for SharedState {
}
}
pub(crate) struct SharedStateMutexGuard<'a> {
guard: MutexGuard<'a, SharedState>,
called_from_fn: &'static str,
}
impl<'a> SharedStateMutexGuard<'a> {
#[inline]
pub(crate) 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);
}
}
pub struct UnownedWindow {
pub ns_window: IdRef, // never changes
pub ns_view: IdRef, // never changes
input_context: IdRef, // never changes
pub shared_state: Arc<Mutex<SharedState>>,
shared_state: Arc<Mutex<SharedState>>,
decorations: AtomicBool,
cursor_state: Weak<Mutex<CursorState>>,
pub inner_rect: Option<PhysicalSize<u32>>,
@ -420,6 +469,14 @@ impl UnownedWindow {
Ok((window, delegate))
}
#[track_caller]
pub(crate) fn lock_shared_state(
&self,
called_from_fn: &'static str,
) -> SharedStateMutexGuard<'_> {
SharedStateMutexGuard::new(self.shared_state.lock().unwrap(), called_from_fn)
}
fn set_style_mask_async(&self, mask: NSWindowStyleMask) {
unsafe { util::set_style_mask_async(*self.ns_window, *self.ns_view, mask) };
}
@ -530,10 +587,8 @@ impl UnownedWindow {
#[inline]
pub fn set_resizable(&self, resizable: bool) {
let fullscreen = {
trace!("Locked shared state in `set_resizable`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
let mut shared_state_lock = self.lock_shared_state("set_resizable");
shared_state_lock.resizable = resizable;
trace!("Unlocked shared state in `set_resizable`");
shared_state_lock.fullscreen.is_some()
};
if !fullscreen {
@ -653,8 +708,7 @@ impl UnownedWindow {
/// user clicking on the green fullscreen button or programmatically by
/// `toggleFullScreen:`
pub(crate) fn restore_state_from_fullscreen(&self) {
trace!("Locked shared state in `restore_state_from_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
let mut shared_state_lock = self.lock_shared_state("restore_state_from_fullscreen");
shared_state_lock.fullscreen = None;
@ -662,7 +716,6 @@ impl UnownedWindow {
let mask = self.saved_style(&mut *shared_state_lock);
drop(shared_state_lock);
trace!("Unocked shared state in `restore_state_from_fullscreen`");
self.set_style_mask_async(mask);
self.set_maximized(maximized);
@ -705,7 +758,7 @@ impl UnownedWindow {
#[inline]
pub fn fullscreen(&self) -> Option<Fullscreen> {
let shared_state_lock = self.shared_state.lock().unwrap();
let shared_state_lock = self.lock_shared_state("fullscreen");
shared_state_lock.fullscreen.clone()
}
@ -716,25 +769,20 @@ impl UnownedWindow {
#[inline]
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
trace!("Locked shared state in `set_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
let mut shared_state_lock = self.lock_shared_state("set_fullscreen");
if shared_state_lock.is_simple_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`");
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();
if fullscreen == old_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`");
return;
}
trace!("Unlocked shared state in `set_fullscreen`");
drop(shared_state_lock);
// If the fullscreen is on a different monitor, we must move the window
@ -787,8 +835,7 @@ impl UnownedWindow {
if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) {
unsafe {
let app = NSApp();
trace!("Locked shared state in `set_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
let mut shared_state_lock = self.lock_shared_state("set_fullscreen");
shared_state_lock.save_presentation_opts = Some(app.presentationOptions_());
}
}
@ -840,8 +887,7 @@ impl UnownedWindow {
}
}
trace!("Locked shared state in `set_fullscreen`");
let mut shared_state_lock = self.shared_state.lock().unwrap();
let mut shared_state_lock = self.lock_shared_state("set_fullscreen");
shared_state_lock.fullscreen = fullscreen.clone();
INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
@ -884,7 +930,6 @@ impl UnownedWindow {
// that the menu bar is disabled. This is done in the window
// delegate in `window:willUseFullScreenPresentationOptions:`.
let app = NSApp();
trace!("Locked shared state in `set_fullscreen`");
shared_state_lock.save_presentation_opts = Some(app.presentationOptions_());
let presentation_options =
@ -918,7 +963,6 @@ impl UnownedWindow {
},
_ => INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst),
};
trace!("Unlocked shared state in `set_fullscreen`");
}
#[inline]
@ -927,9 +971,7 @@ impl UnownedWindow {
self.decorations.store(decorations, Ordering::Release);
let (fullscreen, resizable) = {
trace!("Locked shared state in `set_decorations`");
let shared_state_lock = self.shared_state.lock().unwrap();
trace!("Unlocked shared state in `set_decorations`");
let shared_state_lock = self.lock_shared_state("set_decorations");
(
shared_state_lock.fullscreen.is_some(),
shared_state_lock.resizable,

View file

@ -265,14 +265,13 @@ extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> i
}
extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `windowShouldClose:`");
trace_scope!("windowShouldClose:");
with_state(this, |state| state.emit_event(WindowEvent::CloseRequested));
trace!("Completed `windowShouldClose:`");
NO
}
extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillClose:`");
trace_scope!("windowWillClose:");
with_state(this, |state| unsafe {
// `setDelegate:` retains the previous value and then autoreleases it
autoreleasepool(|| {
@ -282,47 +281,42 @@ extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
});
state.emit_event(WindowEvent::Destroyed);
});
trace!("Completed `windowWillClose:`");
}
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidResize:`");
trace_scope!("windowDidResize:");
with_state(this, |state| {
state.emit_resize_event();
state.emit_move_event();
});
trace!("Completed `windowDidResize:`");
}
// This won't be triggered if the move was part of a resize.
extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidMove:`");
trace_scope!("windowDidMove:");
with_state(this, |state| {
state.emit_move_event();
});
trace!("Completed `windowDidMove:`");
}
extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidChangeBackingProperties:`");
trace_scope!("windowDidChangeBackingProperties:");
with_state(this, |state| {
state.emit_static_scale_factor_changed_event();
});
trace!("Completed `windowDidChangeBackingProperties:`");
}
extern "C" fn window_did_become_key(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidBecomeKey:`");
trace_scope!("windowDidBecomeKey:");
with_state(this, |state| {
// TODO: center the cursor if the window had mouse grab when it
// lost focus
state.emit_event(WindowEvent::Focused(true));
});
trace!("Completed `windowDidBecomeKey:`");
}
extern "C" fn window_did_resign_key(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidResignKey:`");
trace_scope!("windowDidResignKey:");
with_state(this, |state| {
// It happens rather often, e.g. when the user is Cmd+Tabbing, that the
// NSWindowDelegate will receive a didResignKey event despite no event
@ -349,12 +343,11 @@ extern "C" fn window_did_resign_key(this: &Object, _: Sel, _: id) {
state.emit_event(WindowEvent::Focused(false));
});
trace!("Completed `windowDidResignKey:`");
}
/// Invoked when the dragged image enters destination bounds or frame
extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL {
trace!("Triggered `draggingEntered:`");
trace_scope!("draggingEntered:");
use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
use std::path::PathBuf;
@ -376,20 +369,18 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL {
}
}
trace!("Completed `draggingEntered:`");
YES
}
/// Invoked when the image is released
extern "C" fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `prepareForDragOperation:`");
trace!("Completed `prepareForDragOperation:`");
trace_scope!("prepareForDragOperation:");
YES
}
/// Invoked after the released image has been removed from the screen
extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL {
trace!("Triggered `performDragOperation:`");
trace_scope!("performDragOperation:");
use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
use std::path::PathBuf;
@ -411,35 +402,31 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL
}
}
trace!("Completed `performDragOperation:`");
YES
}
/// Invoked when the dragging operation is complete
extern "C" fn conclude_drag_operation(_: &Object, _: Sel, _: id) {
trace!("Triggered `concludeDragOperation:`");
trace!("Completed `concludeDragOperation:`");
trace_scope!("concludeDragOperation:");
}
/// Invoked when the dragging operation is cancelled
extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) {
trace!("Triggered `draggingExited:`");
trace_scope!("draggingExited:");
with_state(this, |state| {
state.emit_event(WindowEvent::HoveredFileCancelled)
});
trace!("Completed `draggingExited:`");
}
/// Invoked when before enter fullscreen
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillEnterFullscreen:`");
trace_scope!("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`");
let mut shared_state = window.shared_state.lock().unwrap();
let mut shared_state = window.lock_shared_state("window_will_enter_fullscreen");
shared_state.maximized = window.is_zoomed();
match shared_state.fullscreen {
// Exclusive mode sets the state in `set_fullscreen` as the user
@ -458,27 +445,22 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
}
}
shared_state.in_fullscreen_transition = true;
trace!("Unlocked shared state in `window_will_enter_fullscreen`");
})
});
trace!("Completed `windowWillEnterFullscreen:`");
}
/// Invoked when before exit fullscreen
extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillExitFullScreen:`");
trace_scope!("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`");
let mut shared_state = window.shared_state.lock().unwrap();
let mut shared_state = window.lock_shared_state("window_will_exit_fullscreen");
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(
@ -487,6 +469,7 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
_: id,
proposed_options: NSUInteger,
) -> NSUInteger {
trace_scope!("window:willUseFullScreenPresentationOptions:");
// Generally, games will want to disable the menu bar and the dock. Ideally,
// this would be configurable by the user. Unfortunately because of our
// `CGShieldingWindowLevel() + 1` hack (see `set_fullscreen`), our window is
@ -498,15 +481,14 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
let mut options: NSUInteger = proposed_options;
with_state(this, |state| {
state.with_window(|window| {
trace!("Locked shared state in `window_will_use_fullscreen_presentation_options`");
let shared_state = window.shared_state.lock().unwrap();
let shared_state =
window.lock_shared_state("window_will_use_fullscreen_presentation_options");
if let Some(Fullscreen::Exclusive(_)) = shared_state.fullscreen {
options = (NSApplicationPresentationOptions::NSApplicationPresentationFullScreen
| NSApplicationPresentationOptions::NSApplicationPresentationHideDock
| NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar)
.bits();
}
trace!("Unlocked shared state in `window_will_use_fullscreen_presentation_options`");
})
});
@ -515,46 +497,40 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
/// Invoked when entered fullscreen
extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace_scope!("windowDidEnterFullscreen:");
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidEnterFullscreen:`");
with_state(this, |state| {
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();
let mut shared_state = window.lock_shared_state("window_did_enter_fullscreen");
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:`");
}
/// Invoked when exited fullscreen
extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
trace_scope!("windowDidExitFullscreen:");
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidExitFullscreen:`");
with_state(this, |state| {
state.with_window(|window| {
window.restore_state_from_fullscreen();
trace!("Locked shared state in `window_did_exit_fullscreen`");
let mut shared_state = window.shared_state.lock().unwrap();
let mut shared_state = window.lock_shared_state("window_did_exit_fullscreen");
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:`");
}
/// Invoked when fail to enter fullscreen
@ -574,14 +550,12 @@ extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
/// This method indicates that there was an error, and you should clean up any
/// work you may have done to prepare to enter full-screen mode.
extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidFailToEnterFullscreen:`");
trace_scope!("windowDidFailToEnterFullscreen:");
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();
let mut shared_state = window.lock_shared_state("window_did_fail_to_enter_fullscreen");
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 {
let _: () = unsafe {
@ -595,5 +569,4 @@ extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id)
state.with_window(|window| window.restore_state_from_fullscreen());
}
});
trace!("Completed `windowDidFailToEnterFullscreen:`");
}