macOS RAII trace guards ()

* 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) { extern "C" fn did_finish_launching(this: &Object, _: Sel, _: id) {
trace!("Triggered `applicationDidFinishLaunching`"); trace_scope!("applicationDidFinishLaunching:");
AppState::launched(this); AppState::launched(this);
trace!("Completed `applicationDidFinishLaunching`");
} }

View file

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

View file

@ -14,7 +14,11 @@ use objc::runtime::{BOOL, NO};
use crate::{ use crate::{
dpi::LogicalSize, 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. // 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) { if !curr_mask.contains(required) {
set_style_mask(*ns_window, *ns_view, required); set_style_mask(*ns_window, *ns_view, required);
if let Some(shared_state) = shared_state.upgrade() { if let Some(shared_state) = shared_state.upgrade() {
trace!("Locked shared state in `toggle_full_screen_callback`"); let mut shared_state_lock = SharedStateMutexGuard::new(
let mut shared_state_lock = shared_state.lock().unwrap(); shared_state.lock().unwrap(),
"toggle_full_screen_callback",
);
(*shared_state_lock).saved_style = Some(curr_mask); (*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); let shared_state = MainThreadSafe(shared_state);
Queue::main().exec_async(move || { Queue::main().exec_async(move || {
if let Some(shared_state) = shared_state.upgrade() { if let Some(shared_state) = shared_state.upgrade() {
trace!("Locked shared state in `set_maximized`"); let mut shared_state_lock =
let mut shared_state_lock = shared_state.lock().unwrap(); SharedStateMutexGuard::new(shared_state.lock().unwrap(), "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 {
@ -171,8 +176,6 @@ pub unsafe fn set_maximized_async(
}; };
ns_window.setFrame_display_(new_rect, NO); 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}, foundation::{NSPoint, NSRect, NSString, NSUInteger},
}; };
use core_graphics::display::CGDisplay; use core_graphics::display::CGDisplay;
use objc::runtime::{Class, Object, Sel, BOOL, YES}; use objc::runtime::{Class, Object};
use crate::dpi::LogicalPosition; use crate::dpi::LogicalPosition;
use crate::platform_impl::platform::ffi; 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... // For consistency with other platforms, this will...
// 1. translate the bottom-left window corner into the top-left window corner // 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 // 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]; 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) { pub unsafe fn toggle_style_mask(window: id, view: id, mask: NSWindowStyleMask, on: bool) {
use cocoa::appkit::NSWindow; 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) { extern "C" fn view_did_move_to_window(this: &Object, _sel: Sel) {
trace!("Triggered `viewDidMoveToWindow`"); trace_scope!("viewDidMoveToWindow");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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); state.tracking_rect = Some(tracking_rect);
} }
trace!("Completed `viewDidMoveToWindow`");
} }
extern "C" fn frame_did_change(this: &Object, _sel: Sel, _event: id) { extern "C" fn frame_did_change(this: &Object, _sel: Sel, _event: id) {
trace_scope!("frameDidChange:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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) { extern "C" fn draw_rect(this: &Object, _sel: Sel, rect: NSRect) {
trace_scope!("drawRect:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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 { extern "C" fn accepts_first_responder(_this: &Object, _sel: Sel) -> BOOL {
trace_scope!("acceptsFirstResponder");
YES 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 // 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` // TODO: Add an API extension for using `NSTouchBar`
extern "C" fn touch_bar(_this: &Object, _sel: Sel) -> BOOL { extern "C" fn touch_bar(_this: &Object, _sel: Sel) -> BOOL {
trace_scope!("touchBar");
NO NO
} }
extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) { extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
trace_scope!("resetCursorRects");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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 { extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL {
trace_scope!("hasMarkedText");
unsafe { unsafe {
trace!("Triggered `hasMarkedText`");
let marked_text: id = *this.get_ivar("markedText"); let marked_text: id = *this.get_ivar("markedText");
trace!("Completed `hasMarkedText`");
(marked_text.length() > 0) as BOOL (marked_text.length() > 0) as BOOL
} }
} }
extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange { extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange {
trace_scope!("markedRange");
unsafe { unsafe {
trace!("Triggered `markedRange`");
let marked_text: id = *this.get_ivar("markedText"); let marked_text: id = *this.get_ivar("markedText");
let length = marked_text.length(); let length = marked_text.length();
trace!("Completed `markedRange`");
if length > 0 { if length > 0 {
NSRange::new(0, length - 1) NSRange::new(0, length - 1)
} else { } 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 { extern "C" fn selected_range(_this: &Object, _sel: Sel) -> NSRange {
trace!("Triggered `selectedRange`"); trace_scope!("selectedRange");
trace!("Completed `selectedRange`");
util::EMPTY_RANGE util::EMPTY_RANGE
} }
@ -421,7 +422,7 @@ extern "C" fn set_marked_text(
_selected_range: NSRange, _selected_range: NSRange,
_replacement_range: NSRange, _replacement_range: NSRange,
) { ) {
trace!("Triggered `setMarkedText`"); trace_scope!("setMarkedText:selectedRange:replacementRange:");
unsafe { unsafe {
let marked_text_ref: &mut id = this.get_mut_ivar("markedText"); let marked_text_ref: &mut id = this.get_mut_ivar("markedText");
let _: () = msg_send![(*marked_text_ref), release]; let _: () = msg_send![(*marked_text_ref), release];
@ -434,11 +435,10 @@ extern "C" fn set_marked_text(
}; };
*marked_text_ref = marked_text; *marked_text_ref = marked_text;
} }
trace!("Completed `setMarkedText`");
} }
extern "C" fn unmark_text(this: &Object, _sel: Sel) { extern "C" fn unmark_text(this: &Object, _sel: Sel) {
trace!("Triggered `unmarkText`"); trace_scope!("unmarkText");
unsafe { unsafe {
let marked_text: id = *this.get_ivar("markedText"); let marked_text: id = *this.get_ivar("markedText");
let mutable_string = marked_text.mutableString(); 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 input_context: id = msg_send![this, inputContext];
let _: () = msg_send![input_context, discardMarkedText]; let _: () = msg_send![input_context, discardMarkedText];
} }
trace!("Completed `unmarkText`");
} }
extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id { extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id {
trace!("Triggered `validAttributesForMarkedText`"); trace_scope!("validAttributesForMarkedText");
trace!("Completed `validAttributesForMarkedText`");
unsafe { msg_send![class!(NSArray), array] } unsafe { msg_send![class!(NSArray), array] }
} }
@ -463,14 +461,12 @@ extern "C" fn attributed_substring_for_proposed_range(
_range: NSRange, _range: NSRange,
_actual_range: *mut c_void, // *mut NSRange _actual_range: *mut c_void, // *mut NSRange
) -> id { ) -> id {
trace!("Triggered `attributedSubstringForProposedRange`"); trace_scope!("attributedSubstringForProposedRange:actualRange:");
trace!("Completed `attributedSubstringForProposedRange`");
nil nil
} }
extern "C" fn character_index_for_point(_this: &Object, _sel: Sel, _point: NSPoint) -> NSUInteger { extern "C" fn character_index_for_point(_this: &Object, _sel: Sel, _point: NSPoint) -> NSUInteger {
trace!("Triggered `characterIndexForPoint`"); trace_scope!("characterIndexForPoint:");
trace!("Completed `characterIndexForPoint`");
0 0
} }
@ -480,8 +476,8 @@ extern "C" fn first_rect_for_character_range(
_range: NSRange, _range: NSRange,
_actual_range: *mut c_void, // *mut NSRange _actual_range: *mut c_void, // *mut NSRange
) -> NSRect { ) -> NSRect {
trace_scope!("firstRectForCharacterRange:actualRange:");
unsafe { unsafe {
trace!("Triggered `firstRectForCharacterRange`");
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); let state = &mut *(state_ptr as *mut ViewState);
let (x, y) = state.ime_spot.unwrap_or_else(|| { 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); let y = util::bottom_left_to_top_left(content_rect);
(x, y) (x, y)
}); });
trace!("Completed `firstRectForCharacterRange`");
NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0)) 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) { extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: NSRange) {
trace!("Triggered `insertText`"); trace_scope!("insertText:replacementRange:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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); AppState::queue_events(events);
} }
trace!("Completed `insertText`");
} }
extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { 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 // 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. // happens, i.e. newlines, tabs, and Ctrl+C.
unsafe { unsafe {
@ -567,7 +561,6 @@ extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
AppState::queue_events(events); AppState::queue_events(events);
} }
trace!("Completed `doCommandBySelector`");
} }
fn get_characters(event: id, ignore_modifiers: bool) -> String { 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) { extern "C" fn key_down(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `keyDown`"); trace_scope!("keyDown:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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]; let _: () = msg_send![this, interpretKeyEvents: array];
} }
} }
trace!("Completed `keyDown`");
} }
extern "C" fn key_up(this: &Object, _sel: Sel, event: id) { extern "C" fn key_up(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `keyUp`"); trace_scope!("keyUp:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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)); AppState::queue_event(EventWrapper::StaticEvent(window_event));
} }
trace!("Completed `keyUp`");
} }
extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) { extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `flagsChanged`"); trace_scope!("flagsChanged:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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), event: WindowEvent::ModifiersChanged(state.modifiers),
})); }));
} }
trace!("Completed `flagsChanged`");
} }
extern "C" fn insert_tab(this: &Object, _sel: Sel, _sender: id) { extern "C" fn insert_tab(this: &Object, _sel: Sel, _sender: id) {
trace_scope!("insertTab:");
unsafe { unsafe {
let window: id = msg_send![this, window]; let window: id = msg_send![this, window];
let first_responder: id = msg_send![window, firstResponder]; 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) { extern "C" fn insert_back_tab(this: &Object, _sel: Sel, _sender: id) {
trace_scope!("insertBackTab:");
unsafe { unsafe {
let window: id = msg_send![this, window]; let window: id = msg_send![this, window];
let first_responder: id = msg_send![window, firstResponder]; 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) // Allows us to receive Cmd-. (the shortcut for closing a dialog)
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
trace!("Triggered `cancelOperation`"); trace_scope!("cancelOperation:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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)); AppState::queue_event(EventWrapper::StaticEvent(window_event));
} }
trace!("Completed `cancelOperation`");
} }
fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: ElementState) { 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) { extern "C" fn mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("mouseDown:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Left, ElementState::Pressed); mouse_click(this, event, MouseButton::Left, ElementState::Pressed);
} }
extern "C" fn mouse_up(this: &Object, _sel: Sel, event: id) { extern "C" fn mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("mouseUp:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Left, ElementState::Released); mouse_click(this, event, MouseButton::Left, ElementState::Released);
} }
extern "C" fn right_mouse_down(this: &Object, _sel: Sel, event: id) { extern "C" fn right_mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("rightMouseDown:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Right, ElementState::Pressed); mouse_click(this, event, MouseButton::Right, ElementState::Pressed);
} }
extern "C" fn right_mouse_up(this: &Object, _sel: Sel, event: id) { extern "C" fn right_mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("rightMouseUp:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Right, ElementState::Released); mouse_click(this, event, MouseButton::Right, ElementState::Released);
} }
extern "C" fn other_mouse_down(this: &Object, _sel: Sel, event: id) { extern "C" fn other_mouse_down(this: &Object, _sel: Sel, event: id) {
trace_scope!("otherMouseDown:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Middle, ElementState::Pressed); mouse_click(this, event, MouseButton::Middle, ElementState::Pressed);
} }
extern "C" fn other_mouse_up(this: &Object, _sel: Sel, event: id) { extern "C" fn other_mouse_up(this: &Object, _sel: Sel, event: id) {
trace_scope!("otherMouseUp:");
mouse_motion(this, event); mouse_motion(this, event);
mouse_click(this, event, MouseButton::Middle, ElementState::Released); 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) { extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
mouse_motion(this, event); 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) { extern "C" fn mouse_entered(this: &Object, _sel: Sel, _event: id) {
trace!("Triggered `mouseEntered`"); trace_scope!("mouseEntered:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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)); AppState::queue_event(EventWrapper::StaticEvent(enter_event));
} }
trace!("Completed `mouseEntered`");
} }
extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) { extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
trace!("Triggered `mouseExited`"); trace_scope!("mouseExited:");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); 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)); AppState::queue_event(EventWrapper::StaticEvent(window_event));
} }
trace!("Completed `mouseExited`");
} }
extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) { extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `scrollWheel`"); trace_scope!("scrollWheel:");
mouse_motion(this, event); 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(device_event));
AppState::queue_event(EventWrapper::StaticEvent(window_event)); AppState::queue_event(EventWrapper::StaticEvent(window_event));
} }
trace!("Completed `scrollWheel`");
} }
extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {
trace!("Triggered `pressureChangeWithEvent`"); trace_scope!("pressureChangeWithEvent:");
mouse_motion(this, event); 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)); AppState::queue_event(EventWrapper::StaticEvent(window_event));
} }
trace!("Completed `pressureChangeWithEvent`");
} }
// Allows us to receive Ctrl-Tab and Ctrl-Esc. // Allows us to receive Ctrl-Tab and Ctrl-Esc.
// Note that this *doesn't* help with any missing Cmd inputs. // 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 // 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 { extern "C" fn wants_key_down_for_event(_this: &Object, _sel: Sel, _event: id) -> BOOL {
trace_scope!("_wantsKeyDownForEvent:");
YES YES
} }
extern "C" fn accepts_first_mouse(_this: &Object, _sel: Sel, _event: id) -> BOOL { extern "C" fn accepts_first_mouse(_this: &Object, _sel: Sel, _event: id) -> BOOL {
trace_scope!("acceptsFirstMouse:");
YES YES
} }

View file

@ -2,11 +2,11 @@ use raw_window_handle::{AppKitHandle, RawWindowHandle};
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
convert::TryInto, convert::TryInto,
f64, f64, ops,
os::raw::c_void, os::raw::c_void,
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Mutex, Weak, Arc, Mutex, MutexGuard, Weak,
}, },
}; };
@ -251,13 +251,24 @@ lazy_static! {
static ref WINDOW_CLASS: WindowClass = unsafe { static ref WINDOW_CLASS: WindowClass = unsafe {
let window_superclass = class!(NSWindow); let window_superclass = class!(NSWindow);
let mut decl = ClassDecl::new("WinitWindow", window_superclass).unwrap(); 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( decl.add_method(
sel!(canBecomeMainWindow), 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( decl.add_method(
sel!(canBecomeKeyWindow), 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()) 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 struct UnownedWindow {
pub ns_window: IdRef, // never changes pub ns_window: IdRef, // never changes
pub ns_view: IdRef, // never changes pub ns_view: IdRef, // never changes
input_context: IdRef, // never changes input_context: IdRef, // never changes
pub shared_state: Arc<Mutex<SharedState>>, shared_state: Arc<Mutex<SharedState>>,
decorations: AtomicBool, decorations: AtomicBool,
cursor_state: Weak<Mutex<CursorState>>, cursor_state: Weak<Mutex<CursorState>>,
pub inner_rect: Option<PhysicalSize<u32>>, pub inner_rect: Option<PhysicalSize<u32>>,
@ -420,6 +469,14 @@ impl UnownedWindow {
Ok((window, delegate)) 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) { fn set_style_mask_async(&self, mask: NSWindowStyleMask) {
unsafe { util::set_style_mask_async(*self.ns_window, *self.ns_view, mask) }; unsafe { util::set_style_mask_async(*self.ns_window, *self.ns_view, mask) };
} }
@ -530,10 +587,8 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn set_resizable(&self, resizable: bool) { pub fn set_resizable(&self, resizable: bool) {
let fullscreen = { let fullscreen = {
trace!("Locked shared state in `set_resizable`"); let mut shared_state_lock = self.lock_shared_state("set_resizable");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.resizable = resizable; shared_state_lock.resizable = resizable;
trace!("Unlocked shared state in `set_resizable`");
shared_state_lock.fullscreen.is_some() shared_state_lock.fullscreen.is_some()
}; };
if !fullscreen { if !fullscreen {
@ -653,8 +708,7 @@ impl UnownedWindow {
/// 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) {
trace!("Locked shared state in `restore_state_from_fullscreen`"); let mut shared_state_lock = self.lock_shared_state("restore_state_from_fullscreen");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.fullscreen = None; shared_state_lock.fullscreen = None;
@ -662,7 +716,6 @@ impl UnownedWindow {
let mask = self.saved_style(&mut *shared_state_lock); let mask = self.saved_style(&mut *shared_state_lock);
drop(shared_state_lock); drop(shared_state_lock);
trace!("Unocked shared state in `restore_state_from_fullscreen`");
self.set_style_mask_async(mask); self.set_style_mask_async(mask);
self.set_maximized(maximized); self.set_maximized(maximized);
@ -705,7 +758,7 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn fullscreen(&self) -> Option<Fullscreen> { 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() shared_state_lock.fullscreen.clone()
} }
@ -716,25 +769,20 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) { pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
trace!("Locked shared state in `set_fullscreen`"); let mut shared_state_lock = self.lock_shared_state("set_fullscreen");
let mut shared_state_lock = self.shared_state.lock().unwrap();
if shared_state_lock.is_simple_fullscreen { if shared_state_lock.is_simple_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`");
return; return;
} }
if shared_state_lock.in_fullscreen_transition { if shared_state_lock.in_fullscreen_transition {
// 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); shared_state_lock.target_fullscreen = Some(fullscreen);
trace!("Unlocked shared state in `set_fullscreen`");
return; return;
} }
let old_fullscreen = shared_state_lock.fullscreen.clone(); let old_fullscreen = shared_state_lock.fullscreen.clone();
if fullscreen == old_fullscreen { if fullscreen == old_fullscreen {
trace!("Unlocked shared state in `set_fullscreen`");
return; return;
} }
trace!("Unlocked shared state in `set_fullscreen`");
drop(shared_state_lock); 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
@ -787,8 +835,7 @@ impl UnownedWindow {
if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) { if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) {
unsafe { unsafe {
let app = NSApp(); let app = NSApp();
trace!("Locked shared state in `set_fullscreen`"); let mut shared_state_lock = self.lock_shared_state("set_fullscreen");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.save_presentation_opts = Some(app.presentationOptions_()); 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.lock_shared_state("set_fullscreen");
let mut shared_state_lock = self.shared_state.lock().unwrap();
shared_state_lock.fullscreen = fullscreen.clone(); shared_state_lock.fullscreen = fullscreen.clone();
INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst); 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 // that the menu bar is disabled. This is done in the window
// delegate in `window:willUseFullScreenPresentationOptions:`. // delegate in `window:willUseFullScreenPresentationOptions:`.
let app = NSApp(); let app = NSApp();
trace!("Locked shared state in `set_fullscreen`");
shared_state_lock.save_presentation_opts = Some(app.presentationOptions_()); shared_state_lock.save_presentation_opts = Some(app.presentationOptions_());
let presentation_options = let presentation_options =
@ -918,7 +963,6 @@ impl UnownedWindow {
}, },
_ => INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst), _ => INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst),
}; };
trace!("Unlocked shared state in `set_fullscreen`");
} }
#[inline] #[inline]
@ -927,9 +971,7 @@ impl UnownedWindow {
self.decorations.store(decorations, Ordering::Release); self.decorations.store(decorations, Ordering::Release);
let (fullscreen, resizable) = { let (fullscreen, resizable) = {
trace!("Locked shared state in `set_decorations`"); let shared_state_lock = self.lock_shared_state("set_decorations");
let shared_state_lock = self.shared_state.lock().unwrap();
trace!("Unlocked shared state in `set_decorations`");
( (
shared_state_lock.fullscreen.is_some(), shared_state_lock.fullscreen.is_some(),
shared_state_lock.resizable, 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 { 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)); with_state(this, |state| state.emit_event(WindowEvent::CloseRequested));
trace!("Completed `windowShouldClose:`");
NO NO
} }
extern "C" fn window_will_close(this: &Object, _: Sel, _: id) { extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillClose:`"); trace_scope!("windowWillClose:");
with_state(this, |state| unsafe { with_state(this, |state| unsafe {
// `setDelegate:` retains the previous value and then autoreleases it // `setDelegate:` retains the previous value and then autoreleases it
autoreleasepool(|| { autoreleasepool(|| {
@ -282,47 +281,42 @@ extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
}); });
state.emit_event(WindowEvent::Destroyed); state.emit_event(WindowEvent::Destroyed);
}); });
trace!("Completed `windowWillClose:`");
} }
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidResize:`"); trace_scope!("windowDidResize:");
with_state(this, |state| { with_state(this, |state| {
state.emit_resize_event(); state.emit_resize_event();
state.emit_move_event(); state.emit_move_event();
}); });
trace!("Completed `windowDidResize:`");
} }
// This won't be triggered if the move was part of a resize. // This won't be triggered if the move was part of a resize.
extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidMove:`"); trace_scope!("windowDidMove:");
with_state(this, |state| { with_state(this, |state| {
state.emit_move_event(); state.emit_move_event();
}); });
trace!("Completed `windowDidMove:`");
} }
extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, _: id) { extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidChangeBackingProperties:`"); trace_scope!("windowDidChangeBackingProperties:");
with_state(this, |state| { with_state(this, |state| {
state.emit_static_scale_factor_changed_event(); state.emit_static_scale_factor_changed_event();
}); });
trace!("Completed `windowDidChangeBackingProperties:`");
} }
extern "C" fn window_did_become_key(this: &Object, _: Sel, _: id) { extern "C" fn window_did_become_key(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidBecomeKey:`"); trace_scope!("windowDidBecomeKey:");
with_state(this, |state| { with_state(this, |state| {
// TODO: center the cursor if the window had mouse grab when it // TODO: center the cursor if the window had mouse grab when it
// lost focus // lost focus
state.emit_event(WindowEvent::Focused(true)); state.emit_event(WindowEvent::Focused(true));
}); });
trace!("Completed `windowDidBecomeKey:`");
} }
extern "C" fn window_did_resign_key(this: &Object, _: Sel, _: id) { extern "C" fn window_did_resign_key(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidResignKey:`"); trace_scope!("windowDidResignKey:");
with_state(this, |state| { with_state(this, |state| {
// It happens rather often, e.g. when the user is Cmd+Tabbing, that the // It happens rather often, e.g. when the user is Cmd+Tabbing, that the
// NSWindowDelegate will receive a didResignKey event despite no event // 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)); state.emit_event(WindowEvent::Focused(false));
}); });
trace!("Completed `windowDidResignKey:`");
} }
/// Invoked when the dragged image enters destination bounds or frame /// Invoked when the dragged image enters destination bounds or frame
extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL { extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL {
trace!("Triggered `draggingEntered:`"); trace_scope!("draggingEntered:");
use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration}; use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
use std::path::PathBuf; use std::path::PathBuf;
@ -376,20 +369,18 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL {
} }
} }
trace!("Completed `draggingEntered:`");
YES YES
} }
/// Invoked when the image is released /// Invoked when the image is released
extern "C" fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) -> BOOL { extern "C" fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `prepareForDragOperation:`"); trace_scope!("prepareForDragOperation:");
trace!("Completed `prepareForDragOperation:`");
YES YES
} }
/// Invoked after the released image has been removed from the screen /// Invoked after the released image has been removed from the screen
extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { 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 cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
use std::path::PathBuf; use std::path::PathBuf;
@ -411,35 +402,31 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL
} }
} }
trace!("Completed `performDragOperation:`");
YES YES
} }
/// Invoked when the dragging operation is complete /// Invoked when the dragging operation is complete
extern "C" fn conclude_drag_operation(_: &Object, _: Sel, _: id) { extern "C" fn conclude_drag_operation(_: &Object, _: Sel, _: id) {
trace!("Triggered `concludeDragOperation:`"); trace_scope!("concludeDragOperation:");
trace!("Completed `concludeDragOperation:`");
} }
/// Invoked when the dragging operation is cancelled /// Invoked when the dragging operation is cancelled
extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) {
trace!("Triggered `draggingExited:`"); trace_scope!("draggingExited:");
with_state(this, |state| { with_state(this, |state| {
state.emit_event(WindowEvent::HoveredFileCancelled) state.emit_event(WindowEvent::HoveredFileCancelled)
}); });
trace!("Completed `draggingExited:`");
} }
/// Invoked when before enter fullscreen /// Invoked when before enter fullscreen
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { 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); INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
trace!("Locked shared state in `window_will_enter_fullscreen`"); let mut shared_state = window.lock_shared_state("window_will_enter_fullscreen");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.maximized = window.is_zoomed(); shared_state.maximized = window.is_zoomed();
match shared_state.fullscreen { match shared_state.fullscreen {
// Exclusive mode sets the state in `set_fullscreen` as the user // 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; shared_state.in_fullscreen_transition = true;
trace!("Unlocked shared state in `window_will_enter_fullscreen`");
}) })
}); });
trace!("Completed `windowWillEnterFullscreen:`");
} }
/// Invoked when before exit fullscreen /// Invoked when before exit fullscreen
extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { 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); INTERRUPT_EVENT_LOOP_EXIT.store(true, Ordering::SeqCst);
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
trace!("Locked shared state in `window_will_exit_fullscreen`"); let mut shared_state = window.lock_shared_state("window_will_exit_fullscreen");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = true; 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( extern "C" fn window_will_use_fullscreen_presentation_options(
@ -487,6 +469,7 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
_: id, _: id,
proposed_options: NSUInteger, proposed_options: NSUInteger,
) -> NSUInteger { ) -> NSUInteger {
trace_scope!("window:willUseFullScreenPresentationOptions:");
// Generally, games will want to disable the menu bar and the dock. Ideally, // Generally, games will want to disable the menu bar and the dock. Ideally,
// this would be configurable by the user. Unfortunately because of our // this would be configurable by the user. Unfortunately because of our
// `CGShieldingWindowLevel() + 1` hack (see `set_fullscreen`), our window is // `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; let mut options: NSUInteger = proposed_options;
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
trace!("Locked shared state in `window_will_use_fullscreen_presentation_options`"); let shared_state =
let shared_state = window.shared_state.lock().unwrap(); window.lock_shared_state("window_will_use_fullscreen_presentation_options");
if let Some(Fullscreen::Exclusive(_)) = shared_state.fullscreen { if let Some(Fullscreen::Exclusive(_)) = shared_state.fullscreen {
options = (NSApplicationPresentationOptions::NSApplicationPresentationFullScreen options = (NSApplicationPresentationOptions::NSApplicationPresentationFullScreen
| NSApplicationPresentationOptions::NSApplicationPresentationHideDock | NSApplicationPresentationOptions::NSApplicationPresentationHideDock
| NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar) | NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar)
.bits(); .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 /// Invoked when entered fullscreen
extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace_scope!("windowDidEnterFullscreen:");
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst); INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidEnterFullscreen:`");
with_state(this, |state| { with_state(this, |state| {
state.initial_fullscreen = false; state.initial_fullscreen = false;
state.with_window(|window| { state.with_window(|window| {
trace!("Locked shared state in `window_did_enter_fullscreen`"); let mut shared_state = window.lock_shared_state("window_did_enter_fullscreen");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false; shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take(); let target_fullscreen = shared_state.target_fullscreen.take();
trace!("Unlocked shared state in `window_did_enter_fullscreen`");
drop(shared_state); drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen { if let Some(target_fullscreen) = target_fullscreen {
window.set_fullscreen(target_fullscreen); window.set_fullscreen(target_fullscreen);
} }
}); });
}); });
trace!("Completed `windowDidEnterFullscreen:`");
} }
/// Invoked when exited fullscreen /// Invoked when exited fullscreen
extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) { extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) {
trace_scope!("windowDidExitFullscreen:");
INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst); INTERRUPT_EVENT_LOOP_EXIT.store(false, Ordering::SeqCst);
trace!("Triggered `windowDidExitFullscreen:`");
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
window.restore_state_from_fullscreen(); window.restore_state_from_fullscreen();
trace!("Locked shared state in `window_did_exit_fullscreen`"); let mut shared_state = window.lock_shared_state("window_did_exit_fullscreen");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false; shared_state.in_fullscreen_transition = false;
let target_fullscreen = shared_state.target_fullscreen.take(); let target_fullscreen = shared_state.target_fullscreen.take();
trace!("Unlocked shared state in `window_did_exit_fullscreen`");
drop(shared_state); drop(shared_state);
if let Some(target_fullscreen) = target_fullscreen { if let Some(target_fullscreen) = target_fullscreen {
window.set_fullscreen(target_fullscreen); window.set_fullscreen(target_fullscreen);
} }
}) })
}); });
trace!("Completed `windowDidExitFullscreen:`");
} }
/// Invoked when fail to enter fullscreen /// 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 /// 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. /// 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) { extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowDidFailToEnterFullscreen:`"); trace_scope!("windowDidFailToEnterFullscreen:");
with_state(this, |state| { with_state(this, |state| {
state.with_window(|window| { state.with_window(|window| {
trace!("Locked shared state in `window_did_fail_to_enter_fullscreen`"); let mut shared_state = window.lock_shared_state("window_did_fail_to_enter_fullscreen");
let mut shared_state = window.shared_state.lock().unwrap();
shared_state.in_fullscreen_transition = false; shared_state.in_fullscreen_transition = false;
shared_state.target_fullscreen = None; shared_state.target_fullscreen = None;
trace!("Unlocked shared state in `window_did_fail_to_enter_fullscreen`");
}); });
if state.initial_fullscreen { if state.initial_fullscreen {
let _: () = unsafe { 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()); state.with_window(|window| window.restore_state_from_fullscreen());
} }
}); });
trace!("Completed `windowDidFailToEnterFullscreen:`");
} }