Fix double borrow error in Window::on_close callbacks when quitting app

The simplest solution I could come up with was to make quitting the app asynchronous. Calling mac::Platform::quit enqueues a request to quit the app and then allows the call stack to fully return. This ensures we aren't holding a borrow when we quit and invoke all the Window::on_close callbacks. Seems like it should be fine to be async on quitting.
This commit is contained in:
Nathan Sobo 2021-05-08 08:49:14 -06:00
parent b292baf334
commit 2c74d75687
2 changed files with 22 additions and 6 deletions

View file

@ -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];
}

View file

@ -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();
}