diff --git a/gpui/src/platform/mac/platform.rs b/gpui/src/platform/mac/platform.rs index 29f75ed3ac..e7ccd280b4 100644 --- a/gpui/src/platform/mac/platform.rs +++ b/gpui/src/platform/mac/platform.rs @@ -347,7 +347,20 @@ impl platform::Platform for MacPlatform { } fn quit(&self) { + // Quitting the app causes us to close windows, which invokes `Window::on_close` callbacks + // synchronously before this method terminates. If we call `Platform::quit` while holding a + // borrow of the app state (which most of the time we will do), we will end up + // double-borrowing the app state in the `on_close` callbacks for our open windows. To solve + // this, we make quitting the application asynchronous so that we aren't holding borrows to + // the app state on the stack when we actually terminate the app. + + use super::dispatcher::{dispatch_async_f, dispatch_get_main_queue}; + unsafe { + dispatch_async_f(dispatch_get_main_queue(), ptr::null_mut(), Some(quit)); + } + + unsafe extern "C" fn quit(_: *mut c_void) { let app = NSApplication::sharedApplication(nil); let _: () = msg_send![app, terminate: nil]; } diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index 92d0503aeb..2475a59381 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -380,12 +380,15 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) { extern "C" fn close_window(this: &Object, _: Sel) { unsafe { - let window_state = get_window_state(this); - let close_callback = window_state - .as_ref() - .try_borrow_mut() - .ok() - .and_then(|mut window_state| window_state.close_callback.take()); + let close_callback = { + let window_state = get_window_state(this); + window_state + .as_ref() + .try_borrow_mut() + .ok() + .and_then(|mut window_state| window_state.close_callback.take()) + }; + if let Some(callback) = close_callback { callback(); }