From 2c59293b69889610eba8f54920cca64c387308ba Mon Sep 17 00:00:00 2001 From: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com> Date: Mon, 16 Feb 2026 08:34:47 +0100 Subject: [PATCH] gpui: Fix thermal state notifications on intel macOS (#49086) Fixes https://github.com/zed-industries/zed/pull/45638#issuecomment-3893732034 Closes #49005 The issue was similar to the one we already had with the quit method https://github.com/zed-industries/zed/blob/8249ef56187b966c33f6667d0d3a35d88d8f2dc0/crates/gpui/src/platform/mac/platform.rs#L491 @notpeter Could you please test this branch to confirm it resolves the issue? - [ ] Tests or screenshots needed? - [x] Code Reviewed - [ ] Manual QA Release Notes: - Fixed an issue where Zed would randomly crash on macOS intel --- crates/gpui/src/platform/mac/platform.rs | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 310c8958452eca0e67f0cc65720cf49224c78fb0..c990042a6e3d02f6284f14dc77b348bd8a6addf7 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); + } } }