Instead of manually handing hiding the cursor on keyboard input at the
editor level, GPUI will now take care of it.
This makes it significantly easier to handle the edge cases, and allows
delegating the cursor restoration to the platform itself in the macOS
case. On Linux and Windows, we still have to restore the cursor on
movement ourselves, but this now happens at the platform-specific level.
Bugs fixed by this change:
- No cursor when "Unsaved edits" prompt appears
- Cursor disappears when clicking a panel button if it contains a search
bar (e.g. collab panel)
### Setting rename
The `hide_mouse` setting value `"on_typing_and_movement"` has been
renamed to `"on_typing_and_action"` to better reflect what it actually
does — it hides the cursor when a keystroke resolves to an action (e.g.
cursor movement, deletion). Existing settings are migrated
automatically.
### Tested platforms
- [x] macOS
- [x] Wayland
- [x] X11
- [x] Windows
- [x] Web
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Renamed the `hide_mouse` setting value `on_typing_and_movement` to
`on_typing_and_action` to better describe its behavior (existing
settings are auto-migrated)
- Fixed a few situations where the mouse cursor would be incorrectly
hidden
## Summary
- Add `unconfigure_surface()` and `replace_surface()` methods to
`WgpuRenderer` for mobile platform window lifecycle management
- Prefer `PresentMode::Mailbox` (triple-buffering) over `Fifo` to avoid
blocking during lifecycle transitions
- Early return in `draw()` when surface is unconfigured to prevent
driver hangs
## Motivation
On Android, the native window (`ANativeWindow`) is destroyed when the
app goes to the background and recreated when it returns to the
foreground. The same happens during orientation changes. Without surface
lifecycle methods, the only option is to destroy the entire
`WgpuRenderer` and create a new one on resume.
The problem: GPUI's scene cache holds `AtlasTextureId` references from
the old renderer's atlas. A new renderer has an empty atlas, so those
cached IDs cause index-out-of-bounds panics.
The fix: Keep the renderer (device, queue, atlas, pipelines) alive
across surface destruction. Only the wgpu `Surface` needs to be
replaced.
### `unconfigure_surface()`
Marks the surface as unconfigured so `draw()` skips rendering via the
existing `surface_configured` guard. Drops intermediate textures that
reference the old surface dimensions. The renderer stays fully alive.
### `replace_surface()`
Creates a new `wgpu::Surface` from fresh window handles using the
**same** `wgpu::Instance` that created the original adapter/device.
Reconfigures the surface and marks it as configured so rendering
resumes. All cached atlas textures remain valid.
### PresentMode::Mailbox
`Fifo` (VSync) blocks in `get_current_texture()` and can deadlock if the
compositor is frozen during a lifecycle transition (e.g.
`TerminateWindow` → `InitWindow` on Android). Mailbox (triple-buffering)
avoids this. Falls back to `AutoNoVsync` → `Fifo` if unsupported.
### draw() early return
Some drivers (notably Adreno) block indefinitely when acquiring a
texture from an unconfigured surface. The early return prevents this.
## Context
This is needed by
[gpui-mobile](https://github.com/itsbalamurali/gpui-mobile), a project
bringing GPUI to Android and iOS. The Android implementation needs these
methods to handle:
1. **Background/foreground transitions** — `TerminateWindow` destroys
the native window, `InitWindow` recreates it
2. **Orientation changes** — Surface is destroyed and recreated with new
dimensions
3. **Split-screen transitions** — Similar surface recreation
Without this change, we maintain a local fork of `gpui_wgpu` with just
these additions. Upstreaming them would let mobile platform
implementations use the official crate directly.
## Test plan
- [x] Tested on Android (Motorola, Adreno 720 GPU) — 3 consecutive
background/foreground cycles, zero panics, atlas textures preserved
- [x] Tested orientation changes (portrait→landscape→portrait) — surface
replacement completed in <40ms per rotation
- [x] Verified `draw()` correctly skips rendering when surface is
unconfigured
- [x] Verified no regression on desktop — methods are additive, existing
code paths unchanged
- [x] PresentMode fallback chain works on devices that don't support
Mailbox
## Release Notes
- N/A
Currently the web backend for gpui doesn't send any events to the
`InputHandler`'s like `EntityInputHandler` which are needed for the
input example and the editor crate, among others. This PR makes it pass
those events, in addition to also dealing with composition events so
that IME works. It adds an invisible input element to listen for
composition events, since canvases don't receive them.
Release Notes:
- N/A
Co-Authored-By: Eric Holk <eric@zed.dev>
In app drop we had been calling `.close()` on the executors. This caused
problems with the BackgroundExecutor on Linux because it raced with
concurrent work: If task A was running and about to poll task B, the
poll to task B would panic with "Task polled after completion". This
didn't really matter (because the app was shutting down anyway) but
inflated our panic metrics on Linux.
It turns out that the call to `.close()` is not needed. It was added to
prevent foreground tasks being scheduled after the app was dropped; but
on all platforms the App run method does not return until after the
ForegroundExecutor is stopped (so no further tasks will run anyway).
The background case is more interesting. In test code it didn't matter
(the background executor is simulated on the main thread so tests can't
leak tasks); in app code it also didn't really make a difference. When
`fn main` returns (which it does immediately after the app is dropped)
all the background threads will be cancelled anyway.
Further confounding debugging, it turns out that the App does not get
dropped on macOS and Windows due to a reference cycle; so this was only
happening on Linux where the app quit callback is dropped instead of
retained after being called. (Fix in #50985)
Release Notes:
- N/A
---------
Co-authored-by: Eric Holk <eric@zed.dev>
Fixes a crash which occurred on firefox-linux when resizing (and was
causing blanks during resize in other browsers)
The issue was due to attempting to resize the drawing buffer while it
was being rendered to, which causes a browser crash since firefox
destroys that buffer while it is still being accessed. This essentially
defers the resize to just before drawing, so that it won't be resized
*while* being drawn to.
Release Notes:
- N/A
Implements a basic web platform for the wasm32-unknown-unknown target
for gpui
Release Notes:
- N/A *or* Added/Fixed/Improved ...
---------
Co-authored-by: John Tur <john-tur@outlook.com>