Skip to content

gpui(linux): Fix RefCell borrow panic when callbacks register new callbacks#49533

Merged
ConradIrwin merged 2 commits intozed-industries:mainfrom
cardinalpointstudio:fix/gpui-linux-refcell-callback-panic
Feb 25, 2026
Merged

gpui(linux): Fix RefCell borrow panic when callbacks register new callbacks#49533
ConradIrwin merged 2 commits intozed-industries:mainfrom
cardinalpointstudio:fix/gpui-linux-refcell-callback-panic

Conversation

@cardinalpointstudio
Copy link
Copy Markdown
Contributor

@cardinalpointstudio cardinalpointstudio commented Feb 18, 2026

Summary

Fixes RefCell borrow panic on Linux (Wayland and X11) when callbacks try to register new callbacks.

Root cause: Linux GPUI backends invoked callbacks while still holding a RefCell borrow on the Callbacks struct. If a callback tried to register a new
callback (e.g., on_window_should_close), it would panic with "already borrowed: BorrowMutError".

Bug pattern:

// Callback runs while borrow is held - panics if callback borrows callbacks
if let Some(ref mut fun) = self.callbacks.borrow_mut().input {
    fun(input);
}

Fix: Apply the take-call-restore pattern (already used in macOS backend):
// Take callback out, release borrow, call, restore
let callback = self.callbacks.borrow_mut().input.take();
if let Some(mut fun) = callback {
    let result = fun(input);
    self.callbacks.borrow_mut().input = Some(fun);
}

Changes

- Wayland (window.rs): Fixed 6 callback invocations
- X11 (window.rs): Fixed 4 callback invocations

Test plan

- cargo check -p gpui compiles successfully
- Tested on Linux (Wayland) - no more RefCell panic

Release Notes:

- Fixed a crash on Linux when window callbacks attempted to register new callbacks

@cardinalpointstudio cardinalpointstudio requested a review from a team as a code owner February 18, 2026 22:46
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Feb 18, 2026
@zed-community-bot zed-community-bot bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Feb 18, 2026
@mikayla-maki
Copy link
Copy Markdown
Member

while I think this is a correct change, there’s a deeper problem here that every workspace is rebinding a window-level event. This should be hoisted up to the multiworkspace.

…lbacks

On Linux (Wayland and X11), callbacks were invoked while the Callbacks
RefCell was still borrowed. If a callback tried to register a new
callback (e.g., on_window_should_close during workspace creation), it
would panic with "already borrowed".

The bug pattern was:
```rust
if let Some(ref mut fun) = self.callbacks.borrow_mut().input {
    fun(input);  // Panics if fun() tries to borrow_mut() callbacks
}
```

Fix by using take-call-restore pattern (matching macOS implementation):
```rust
let callback = self.callbacks.borrow_mut().input.take();
if let Some(mut fun) = callback {
    let result = fun(input);
    self.callbacks.borrow_mut().input = Some(fun);
}
```

Fixed locations:
- Wayland: handle_toplevel_decoration_event (2x), set_size_and_scale,
  handle_input, set_focused, set_hovered, set_appearance
- X11: refresh, handle_input, set_active, set_hovered, set_appearance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cardinalpointstudio cardinalpointstudio force-pushed the fix/gpui-linux-refcell-callback-panic branch from 4e0238d to f2897a3 Compare February 19, 2026 19:37
@ConradIrwin ConradIrwin removed the request for review from a team February 25, 2026 16:09
@ConradIrwin ConradIrwin enabled auto-merge (squash) February 25, 2026 16:10
@ConradIrwin ConradIrwin merged commit 533cdb8 into zed-industries:main Feb 25, 2026
27 checks passed
tahayvr pushed a commit to tahayvr/zed that referenced this pull request Mar 4, 2026
…lbacks (zed-industries#49533)

## Summary

Fixes RefCell borrow panic on Linux (Wayland and X11) when callbacks try
to register new callbacks.

**Root cause:** Linux GPUI backends invoked callbacks while still
holding a `RefCell` borrow on the `Callbacks` struct. If a callback
tried to register a new
callback (e.g., `on_window_should_close`), it would panic with "already
borrowed: BorrowMutError".

  **Bug pattern:**
  ```rust
// Callback runs while borrow is held - panics if callback borrows
callbacks
  if let Some(ref mut fun) = self.callbacks.borrow_mut().input {
      fun(input);
  }

Fix: Apply the take-call-restore pattern (already used in macOS
backend):
  // Take callback out, release borrow, call, restore
  let callback = self.callbacks.borrow_mut().input.take();
  if let Some(mut fun) = callback {
      let result = fun(input);
      self.callbacks.borrow_mut().input = Some(fun);
  }

  Changes

  - Wayland (window.rs): Fixed 6 callback invocations
  - X11 (window.rs): Fixed 4 callback invocations

  Test plan

  - cargo check -p gpui compiles successfully
  - Tested on Linux (Wayland) - no more RefCell panic

  Release Notes:

- Fixed a crash on Linux when window callbacks attempted to register new
callbacks

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants