gpui: Fix RefCell panic in thermal/keyboard state callbacks (#49187)
The `on_thermal_state_change` and `on_keyboard_layout_change` callbacks in `App::new_app()` called `borrow_mut()` unconditionally. These callbacks are invoked asynchronously by macOS via dispatch queues when the system's thermal or keyboard state changes, which can happen while the app's RefCell is already borrowed during an update cycle, causing a panic. This change uses `try_borrow_mut()` instead. If the borrow fails (because the app is already borrowed), the callback silently skips the update - the state can be queried on the next frame. Fixes [ZED-4WM](https://zed-dev.sentry.io/issues/ZED-4WM) Closes #49181 Release Notes: - Fixed a crash on macOS caused by thermal or keyboard layout state changes occurring during UI updates.
This commit is contained in:
1 parent
8c1ee9f2a3
commit
b69bbc2e0e
1 file changed
+16
-10
+16
-10
@@ -732,12 +732,15 @@ impl App {
|
||||
let app = Rc::downgrade(&app);
|
||||
move || {
|
||||
if let Some(app) = app.upgrade() {
|
||||
let cx = &mut app.borrow_mut();
|
||||
cx.keyboard_layout = cx.platform.keyboard_layout();
|
||||
cx.keyboard_mapper = cx.platform.keyboard_mapper();
|
||||
cx.keyboard_layout_observers
|
||||
.clone()
|
||||
.retain(&(), move |callback| (callback)(cx));
|
||||
// Use try_borrow_mut because this callback can be called asynchronously
|
||||
// from macOS while the app is already borrowed during an update.
|
||||
if let Ok(mut cx) = app.try_borrow_mut() {
|
||||
cx.keyboard_layout = cx.platform.keyboard_layout();
|
||||
cx.keyboard_mapper = cx.platform.keyboard_mapper();
|
||||
cx.keyboard_layout_observers
|
||||
.clone()
|
||||
.retain(&(), move |callback| (callback)(&mut cx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -746,10 +749,13 @@ impl App {
|
||||
let app = Rc::downgrade(&app);
|
||||
move || {
|
||||
if let Some(app) = app.upgrade() {
|
||||
let cx = &mut app.borrow_mut();
|
||||
cx.thermal_state_observers
|
||||
.clone()
|
||||
.retain(&(), move |callback| (callback)(cx));
|
||||
// Use try_borrow_mut because this callback can be called asynchronously
|
||||
// from macOS while the app is already borrowed during an update.
|
||||
if let Ok(mut cx) = app.try_borrow_mut() {
|
||||
cx.thermal_state_observers
|
||||
.clone()
|
||||
.retain(&(), move |callback| (callback)(&mut cx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Reference in new issue
Block a user