3678 Commits
Author SHA1 Message Date
yenru0 fe62a99bf5 gwen: Purge remaining Zed branding from user-facing surfaces
Sweep every user-visible product string to Gwen: app menus (Quit,
Hide, Gwen Repository), feedback links (repo/issues now point at
github.com/kk376/zed, email to yenru@yrkaierx.com), move-to-Applications
and update dialogs, provider and settings copy, CLI help, installer and
desktop/flatpak/snap/plist metadata.

Rename user-facing settings values with back-compat aliases: base_keymap
"Gwen" (accepts "Zed"), fonts ".GwenMono"/".GwenSans" (accept
".ZedMono"/".ZedSans"), icon theme "Gwen (Default)". Fix F10
app-menu keymap arguments to "Gwen" and align the Windows installer
AppMutex with release_channel::app_identifier(). Internal identifiers,
wire protocol names, upstream service URLs and legal attribution are
intentionally kept.
2026-09-29 09:24:34 +09:00
Kirill Bulatov 1753d7f52b Share GPUI and scheduler implementations (#64261)
Move GPUI window/entity updates, view rendering, listener adapters,
arena allocation, and scheduler task setup into shared implementations.
Keep the generic entry points as thin adapters.

Uses pretty much the same technique prior PRs did, but this time on
`gpui` which I am not too confident about — can close it if seems
dangerous, but the binary strip win looks good to try.

`cargo llvm-lines --locked -p gpui`:
Before (bec63dee23): 934803 lines, 33225 copies
After: 926925 lines (-0.8%), 33454 copies (+0.7%)

With compiler wrappers disabled, `cargo clean --target-dir
target/binary-size-split-build` and `cargo build --locked -p zed`:
Before: 135.6s wall, 1569.8s CPU, zed binary 1175563800 bytes 
After: 142.5s wall (+5.1%), 1589.0s CPU (+1.2%), zed binary 1144068952
bytes (-2.7%, -31.5MB)

Release Notes:

- N/A
- [GPUI] Shared GPUI and scheduler implementations to reduce the final
binary size of the app
2026-09-18 10:50:41 +00:00
Cameron Mcloughlin 3eddbb7f4e gpui: Fix debug selectors with cached views (#64433)
The debug-selector test mapping skipped cached views that weren't
rendered. Make sure we include them

---

Release Notes:

- [GPUI] N/A
2026-09-18 07:42:25 +00:00
zooeywmandChris Biscardi 42038d0b14 gpui: Fix manifest path for cross-compilation (#62525)
# Objective

Fixes #62522

`cargo xwin` fails to find the GPUI Windows manifest because `llvm-rc`
resolves the path from the resource directory.

## Solution

Reference the manifest relative to `gpui.rc` and explicitly add the
resource directory to the include paths. This keeps both native Windows
and xwin builds working.

## Testing

- Tested with `cargo xwin clippy --target x86_64-pc-windows-msvc`

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- N/A
- [GPUI] N/A

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-09-17 17:38:24 +00:00
Habis AhmadandChris Biscardi 2c8f682cd5 gpui: Fix centered window bounds to display settings header (#62073)
# Objective

- Fixes https://github.com/zed-industries/zed/issues/61914 
- The setting window gets cut off from the top of the screen when using
a high DP on Windows (e.g. 250% 2560×1600). This is because
`Bounds::centered` computes a wide rectangle with `origin =
display.center() - size / 2` which can cause issues on higher DPI.
## Solution

`Bounds::centered` now centers within the display's work area. 
```rust
let visible_bounds = display.visible_bounds();
Bounds::centered_at(visible_bounds.center(), size.min(&visible_bounds.size))
```
Added visible_bounds() and size.min(&visible_bounds.size). Size::min
will clamp each axis, windows that already fit are unaffected

## Testing

- Reproduced the bug locally and on production that the settings header
does not get clipped anymore; the video showcase shows this.

## 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 adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase


https://github.com/user-attachments/assets/5cafd03c-7835-488c-a70b-ba559e4cfff3

0:00 - 0:11. Current behaviour in production, settings header gets
clipped at 225%
0:11 - 0:20. My fix, header does not get clipped


Release Notes:

- Fixed the Settings window opening with its header off-screen at high
DPI scaling on Windows
- [GPUI] N/A

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-09-17 16:42:31 +00:00
Finn Evers 20d55798db Fix cargo shear warnings (#64340)
Also updates CI to always run this - that way we ensure that disabling
or enabling tests does not become stale at some point and thus can
safely add this.

Release Notes:

- N/A
- [GPUI] N/A
2026-09-17 08:49:31 +00:00
Finn Evers 26fb9817c4 gpui: Improve PlatformAtlas::get_or_insert_with (#64331)
Stumbled across this during a recent review:

At all of the call sites in prod code, we would clone, then into, then
pass by ref, and then immediately clone again in `get_or_insert_with`
when the texture was not found.

Instead, changed the API to now take an owned `AtlasKey` to make better
use of the cloning.

As a second step, went ahead and added a generic `AtlasState`, as I
noticed all atlases shared some similar logic around keeping track of
the tiles. With this restructing, we reuse some code across different
backends, but more importantly, get rid of an additional hashmap lookup
by instead using the `Entry` API.

Release Notes:

- N/A
- [GPUI] N/A
2026-09-17 08:24:25 +00:00
tidely 85b8aa5898 gpui_macos: Migrate screen capture to objc2 (#64251)
# Objective

Get rid of instances of the `block` crate, as it will not compile in a
future version of Rust. This gets rid of the `block` crate inside of
`gpui_macos`, which means were on the home stretch.

## Solution

Migrate `screen_capture.rs` completely to `objc2`. While a more targeted
fix is theoretically possible, there were enough upsides where I thought
this was worth a full migration.

Completely gets rid of the `media` crate, which had manual bindings to
`core_media`, which `objc2` can provide. Gets rid of tons of unsafe
code, and a lot of code in general.

## Testing

Tested manual sharing inside of a Zed channel

Release Notes:

- N/A
- [GPUI] Migrated macOS screen capture to `objc2`
2026-09-17 01:46:02 +00:00
9a606bc84c editor: Render point diagnostics without glyphs (#63933)
Closes #63084.

Zed already normalizes most empty and line-terminator-only diagnostic
ranges onto an adjacent character. A diagnostic can still remain a true
point when its position has no glyph, such as column zero of an empty
line or an empty file. The shaped-text path has no `TextRun` at that
position, so the diagnostic appears in diagnostic UI but has no editor
squiggle.

Render only diagnostics that remain zero-width after ingress as a one-em
wavy underline at their `DisplayPoint`. This keeps the stored LSP range
unchanged, uses the existing diagnostic underline policy and font
metrics, and also paints the decoration in a pinned sticky-header copy
when an anchored point survives an edit.

## Evidence

### Empty Go file with gopls

Before:

<img width="471" height="430" alt="Empty Go file before the fix:
diagnostic message without a squiggle"
src="https://github.com/user-attachments/assets/a7f29dd3-a16c-43ea-a53f-d0264efb4ce0"
/>

After:

<img width="471" height="430" alt="Empty Go file after the fix:
diagnostic message with a point squiggle"
src="https://github.com/user-attachments/assets/0546970a-e24e-4e15-a764-d548291eb623"
/>

`gopls` reports `expected ';', found 'EOF'` at `(0,0)..(0,0)` for the
empty file. The diagnostic message is present in both builds; only the
patched build paints the point squiggle.

Sticky-header behavior was also verified with a deterministic stdio LSP.
Before/after recordings are included in the review response below.

## Validation

- `cargo test -p editor point_diagnostic`
- `cargo test -p editor test_point_diagnostic_stays_in_edited_excerpt`
- `cargo test -p editor
test_point_diagnostics_follow_expanded_deletions`
- `cargo test -p project test_empty_diagnostic_ranges`
- `cargo test -p project test_diagnostic_range_spanning_line_terminator`
- `cargo fmt --all -- --check`
- `CCACHE_TEMPDIR=/tmp/zed-ccache-tmp ./script/clippy -p editor -p gpui
-p multi_buffer -p project`
- `git diff --check`
- Manual before/after verification with gopls on an empty Go file
- Manual before/after verification of a retained point diagnostic in a
sticky header
- Manual Fedora verification of physical overlap handling with
`.ZedMono` and proportional Jomolhari text

Regression coverage also includes retained point diagnostics across
edited excerpt boundaries and expanded deleted diff hunks at the
beginning, middle, and EOF, including an empty live buffer, plus
painted-span severity arbitration for point-vs-range and point-vs-point
overlaps.

Release Notes:

- Fixed missing editor underlines for language server diagnostics at
positions without underlying text.
- [GPUI] N/A

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
2026-09-16 16:04:28 +00:00
Kirill Bulatov 5e04c64b52 Optimize GPUI inspector's runtime cost by an order of magnitude (#64309)
Prerequisite to https://github.com/zed-industries/zed/pull/64257

* gpui: build inspector IDs only when the window's inspector exists,
drop the inspector maps on close, skip inspector state lookups for
absent or non-selected IDs
* gpui: create inspector element renderers per inspector instance
instead of at registration
* inspector_ui: create the project and editors lazily per inspector
session, keep the init task and subscriptions cancellable, hold the
inspector weakly from the completion provider
* lsp: bound the shutdown output drain by the same timeout as the
shutdown request
* gpui_platform: add an `inspector_render` benchmark that builds with
the inspector in or out

Mean time per rendered frame with the inspector closed; overhead is
relative to the inspector compiled out.

| Benchmark | Frame, compiled out | Frame, `main` | Frame, this PR |
Overhead on `main` | Overhead on this PR |
| --- | ---: | ---: | ---: | ---: | ---: |
| 1,000 bare divs, never opened | 3.352 ms | 3.505 ms | 3.362 ms | +153
µs (+4.57%) | +10 µs (+0.29%) |
| 1,000 bare divs, opened and closed twice | 3.349 ms | 3.508 ms | 3.364
ms | +159 µs (+4.76%) | +15 µs (+0.46%) |
| 100 bare divs, opened and closed twice | 317.0 µs | 336.3 µs | 317.6
µs | +19 µs (+6.10%) | +1 µs (+0.18%) |
| 10,000 bare divs, never opened | 56.617 ms | 58.925 ms | 56.472 ms |
+2.31 ms (+4.08%) | -145 µs (-0.26%) |
| 500 panel rows with text, hover, click, never opened | 4.173 ms |
4.451 ms | 4.179 ms | +278 µs (+6.67%) | +7 µs (+0.16%) |
| 500 panel rows with text, hover, click, opened and closed twice |
4.197 ms | 4.448 ms | 4.159 ms | +252 µs (+6.00%) | -37 µs (-0.89%) |
| 50 panel rows with text, hover, click, never opened | 523.4 µs | 543.3
µs | 522.3 µs | +20 µs (+3.80%) | -1 µs (-0.21%) |
| 500 panel rows with text, hover, click, opened and closed twice,
another window inspected | 4.191 ms | 4.469 ms | 4.176 ms | +278 µs
(+6.64%) | -15 µs (-0.35%) |
| editor, cursor moves (`crates/benchmarks`, `release-fast`) | 940.9 µs
| 943.0 µs | 942.5 µs | +2 µs (+0.23%) | +2 µs (+0.17%) |




Release Notes:

- N/A
- [GPUI] Optimize GPUI inspector's runtime cost by an order of magnitude
2026-09-16 16:02:58 +00:00
Anthony Eid 04d586b80e gpui: Make ForegroundJournal aware of sleep and window visibility (#64269)
## Summary

Keep foreground-work measurements and per-window presentation
expectations valid across observed sleep/wake and visibility changes.
Simplified after review to about 530 changed lines including tests and
configuration.

## Scope

- Keep all measurement state in the foreground-local journal writer. Use
`PowerState` and `PowerTransition`; no new locks, counters, or changes
to the ring protocol.
- Work that started at or before the last power transition (or while
suspended) is dropped when it completes: task polls before small-poll
folding, and actions, inputs, draws, and presents through the same
`power_interrupted_since(start)` check. No per-activity state is added;
every measurement already carries its start time.
- Track visibility and pending frames together per window. Hiding or
sleeping clears the presentation expectation; on recovery
`Window::refresh_visibility` re-records it from the window's actual
dirty state, so the journal never guesses. Old latency associations
remain invalid.
- Repeated notifications for the same power state are ignored, so a
duplicate wake does not invalidate in-flight work.
- The journal subscribes to GPUI's existing power notifications and
rechecks native window visibility after wake. App only registers these
subscriptions (two initialization lines).
- Keep the existing one-second pending-frame deadline and
foreground-turn sealing behavior. No watchdog, recurring timer, test-app
exceptions, unfinished-hang detection, start/end ring notices, or
reader-side deduplication.
- Remove lifecycle counters. Keep measurement version 2 on reports and a
valid dirty-to-present sample count for weighting averages.

## Telemetry

- `Hang Incidents` gains `report_window_seconds` and stall percentiles
over every incident in the window (`stall_p50_ms`, `stall_p95_ms`,
`stall_max_ms`, from an `hdrhistogram`), so stall distributions no
longer depend on the censored `incidents[]` list. Reports are now sent
even when no incident occurred, so summing `report_window_seconds` gives
observed running time for incident rates.
- `Frame Duration Report` gains dirty-to-present percentiles
(`dirty_to_present_p50_ms`, `dirty_to_present_p95_ms`,
`dirty_to_present_max_ms`) alongside the existing average, and
`average_present_interval_ms` (mean frame-to-frame interval while
animating, a proxy for the display's refresh interval when normalizing
dirty-to-present).

Detection remains completion-based. This does not solve hangs that never
return or force an interval to seal when no further foreground events
arrive. Existing legacy hang logs/trace triggers are unchanged. Late or
coalesced platform notifications remain a coverage limitation.

## Validation

- `corgi test -p gpui --features profiler --lib`: **392 tests passed**.
- Focused lifecycle/wake tests also passed a 20-seed run.
- The extension-suggestion regression that failed on all three CI
platforms now passes locally after removal of the
watchdog/test-construction changes.
- `corgi check -p gpui` and `corgi check -p zed -p input_latency_ui`
passed.
- Formatting and `git diff --check` passed.
- Corgi configuration includes only the three existing GPUI image/font
fixtures needed to run its tests.

Native platform sleep/wake testing and review remain outstanding. The
README review marker remains for the human author to remove manually
after review.

Release Notes:

- Improved the accuracy of hang and frame-latency telemetry around
sleep, wake, and hidden windows.
- [GPUI] Added a `PowerTransition` interval boundary and
`measurement_version` to profiler hang reports.
2026-09-16 16:00:19 +00:00
Antonio Scandurra 2e31de1c44 gpui: Avoid main-thread waits when unlocking web task queues (#64298)
## Problem

GPUI's web dispatcher already uses `spin_send` and `spin_try_pop` on the
browser main thread. Those operations spin on `try_lock()` instead of
blocking while acquiring the queue mutex. However, that does **not**
make releasing a `parking_lot` mutex safe on that thread.

When a worker is waiting for the queue mutex, dropping the main thread's
guard follows this path:

```text
RawMutex::unlock_slow
  → parking_lot_core::unpark_one
    → lock_bucket
      → WordLock::lock_slow
        → ThreadParker::park
          → memory.atomic.wait32
```

`unpark_one` first locks the internal table used to locate sleeping
threads. If another thread holds that bucket lock, the caller can itself
park before reaching the actual wake instruction. See
[`unpark_one`](https://github.com/Amanieu/parking_lot/blob/d7828fff7b5d6327ae608e82db45f888b344449a/core/src/parking_lot.rs#L732-L737),
[`lock_bucket`](https://github.com/Amanieu/parking_lot/blob/d7828fff7b5d6327ae608e82db45f888b344449a/core/src/parking_lot.rs#L358-L366),
and [`WordLock`'s park
call](https://github.com/Amanieu/parking_lot/blob/d7828fff7b5d6327ae608e82db45f888b344449a/core/src/word_lock.rs#L163-L168).

Browsers forbid synchronous atomic waits on the main thread. Chromium
reports `Atomics.wait cannot be called in this context`; Safari can
misleadingly report an out-of-bounds memory access. Ordinary UI activity
can encounter this contention while scheduling background work; no
explicit blocking operation by the application is required.

## Why `std` fixes it

For **atomics-enabled Wasm**, Rust's standard-library mutex uses a futex
directly. Unlocking changes the mutex state with an atomic swap and, if
needed, calls `memory.atomic.notify`. Its condition-variable
notification similarly increments an atomic notification counter and
calls `memory.atomic.notify`. Neither operation acquires a secondary
waiter-table lock or performs an atomic wait.

A contended `std::Mutex::lock()` would still be unsafe on the browser
main thread, so this change **retains the existing `try_lock()` spin
loops**. Workers retain ordinary blocking acquisition and
condition-variable waiting. This relies on the Wasm backend's
implementation, not a portable guarantee that standard mutex operations
never block on every platform.

The production change only replaces the queue synchronization primitives
and adapts their APIs. The high/medium/low queues, weighted selection,
queue methods, and disconnect behavior are unchanged. Poisoned guards
are recovered to preserve the previous non-poisoning behavior. The
main-thread-only mailbox receiver also uses a standard mutex with
`try_lock()` so an unexpected acquisition cannot park it.

## Regression test and verification

One browser/Wasm stress test exchanges work and replies between the
actual browser main thread and configurable `N` Web Workers. It checks
exact-once delivery, cycles between idle and busy queues, and waits for
all workers to stop. An explicit Wasm wait is a negative control
confirming that the main thread rejects waits; a deadline outside the
page detects hangs.

- **Fix stashed:** rebuilt and ran the test against the original queue.
It failed with `Atomics.wait cannot be called in this context`, with
`WordLock::lock_slow → RawMutex::unlock_slow → spin_send` in the stack.
- **Fix restored:** rebuilt and ran the unchanged test with **8 and 16
workers**. Both passed, each exchanging **524,288 items over 128
rounds**.
- Both existing native queue tests passed. Shared-memory Wasm
compilation, Rust formatting, JavaScript syntax, and diff checks passed.
- Browser execution was verified in Chromium, not directly on an iOS
Safari device. This does not update any downstream application's pinned
GPUI dependency.

The test is available through the existing `hello_web` gallery:

```sh
node crates/gpui_web/examples/hello_web/test_queue.mjs http://127.0.0.1:8080 8
```

For the recorded runs, the fixture was built directly with the gallery's
shared-memory flags, `nightly-2026-07-01`, and matching wasm-bindgen
0.2.120, then served with COOP/COEP headers.

## Suggested .rules additions

For code running on the browser main thread, audit mutex unlock and
notification paths as well as acquisition: using `try_lock()` does not
guarantee that releasing the guard cannot park.

Release Notes:

- [GPUI] N/A
2026-09-16 13:17:03 +00:00
Finn Evers 8e20f12347 Remove ztracing dependency from GPUI (#64237)
Release Notes:

- N/A
2026-09-15 12:52:48 +00:00
Cameron Mcloughlin 4d0d1f1835 gpui: Remove mutex from dynamic font loading (#64204)
Dynamic font loading is useful on web, but locked a mutex on the main
thread. This PR removes that

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-14 23:49:34 +00:00
Lukas WirthandMax Brunsfeld 00e0676e5e gpui: Support dynamic font installation (#63498)
Browser applications cannot rely on operating-system font discovery, but
embedding comprehensive emoji and CJK fonts makes the initial
WebAssembly payload prohibitively large. GPUI previously offered no
structured way to learn that fallback was exhausted, and adding a font
at runtime left descriptor and line-layout caches shaped against the old
font database.

This change lets WGPU text systems report unresolved grapheme clusters
through `App::on_missing_glyphs`. GPUI invokes one replaceable
application callback after shaping, carrying each complete grapheme and
whether its source run is proportional or monospace. Reports are
deduplicated and delivered through a bounded, nonblocking channel;
reporting remains disabled until the callback is installed, and queued
reports from an earlier font generation are discarded.

Successful font installation now advances a font generation. GPUI clears
descriptor and platform family resolution, reuses stable font IDs for
unchanged faces while refreshing their fallback chains, and invalidates
each window's current and previous line-layout caches when it observes
the new generation. This supplies the GPUI half of an on-demand web font
loader; fetching and selecting font assets remains application-owned.

Release Notes:

- N/A

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2026-09-14 21:18:17 +00:00
Max Brunsfeld 3e14bae23e Fix Trunk link in GPUI examples documentation (#64192)
## Summary

- Replace the outdated Trunk URL in the GPUI examples README with
https://trunk-rs.github.io/trunk/.

## Verification

- Confirmed the replacement URL returns HTTP 200.
- Ran `git diff --check` successfully.
- No code tests needed for this documentation-only link change.

Release Notes:

- N/A
2026-09-14 16:38:51 +00:00
Bennet Bo Fenner 457d22be3a gpui: Add ShapedLineCursor API (#64185)
Release Notes:

- N/A
2026-09-14 14:38:54 +00:00
Giorgi MerebashviliandMrSubidubi d643da9c3b project_panel: Add Menu key support to project panel context menu (#46744)
Closes #45783 

`Menu` key or `Shift + F10` shortcut wasn't supported in project panel
for opening the context menu, this PR fixes it.

Release Notes:
- Added an action and default keyboard shortcuts to open the context
menu in the project panel. You can now bind
`project_panel::OpenContextMenu` to deploy the context menu at the
currently selected entry in the panel.

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
2026-09-14 12:03:12 +00:00
Max Brunsfeld abc6b3b357 gpui: Add Canvas font fallback for web text (#64110)
## Summary

Add browser-font fallback to GPUI on the web, so applications can render
emoji using the user’s local fonts without bundling an emoji font.

GPUI continues to shape text with Cosmic Text using application-provided
fonts. When those fonts cannot supply an eligible grapheme or its
requested emoji presentation, the web backend measures and rasterizes
the complete grapheme using Canvas 2D, then caches and paints the result
through GPUI’s existing glyph atlas.

### Configurable fallback

- **Emoji-only by default**, including supported variation-selector,
skin-tone, flag, keycap, and ZWJ sequences.
- Applications can opt into **CJK fallback** for a conservative subset
of horizontal Han, kana, and modern Hangul text.
- Applications can disable Canvas fallback entirely.

CJK fallback renders graphemes independently. It prioritizes readable
text over full fidelity to contextual spacing and font features. Browser
font coverage and appearance depend on the user’s environment.

### Web input and application lifecycle

- Fix text insertion that arrives without a corresponding keyboard
event, allowing emoji input through the browser’s text-input path.
- Keep the GPUI application alive after `Application::run` returns on
WebAssembly. Browser startup is asynchronous; releasing the application
after the startup callback previously caused the window to disappear.

### Browser example gallery

Make the existing GPUI examples available from a single development
server, with separate routes for hello world, styled text, text layout,
wrapping, input, and the prime sieve demo.

The gallery supports direct links and reloads, loads only the selected
example, and provides a simple way to exercise font fallback and text
input.

## Validation

- Native unit tests cover fallback eligibility and presentation, policy
defaults, glyph-cache reuse, and in-place glyph-run replacement.
- All six gallery binaries pass WASM compilation checks.
- Browser smoke coverage exercises emoji insertion, whole-grapheme
Canvas rendering, cache reuse, and deletion.
- Manually exercised the gallery and fallback rendering in Chrome.

Release Notes:

- N/A
2026-09-12 20:38:07 +00:00
Anthony Eid 6736a09abe gpui: Add is_visible and on_visibility_changed API on Window (#64107)
Adds a `WindowVisibility` API to GPUI: `Window::visibility()` /
`Window::is_visible()`, `Window::observe_window_visibility`, and
`Context::observe_window_visibility`, backed by one platform signal per
backend — `NSWindow.occlusionState` on macOS, `WS_VISIBLE` plus the
minimized state on Windows, the xdg-shell v6 `suspended` toplevel state
on Wayland, mapped state plus `VisibilityNotify` on X11, and the Page
Visibility API on web. Only transitions are reported, the initial value
is read from the platform when the window is created, and the two
`PlatformWindow` methods have no default so a backend cannot silently
opt out. The per-platform limits (Windows can't see a fully covered
window, pre-v6 Wayland compositors never report `Hidden`) are documented
on the type.

It also adds `Platform::on_system_sleep` / `App::on_system_sleep`,
mirroring the existing wake hook, on macOS
(`NSWorkspaceWillSleepNotification`), Windows (`PBT_APMSUSPEND`), and
Linux (logind `PrepareForSleep(true)`, which the listener previously
discarded). Nothing in Zed subscribes to either yet; the hang-telemetry
journal will use visibility to stop measuring frames that could not have
been presented, and the sleep/wake pair to bracket time the process was
not running.

Release Notes:

- N/A
2026-09-12 03:25:52 +00:00
Anthony Eid 56239b364e gpui: Add unpaced frame-driven renderer sessions (#64109)
## Objective

Make renderer benchmarks exercise GPUI's scheduled frame callback
instead of drawing synchronously whenever application effects are
flushed. Add finite rendering sessions for workloads that need to run
until explicit completion, with the goal of exposing expensive
foreground work and rendering stalls without artificial display waits.

## Changes

- Keep automatic drawing during effect flushing test-only. Benchmark
updates schedule frames, and the benchmark context scans existing
per-window scheduling state to deliver callbacks outside the App borrow.
- Deliver pending frames after foreground task polls and benchmark
input/workload callbacks. Nested actions and effects complete before
frame delivery.
- Add `bench_renderer_session` with fresh untimed setup, an input-turn
index, a stop flag, a deadline, and final presentation before successful
completion. Session-owned state is dropped outside measurement so it can
cancel unfinished work.
- Present setup's initial frame batch before tracing starts and activate
benchmark windows to avoid unintended inactive-window animation
throttling.
- Stop task benchmarks as soon as their result is ready, before
delivering an unrelated extra animation frame. Renderer sessions
separately retain their final-presentation guarantee.

## Scheduling and scope

This is an **unpaced work-and-render benchmark**, not a simulation of
display latency or an OS event loop. Renderer input turns service up to
the initial ready-task count, delivering frames between polls; rendering
after a poll does not inject another input. The report's FPS affects
reporting only, not execution. Individual task polls and frame callbacks
cannot be preempted, so an external process timeout is still needed for
work that never returns.

This is the second part of the benchmark split following #64099, which
has merged. Expanded timing/attribution reporting, intermediate-texture
reuse, and native event-loop integration are deferred.

## Validation

Passed after merging current `main`:

- `corgi fmt -p gpui -- --check`
- `corgi check -p gpui --features bench-support --lib`
- `corgi check -p gpui --lib`
- `git diff --check origin/main...HEAD`

This PR intentionally contains no added tests while the implementation
is being reviewed. Existing test modules are unchanged. Runtime tests
and downstream Delta smoke runs have not been performed for this
redesigned scheduling policy; checks from the earlier implementation are
not validation of this version.

Release Notes:

- N/A
2026-09-12 03:16:09 +00:00
Lukas Wirth 8687b3f35d gpui: List only available font families in suggestions (#64095)
## Summary

Make GPUI's font suggestions reflect the platform text system's actual
font inventory, including fonts loaded by the application, rather than
appending hardcoded fallback candidates.

The appended names could be unavailable on the current platform.

The downside of this is that virtual aliases such as `.SystemUIFont`,
`.ZedMono`, and `.ZedSans` are no longer injected into suggestions;
existing settings using those aliases still resolve as before, they just
won't be shown in the settings UI anymore.

Release Notes:

- Fixed font suggestions listing unavailable fallback fonts and internal
font aliases.
2026-09-11 17:14:29 +00:00
Ben Brandt 1e6cc1f182 Upgrade ACP to 2.1 and futures to 0.3.34 (#64077)
Upgrade to ACP SDK 2.1 and futures 0.3.34. Remove the dedicated-thread
polling workaround introduced in #62259 now that the SDK bounds
dispatch-chain stack usage.

This is the first PR from the ACP integration work. First-class
tool-call names, context compaction support, and the independent native
elicitation ID fix are intentionally deferred to separate PRs.

- Upgrade the ACP SDK and derive crate to 2.1.0, with schema 1.7.0.
- Upgrade the nine futures-rs 0.3 components to 0.3.34, including the
[cloned-waker identity
fix](https://github.com/rust-lang/futures-rs/pull/3032) identified
through [ACP
rust-sdk#254](https://github.com/agentclientprotocol/rust-sdk/issues/254).
- Poll ACP connections on the normal GPUI background executor and remove
the now-unused ACP-specific dedicated-spawn wrapper. Keep the general
scheduler dedicated-executor APIs intact.
- Use the stable authentication metadata accessor and route first-class
terminal authentication without requiring ACP beta. Keep legacy
terminal-auth metadata as a fallback for other authentication methods.

Also upgrades a big fix release of the futures crates because there was
some polling issues with FuturesUnordered reported with the old
versions.

Release Notes:

- Improved ACP compatibility and async task wakeup handling.
2026-09-11 11:10:44 +00:00
Cameron Mcloughlin 9eb022bd23 gpui: Long-press to activate tooltips (#63948)
Tooltips on web need long-press, rather than hover

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-11 05:25:06 +00:00
tidelyandKirill Bulatov 5a74e0b423 project_panel: Fix dragged folders remaining highlighted even after the drag has ended (#64038)
# Objective

When dragging a folder outside of Zed, it is considered a platform drag,
instead of a GPUI native drag event. Currently when this platform drag
finishes, the selected folder remains highlighted, until unhighlighted
by initiating a GPUI native drag event.

Found this while testing #64033, I did not find an issue related to this
bug.

## Solution

- Clear the drag state when no gpui **or** platform drag event is
active.

## Testing

- Added asserts to relevant parts of previous tests
- Tested this locally

I can record a showcase if requested, skipping it for now since its
quite time consuming

## 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 adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed folders remaining highlighted even after dragging the folder has
stopped

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-09-10 21:42:22 +00:00
Cameron Mcloughlin 42626fe94e gpui_web: Simplify keyboard focus model (#63989)
Simplifies the mobile web virtual keyboard implementation in the
following ways:
- assumes that GPUI web apps will set
`interactive-widget=resizes-visual`. This means that GPUI's window will
not change viewport size when the keyboard appears
- Exposes `Window::fully_visible_bounds`, which returns a rectangle
which is fully visible (pixels outside these bounds *may* be visible but
may not be)
- These two changes together mean that keyboard visibility is more
reliably detectable (though not fully), and also makes it easier to have
a stable scroll position when the keyboard is animating in/out
- tweaks the focus model so that:
- transitions into/out of the state "GPUI focus is in a text input, and
that text input is in an editable range" will change keyboard visibility
- manually-dismissed keyboards are preserved by not synchronizing unless
a tap event (or similar, or a programmatic request) on that input
happens
- there is a new `Window::{request,dismiss}_virtual_keyboard()` method
that allows programmatically controlling keyboard visibility (without
interacting with GPUI focus). This allows for patterns like "pressing
button A focuses text field B, *and opens the keyboard*

This PR also fixes a bug in non-touch web that caused text fields to
lose IME mirror focus when they entered non-editable regions, which
could prevent keyboard input from being detected by GPUI properly.

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-10 09:49:08 +00:00
Xiaobo LiuandKirill Bulatov 3d0649186f gpui: Prevent idle sleep during AI response streaming (#53130)
Release Notes:

- Added button tu prevent idle sleep during AI response streaming


**Context / Motivation:**
When an AI agent takes a long time to generate a response, the operating
system might enter an idle sleep (or display sleep) state if there is no
user interaction (mouse or keyboard). This can interrupt the workflow.
This PR aims to prevent the system from sleeping during an active AI
turn by invoking native OS APIs, and provides a UI toggle for users to
control this behavior.

**Key Changes:**

1. **Cross-Platform Idle Sleep Prevention in GPUI (`gpui`, `gpui_*`)**
- Added a new `prevent_idle_sleep` method to the `Platform` trait. It
returns a RAII-based `PreventIdleSleepToken`, which automatically
restores the original sleep policy when dropped.
- **macOS**: Utilizes `NSProcessInfo`'s `beginActivityWithOptions` with
`NSActivityIdleDisplaySleepDisabled`.
- **Windows**: Uses `SetThreadExecutionState` to prevent display and
system sleep, incorporating a reference counter to handle concurrent
requests safely.
- **Linux**: Uses `ashpd` to request `org.freedesktop.portal.Inhibit`
(inhibiting `Idle` and `Suspend` states) via D-Bus.

2. **AI Agent State Integration (`crates/acp_thread`)**
- Introduced idle sleep prevention logic in `AcpThread`: Acquires the
token at the beginning of `run_turn`, and automatically releases it when
the turn completes normally, errors out, or is explicitly canceled by
the user.
- Added comprehensive unit tests to ensure the token is correctly
acquired and released under various cancellation and concurrency
scenarios.

3. **Settings and UI (`crates/agent_settings`, `crates/agent_ui`)**
   - Added `AgentOutputIdleSleepControl` to global state.
- Added a new toggle button (screen icon) to the toolbar at the bottom
of the `ThreadView` (AI conversation panel). Users can hover to view the
tooltip and click to toggle the feature on or off.

<img width="419" height="132" alt="截屏2026-04-04 16 09 08"
src="https://github.com/user-attachments/assets/619da9ff-10f7-46e0-b959-d7c74b16b918"
/>

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-09-09 13:49:13 +00:00
Toru NayukiandKirill Bulatov a6cf4032e6 Restore macOS windows to their original Space after restart (#58886)
Addresses #9640 (the Spaces part).

On macOS, Zed already restores each window's size, position, and
display, but not its Space (virtual desktop). So after a restart, all
windows open on whatever Space is active at launch, not the Space they
were on before. This is the most reported problem in #9640.

A window's Space is not part of the window bounds we save. It is handled
by AppKit's own window state restoration. So instead of tracking the
Space myself, this PR uses that AppKit feature:

- I mark `GPUIWindow` as restorable and encode its native state (frame +
Space) by calling `encodeRestorableStateWithCoder:` with an
`NSKeyedArchiver`. A delegate skips the `NSView`/`NSWindow` objects that
do not support `NSSecureCoding`.
- I save the blob per workspace in a new `restorable_window_states`
table.
- When a saved workspace is opened again, I create the window and then
replay the blob with `restoreStateWithCoder:`. AppKit then moves the
window back to its Space.

On other platforms, and when there is no saved blob, this does nothing.

Verification:

- Added a round-trip test for the database part (save / overwrite /
read, and `ON DELETE CASCADE`).
- The macOS encode/restore part calls into AppKit, so I could not
unit-test it. I checked it by hand: I put several windows on different
Spaces, quit with Cmd+Q, started Zed again, and each window came back on
the Space it was closed on. I also checked that the saved blob is a real
AppKit archive (it starts with `bplist00`).

For now this only works for local workspaces. Remote workspaces could
use the same way later.

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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- macOS: Restored windows now reopen on the Space (virtual desktop) they
were on, instead of all landing on the currently active Space.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-09-09 13:48:50 +00:00
Lukas Wirth 5849530017 gpui: Replace shared asset futures with owning cache entries (#63934)
## Summary

Replace GPUI's shared asset futures with owning cache entries. The
mutex-backed waiter collection in futures::future::Shared can contend
between a worker and the browser main thread, where blocking waits are
forbidden.

- Keep loading on the background executor, with one foreground task
publishing the cached result and notifying interested views.
- Deduplicate loads and view registrations; cancel pending work on
eviction without allowing completion to update a replacement entry.
- Change App::fetch_asset to return Option<A::Output>, remove
ImageLoadingTask, and make ImageCacheItem an opaque owning entry.
- Migrate the retain-all image cache and image gallery LRU example.
Repository-wide search found no further callers requiring migration.

Results become visible after the foreground completion task publishes
them. Entries expose neither cloneable nor awaitable task handles.

Release Notes:

- N/A
2026-09-09 09:30:38 +00:00
Kirill Bulatovandzed-zippy[bot] 84148a0f73 Reduce LLVM IR bloat one last time (#63882)
I think this is the final attempt of mine to do anything about the
binary size, as those fixes become relatively intricate and I like them
less and less.

Each commit has its own improvement stats and mainly reduce generic-code
duplication through shared non-generic helpers and `#[inline(never)]`
boundaries.

Total reduction stats:

With sccache disabled, `cargo clean` and `cargo build --release -p zed`:
Before: zed binary 396716472 bytes
After: zed binary 359416504 bytes (-9.40%, -37.29MB)

Release Notes:

- N/A

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-09-07 15:18:49 +00:00
goringandSmit Barmase 86aae77e5e gpui: Add scale-factor simulation to TestWindow (#63719)
> **AI disclosure:** I used Claude (Anthropic) to write this change, its
test, and draft this PR description, after my own app shipped a
rendering bug that only reproduces on 1x displays — every test built on
gpui's test platform renders at a fixed 2.0 scale factor, so the bug was
invisible to an otherwise thorough offscreen test suite. I reviewed the
diff, ran the tests myself, and understand and take responsibility for
the change, per Zed's [AI
Policy](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#ai-policy).

# Objective

- `TestWindow::scale_factor()` has returned a hardcoded `2.0` since the
test platform's inception (`75f0670dd`, 2024-01-03), with no way for a
test to change it. Rendering behavior that only appears on 1x displays —
device-grid rounding, pixel snapping — can't be exercised: an error of
one device pixel is the full width of a hairline at 1x and half a
logical pixel at 2x, so this class of bug passes every test and ships.
- `Window::set_scale_factor` (`24058c865`, #61348, 2025-08) exists but
doesn't cover this: it overrides only the `Window`'s cached copy, so the
next `bounds_changed` re-reads the platform window and silently reverts
the override to 2.0.

## Solution

- Back the value with `TestWindowState`, still defaulting to `2.0`, so
existing tests are unchanged.
- Add `TestWindow::simulate_scale_factor_change`, which stores the new
factor and reports it through the resize callback — the same channel a
real DPI change reaches the window on — plus the matching wrappers on
`TestAppContext`, `VisualTestContext`, and `TestAppWindow`, mirroring
the `simulate_resize` family.
- Because the platform window owns the value, it survives later bounds
changes (unlike `set_scale_factor`); the test pins that.

## Testing

- Added `test_simulate_scale_factor_change` in
`crates/gpui/src/window.rs`: asserts the unchanged 2.0 default, that a
simulated change propagates to `Window::scale_factor()` through the
resize callback, and that it persists across a subsequent
`simulate_resize`.
- Reverting `scale_factor()` to the hardcoded `2.0` while keeping the
test reproduces the failure (see Showcase), so the test pins the
behaviour rather than passing vacuously.
- `cargo test -p gpui --lib` — 299 passed, 0 failed:

```
running 299 tests
...
test window::tests::test_simulate_scale_factor_change ... ok
...
test result: ok. 299 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s
```
- Tested on macOS. The change is confined to test-support code
(`platform/test/`, test contexts), which is platform independent, but I
have not built the Linux or Windows platform crates.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

Before — the new test against the hardcoded `2.0`:

```
thread 'window::tests::test_simulate_scale_factor_change' panicked at crates/gpui/src/window.rs:7230:9:
assertion `left == right` failed
  left: 2.0
 right: 1.0

test result: FAILED. 0 passed; 1 failed
```

After — see the full run above.

Release Notes:

- N/A

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-09-07 14:34:00 +00:00
shxmblesandKirill Bulatov 5b6ba0375d Add disable_ai check for "Agent Panel" MenuItem (#63580)
# Objective

- Removes Agent Panel menu item when AI disabled toggle is on.
- Fixes #63497

## Solution

- Use the global DisableAiSettings - disable_ai check in `app_menus.rs`.
To keep the order the same I
1. Check the disable AI setting
2. If true push to the `view_items` vec![]
3.  Extend the vec![] with the remaining Menu Items and Separators. 

## Testing

This can be tested visually:
 1. Open Zed with AI settings enabled 
 2. Click View when Zed is focused
3. Noting where Agent Panel is on the list and to make sure clicking it
opens up the Agent Panel.
 4. Open settings 
 5. Navigate to AI settings
 6. Toggle disable AI on
 7. Click View 
 
Expected: Agent Panel is gone from the menu. The opposite is also
expected.
 
- This was tested on macOS 26.6.2 (25G83).

## 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 adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [] Tests cover the new/changed behavior 
To keep this PR simple, I did not add any testing to this, as there were
no tests in this file already.
- [x] Performance impact has been considered and is acceptable

## Showcase
<details>
  <summary>Click to view showcase</summary>




https://github.com/user-attachments/assets/50db44ac-6c11-4101-a064-fd4e3b285620



</details>

---

Release Notes:

- Fixed Agent Panel appearing in the "View" menu when disable AI
settings is on.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-09-04 17:19:04 +00:00
Cameron Mcloughlin 7211b33bd4 gpui: Add Hitbox::is_hovered_at (#63696)
Adds `Hitbox::is_hovered_at` to improve touch selection on delta web

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-03 14:36:51 +00:00
Smit BarmaseandKirill Bulatov d4424eec68 which_key: Add a pending key binding indicator (#63343)
This PR makes Zed's one-second key binding delay visible.

Say both ctrl-w and ctrl-w left have bindings. After you press ctrl-w,
Zed waits to see whether left follows. The PR shows that wait in the
status bar with a countdown. Hovering the indicator shows which bindings
can still match.

It also adds a setting to hide the indicator. It does not change how Zed
resolves key bindings.

<img height="100" alt="dyn-db84a840272e2f6250a3f527a59b1efd"
src="https://github.com/user-attachments/assets/e42c6a6c-4677-499f-a1d3-835960ebb21a"
/>
<br/>
<img height="100" alt="dyn-8012278d030b41bc8ebfae1540504eff"
src="https://github.com/user-attachments/assets/250928d5-f913-40f0-9068-00ccb5cdf59f"
/>
<br/>
<img height="100" alt="file-5e6ffa90944faa294e7870f471b4e65b"
src="https://github.com/user-attachments/assets/c250e6eb-a269-4e2c-a5a0-0be9b5006f99"
/>

Release Notes:

- Added a status bar countdown for pending multi-stroke key bindings.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-09-03 09:35:53 +00:00
Smit Barmase a47324bb2b gpui: Add an option to keep hover listeners active after keyboard input (#63614)
While working on https://github.com/zed-industries/zed/pull/63343, I ran
into a problem with the pending key binding indicator. Hovering pauses
its countdown, but pressing the next key made `on_hover` report false
even though the mouse had not moved. The countdown then resumed while
the pointer was still over the indicator.

`on_hover` currently follows GPUI's normal hover rules. GPUI clears
hover after keyboard input so the item under a stationary mouse does not
interfere with keyboard navigation, for example list popover navigation
with keyboard.

This PR adds `HoverListenerMode` and `hover_listener_mode`. Callers that
need to track the pointer across key presses can opt in like this:

```rs
div()
    .hover_listener_mode(HoverListenerMode::InputModalityIndependent)
    .on_hover(|is_hovered, window, cx| {
          // ...
      })
```

`InputModalityAware` remains the default.

Release Notes:

- N/A
2026-09-03 09:35:52 +00:00
Vlad GaevskyandMrSubidubi d0699ca1d6 gpui: Snap recomputed padding to the device pixel grid before clamping scroll (#62296)
# Objective

Follow-up to #62135, taking the approach suggested there: fix the error
at its
source in GPUI instead of hiding it in the scrollbar.

At fractional rem sizes (`py_1` at an odd UI font size), a container
whose
content fits becomes scrollable by a sub-pixel amount, and every
uniform-list
picker grows a full-height scrollbar thumb for that phantom range.

## Solution

Taffy lays boxes out with every authored length snapped to the device
pixel grid
(`to_taffy`), and the final bounds are snapped again after layout.
However,
`Interactivity::clamp_scroll_position` recomputed the padding from the
raw style
with no snapping at all, so the padded content size exceeded the snapped
bounds
by up to half a device pixel, far past the existing two-decimal
float-noise
rounding, and `scroll_max` came out positive.

The fix snaps the recomputed padding with the same `pixel_snap` helper
the rest
of the pipeline uses, so both operands of the subtraction sit on the
same grid
and the phantom range never comes into existence.

Two neighbouring cases are deliberately left out to keep this scoped,
both are
follow-up candidates: percentage-based padding resolves inside Taffy
without
pre-snapping, so a discrepancy is still theoretically possible there;
and
`ListState::max_scroll_offset` (the older `list()` element) has no
rounding
protection at all.

## Testing

- New regression test: a 50px container with `py(4.25)` padding and a
child that
fits exactly. It fails on main (`max_offset` comes out at 0.5px) and
passes
  with the fix; verified in both directions.
- Full gpui suite: 241 tests pass.
- Reviewers can see the original symptom by opening any picker at a UI
font
size that makes `py_1` fractional in device pixels: a spurious
full-height
scrollbar thumb appears on main and is gone with this change. The math
is
  logical-pixel only, so the behavior is platform-independent.

## 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 adheres to Zed's UI standards
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable (one
pixel-snap
per padding edge per clamp, negligible against existing per-frame layout
work)

cc @MrSubidubi

Release Notes:

- Fixed containers becoming scrollable by a sub-pixel amount, with a
phantom
  full-height scrollbar thumb, at fractional UI font sizes.

Co-authored-by: MrSubidubi <finn@zed.dev>
2026-09-02 23:15:40 +00:00
Cameron Mcloughlin 81808cb5db gpui: Add TouchDragEvent API (#63645)
Adds `TouchDragEvent` and coresponding APIs. This allows web/touch-based
code to capture long press events without having to go through
scroll-like APIs

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-02 20:28:07 +00:00
Cameron Mcloughlin bd46f70cfd gpui: Prevent touch mispredict jitter (#63638)
When scrolling, mispredicted touch events could cause scroll jitter. We
now ignore predictions that are "travelling the wrong direction".

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-02 18:23:32 +00:00
Cameron Mcloughlin 1a1d00988e gpui_web: Drive IME mirror focus state from GPUI (#63629)
Previously, we manually synchronized the keyboard state in response to
tap events, but this meant that several common cases were unreliable.

Now, we use GPUI's focused element as the source of truth, and use
`sync_virtual_keyboard` in cases where they have gotten out of sync
(i.e. a user manually dismisses a keyboard while the input is still
focused).

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-02 18:23:07 +00:00
Kirill Bulatov b80f016f89 Bump more dependencies (#63379)
* 1st commit fixes bumps `quinn-proto` and `serde_with` to fix the
dependabot alerts

* 2nd commit deduplicates more dependencies

`cargo tree -d` listing: 194 -> 187 top-level entries on the host
target, 298 -> 287 unique duplicated crate-versions across all targets.

<details>
<summary>Deduplicated list</summary>

```
accesskit_consumer (v0.35.0, v0.37.0 -> v0.38.0)
bindgen (v0.71.1, v0.72.1 -> v0.72.1)
nix (v0.28.0, v0.29.0, v0.30.1 -> v0.28.0, v0.30.1)
ordered-float (v2.10.1, v4.6.0 -> v5.5.0)
quick-xml (v0.30.0, v0.37.5, v0.38.3, v0.39.3, v0.41.0 -> v0.30.0, v0.37.5, v0.39.3, v0.41.0)
sysinfo (v0.31.4, v0.37.2 -> v0.31.4, v0.39.6)
wasm-encoder (v0.252.0, v0.254.0 -> v0.254.0)
wasmparser (v0.252.0, v0.254.0 -> v0.254.0)
windows-registry (v0.4.0, v0.5.3, v0.6.1 -> v0.4.0, v0.6.1)
```

`ordered-float v4.6.0` remains in the lockfile only as an inactive
optional dependency of `sea-query`; the compiled graph is fully
deduplicated to v5.5.0.

</details>

Release Notes:

- N/A
2026-09-02 18:21:25 +00:00
Anthony Eid 265ea4e838 gpui: Record hang trigger class and set the release frame budget to 24ms (#63586)
Hang incidents come in two classes that consumers could only tell apart
by comparing `stall_ms` against the hang threshold, which is not
recorded in the event: a single event over the threshold, or an interval
whose cumulative foreground spend reached the frame budget. This PR
makes the class explicit and re-tunes the budget.

- `HangIncident` and `SerializedHangIncident` gain `trigger:
HangTrigger` (`threshold` | `budget`).
- The `Hang Incidents` telemetry event reports `threshold_incidents` and
`budget_incidents` alongside the existing `total_incidents` (kept for
existing queries; it is now the sum of the two).
- The release frame budget moves from 8 ms to 24 ms. At 8 ms almost
every busy 60 Hz frame qualified, so the budget class dominated incident
counts without saying much. 24 ms is above every refresh period, so a
budget incident now means the interval dropped at least one frame on any
display. Frame smoothness below that is measured per-frame by `Frame
Duration Report`. `budget_incidents` is the signal for lowering it
further as hangs get fixed. Debug builds already used 100 ms and are
unchanged.

Part of a series on hang-telemetry data quality; #63588 handles
withheld-frame `dirty_at`, and marking OS prompt waits so they stop
registering as task-poll hangs is next.

Release Notes:

- N/A
2026-09-02 05:03:27 +00:00
Jakub Konka 966ba1f92a gpui: Add long-press gesture recognition (#63561)
GPUI's touch gesture recognizer handles taps and pans, but its
long-press event was only a placeholder. Applications therefore could
not distinguish a deliberate press-and-hold from a tap or scroll using
the portable touch path.

This adds deadline-driven long-press recognition and dispatches a phased
event stream through GPUI's existing capture and bubble listener path. A
listener claims the gesture by preventing the initial event's default
behavior and capturing it for an entity. Unclaimed gestures remain
eligible for the existing tap and pan behaviors, while claimed gestures
receive movement and termination events without also producing taps or
scrolling.

The timer is cancelled when the pending gesture resolves. `gpui_web` now
translates reusable browser pointer identifiers into touch identifiers
that remain unique for each touch lifetime, preventing an old timer from
acting on a newer touch. Native macOS trackpad scrolling remains on its
existing `ScrollWheelEvent` path and does not enter touch gesture
recognition.

Testing performed:

- `cargo fmt --all -- --check`
- `cargo nextest run -p gpui --lib long_press` (10 passed)
- `RUSTC_BOOTSTRAP=1 cargo check -p gpui_web --target
wasm32-unknown-unknown`

Release Notes:

- N/A
2026-09-01 16:28:50 +00:00
Jakub Konka 16da2ea125 gpui: Lock touch scrolling to the dominant axis (#63553)
Touch pans currently preserve small amounts of movement on both axes,
including in the synthetic momentum generated after release. In a nested
scrolling layout, a mostly vertical fling that starts over a
horizontally scrollable child can therefore move the child horizontally
while its ancestor moves vertically.

This locks each touch pan to the dominant axis of its accumulated
movement when it crosses the touch-slop threshold. Initial movement,
predicted updates, release correction, velocity, and momentum are
projected onto that axis, so every scroll listener sees the same
one-dimensional gesture for its full lifetime.

The existing trackpad and wheel behavior remains unchanged; the new rule
is applied by the portable raw-touch recognizer before it emits semantic
scroll events.

Testing:

- `cargo nextest run -p gpui --lib gestures::tests`
- `cargo fmt --all -- --check`
- `./script/clippy -p gpui`
- Built Delta Web for `wasm32-unknown-unknown` with this GPUI worktree
and reached a successful Trunk release build

Release Notes:

- N/A
2026-09-01 14:20:13 +00:00
Cameron Mcloughlin c940c0c669 gpui_web: Tighten up web keyboard feel (#63533)
Fixes a few edge cases where we weren't correctly tracking whether to
hide the keyboard when touch events happen

Also forces a synchronous render on web after the viewport resizes
(which happens when the keyboard appears/disappears). This prevents a 1
frame delay where the browser would use the old bitmap, stretched to the
new size

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-09-01 12:43:44 +00:00
Conrad IrwinandBen Kunkle 72dc742101 Support building with corgi (#63396)
[corgi](https://github.com/ConradIrwin/corgi) is a cargo-compatible
build tool that runs `build.rs` scripts and proc-macros in a sandbox (no
network, no ambient env, reads limited to a package's own `.rs` sources
unless declared). This makes Zed buildable under it. Cargo builds (dev
and release) are unaffected.

### Changes

- **`scratch` patch**: patch `scratch` to a small local copy
(`corgi-patches/scratch`) that reads `OUT_DIR` at runtime instead of
baking it in at compile time. `cxx-build` writes its shared cxxbridge
headers into `scratch::path(...)`; upstream returns a single global dir
(outside any action's `OUT_DIR`) that the sandbox can't grant, while
this patch gives each build script a private, writable dir in its own
entry. webrtc-sys is self-contained, so per-crate scratch dirs are
sufficient. Kept local rather than a cxx git fork because a git checkout
of cxx needs symlink support that Windows cargo CI lacks.
- **Dev asset loading**: add `util::dev_fs_embed!` and switch dev-mode
`rust_embed` asset sources (`assets`, `settings`, `grammars`, `agent`,
`edit_prediction_cli`) to read from the checkout at runtime, locating
the repo root by walking from the executable up to the enclosing `.git`.
This avoids baking `CARGO_MANIFEST_DIR` into the binary (corgi rejects
artifacts that embed the build-time checkout path, and it's wrong in any
other worktree). Release builds still embed via `#[derive(RustEmbed)]`.
- **Stop baking checkout paths into artifacts**: drop
`gpui::GPUI_MANIFEST_DIR`; resolve `../gpui` from `gpui_apple`'s build
script; stage the metal shader into `OUT_DIR` before compiling so the
`.metallib` records the output dir, not the checkout; resolve the repo
root at runtime in `remote` and `inspector_ui` (removing
`inspector_ui`'s `build.rs` / `ZED_REPO_DIR`).
- **corgi.toml**: declare the pinned tools (`cmake`, prebuilt libwebrtc
via `LK_CUSTOM_WEBRTC`), a release-only `ZED_COMMIT_SHA` probe, and the
non-`.rs` / cross-package reads each package performs.

### Validation

- `corgi check` + `corgi build`, dev and release, for `zed` (plus `cli`,
`remote_server`, `ep`) with a warm C++ cache — clean; built binaries
embed no checkout path.
- `corgi fmt --check`, `corgi clippy`, and `corgi test` on the changed
crates (922 tests pass).
- `cargo check -p util` locally; relying on CI for the full cargo
build/test matrix.

### Notes for the reviewer

- Per the repo rule, the first two lines of `README.md` are the
review-confirmation marker; remove them before merging (this is what
Danger is failing on).
- `remote_server` cross-compilation (linux-musl via zigbuild) is not yet
covered by `corgi.toml` — host (macOS arm64) only for now.

### Suggested .rules additions

Only if the team wants corgi guidance in `.rules` (it recurred several
times here): dev builds must not bake the checkout path into artifacts —
no `env!("CARGO_MANIFEST_DIR")` or `file!()`-derived absolute paths in
library/binary output. Resolve the repo root at runtime via
`util::dev_repo_root()` (walks to `.git`), and use `util::dev_fs_embed!`
for dev-mode `rust_embed` sources.

Release Notes:

- N/A

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2026-08-31 17:37:00 +00:00
Cameron Mcloughlin 87222d1d29 gpui: Platform-specific scroll physics (#63505)
Adds platform-specific scroll behaviour, and also exposes predicted
events for better latency

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-08-31 17:08:14 +00:00
Lukas Wirth 1344a8a846 gpui: Gate blocking executor APIs on WebAssembly (#63484)
GPUI's scheduler exposed synchronous blocking APIs on WebAssembly even
though the platform implementation could only panic. This became an
implicit crash when cancellation dropped a scoped background operation:
preserving the borrowed task lifetime called `Scheduler::block`, which
panicked with `Cannot block on wasm`.

This change removes blocking scheduler and executor APIs from
WebAssembly builds, including borrowed background scopes and the
separate `pollster::block_on` export. Native behavior remains unchanged.
Application shutdown now runs WebAssembly quit handlers asynchronously
as best-effort cleanup rather than blocking the browser event-loop
thread.


Release Notes:

- Fixed a GPUI Web crash caused by synchronous executor blocking.
2026-08-31 13:35:07 +00:00
Lukas Wirth ab1c37a4ef gpui_web: Let applications provide fonts (#63493)
`gpui_web` currently embeds IBM Plex Sans and Lilex into every browser
application during platform construction. Applications such as Delta
already provide their own fonts, so those binaries contain overlapping
font bundles and register the same faces twice.

This change starts the web platform with an empty font database,
matching the ownership boundary used by native applications: the
application selects and registers its fonts before opening a window.
Delta already follows that sequence. GPUI's browser-capable examples now
load the former eight-face bundle explicitly through shared example
support, while the standalone `hello_web` example demonstrates
registering a minimal application font directly.

Testing performed:

- `cargo check -p gpui --examples --target wasm32-unknown-unknown`
- `cargo check -p gpui --examples`
- `cargo check -p gpui_web --target wasm32-unknown-unknown`
- `cargo check --manifest-path
crates/gpui_web/examples/hello_web/Cargo.toml --target
wasm32-unknown-unknown`
- `./script/clippy -p gpui_web --target wasm32-unknown-unknown`
- `cargo fmt -p gpui -p gpui_web --check`

Release Notes:

- N/A
2026-08-31 13:07:22 +00:00
Cameron McloughlinandJakub Konka 50b7479f17 gpui: Touch events (#63373)
Adds support to GPUI for touch events, important for mobile web
browsers, and any potential native ios/android platforms

---

Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2026-08-28 17:22:25 +00:00
Cameron Mcloughlinandzed-zippy[bot] 0854657a2b gpui: Add text_edit_editable_range API (#63294)
When syncing text to the browser IME mirror, we sometimes need to mark a
particular range as "editable". Native clients have a pull-based model,
so don't need this mechanism, but on the web we need to proactively push
content to the IME mirror `textarea`.

---

Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-08-27 10:13:49 +00:00