diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 041a914251127b202cd29d4ae773c4eaef12964a..57848f8ddce8862652f94f711ff46bf95f535d99 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1258,16 +1258,33 @@ extern "C" fn on_keyboard_layout_change(this: &mut Object, _: Sel, _: id) { } extern "C" fn on_thermal_state_change(this: &mut Object, _: Sel, _: id) { + // Defer to the next run loop iteration to avoid re-entrant borrows of the App RefCell, + // as NSNotificationCenter delivers this notification synchronously and it may fire while + // the App is already borrowed (same pattern as quit() above). + use super::dispatcher::{dispatch_get_main_queue, dispatch_sys::dispatch_async_f}; + let platform = unsafe { get_mac_platform(this) }; - let mut lock = platform.0.lock(); - if let Some(mut callback) = lock.on_thermal_state_change.take() { - drop(lock); - callback(); - platform - .0 - .lock() - .on_thermal_state_change - .get_or_insert(callback); + let platform_ptr = platform as *const MacPlatform as *mut c_void; + unsafe { + dispatch_async_f( + dispatch_get_main_queue(), + platform_ptr, + Some(on_thermal_state_change), + ); + } + + unsafe extern "C" fn on_thermal_state_change(context: *mut c_void) { + let platform = unsafe { &*(context as *const MacPlatform) }; + let mut lock = platform.0.lock(); + if let Some(mut callback) = lock.on_thermal_state_change.take() { + drop(lock); + callback(); + platform + .0 + .lock() + .on_thermal_state_change + .get_or_insert(callback); + } } }