Skip to content

Sync With upstream and Update crates version to latest - #6

Open
vrdons wants to merge 45 commits into
sonorahq:masterfrom
vrdons:sync-upstream
Open

vrdons wants to merge 45 commits into
sonorahq:masterfrom
vrdons:sync-upstream

Conversation

@vrdons

@vrdons vrdons commented Sep 7, 2026

Copy link
Copy Markdown

No description provided.

reflectronic and others added 30 commits August 24, 2026 02:59
Handle the `WM_QUERYENDSESSION` and `WM_ENDSESSION` messages, which are
used by Windows when shutting down an application. For example, Restart
Manager uses this mechanism to gracefully close applications (e.g. when
installing an update to the application).

Release Notes:

- N/A
Prewarming cosmic-text font cache completely eliminated expensive
`get_font_matches` calls and thus reducing the time it takes to call
`cosmic_text::shape::ShapeLine::new`.

Release Notes:

- Improved rendering performance on Linux by prewarming font match
caches.
Allow disabling stacker in gpui (as on wasm it uncondtionally allocates
more stack)

Release Notes:

- N/A
Release Notes:

- Improved rasterization performance on Linux by caching glyphs after
measuring bounds.
Extends the existing GPUI frame-duration telemetry with the average time
from a window's first invalidation through presentation.

- Record dirty-to-present durations in each window profiler
- Include the declared root entity type name on window handles
- Add the average and root type to the existing five-minute `Frame
Duration Report` event

Testing:

- `cargo fmt --all -- --check`
- `cargo test -p gpui --features profiler
records_dirty_to_present_durations`
- `cargo check -p gpui --no-default-features`
- `cargo check -p input_latency_ui -p zed`

Release Notes:

- N/A
# Objective

I’m building a component library with GPUI and ran into a panic when I
enabled the profiler feature for a `wasm32-unknown-unknown` build.
Dispatching an action calls std::time::Instant::now(), which has no
clock implementation on this target, and the browser reports time not
implemented on this platform. The panic then triggers RefCell already
borrowed errors and leaves the GPUI window unresponsive.

The current `main` fails to compile this feature combination because the
action profiler’s std::time::Instant does not match the scheduler-based
timestamps in the profiler journal. I want GPUI’s action profiler to use
the same cross-platform clock as the rest of the profiler and keep this
configuration covered by CI.

## Solution

Use `scheduler::Instant`, the scheduler crate's cross-platform instant
type, for action timings so they match the rest of the GPUI profiler.
Keep the existing downstream wasm check and add a separate
profiler-enabled GPUI wasm check so CI covers both feature
configurations.

## Testing

- `cargo check --target wasm32-unknown-unknown -p gpui
--no-default-features --features profiler`
- `cargo -Zbuild-std=std,panic_abort check --target
wasm32-unknown-unknown -p gpui_platform -p cloud_api_client --features
gpui/profiler`
- `cargo test -p gpui --no-default-features --features profiler
profiler::` (48 tests passed)
- `./script/clippy -p gpui`

I ran a wasm GPUI app in Edge with WebGPU. The app opens a window and
dispatches an action with `profiler` enabled. Before this change, the
action produced the clock panic and follow-on borrow errors. After the
fix change, the action completed and the window remained active.

I did not run the browser harness in Firefox or Safari, though the wasm
compile check covers the changed profiler configuration without
depending on a browser.

## 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); this PR has no UI changes
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
… layers

# Objective

olor emoji (COLR glyphs) are rasterized on the GPU by compositing each
glyph layer into a D3D11 render target that is created with
`pInitialData: None` and, until now, never cleared. The texture contents
are undefined: texels not covered by any layer quad retained garbage
(typically leftovers from previous rasterizations via the DXGI
allocation pool).

## Solution

- Clear the render target with `[0, 0, 0, 0]` (premultiplied
transparent) immediately after binding it and before drawing the layers.

## Testing

add test to test this specifically

## Showcase

before :
<img width="1634" height="754" alt="ezgif-1a339c7dea79f905"
src="https://github.com/user-attachments/assets/6e282c46-d2a4-4043-9c1c-7f4ee9232fcc"
/>

after :

<img width="1677" height="690" alt="Screenshot 2026-08-26 015248"
src="https://github.com/user-attachments/assets/c922909e-c70b-49f0-88fd-5a0c7cbe574b"
/>
## Objective

GPUI's X11 `WM_CLASS` property omits its final NUL terminator, so any
window
manager that relies on the terminator reads the class one byte short.

`WM_CLASS` is specified by [ICCCM
§4.1.2.5](https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.5)
as two consecutive NUL-**terminated** strings, `instance\0class\0`.
`set_app_id` writes the separator but not the final terminator:

```rust
let mut data = Vec::with_capacity(app_id.len() * 2 + 1);
data.extend(app_id.bytes()); // instance
data.push(b'\0');
data.extend(app_id.bytes()); // class   <- no trailing NUL
```

This affects Zed itself. `ReleaseChannel::app_id()` returns
`dev.zed.Zed` on
stable, so under X11 and XWayland the class is read as `dev.zed.Ze`. The
shipped
desktop file is `dev.zed.Zed.desktop`, so the association it depends on
is
exactly the string being truncated, and window-manager rules or taskbar
grouping
matching `dev.zed.Zed` silently fail to apply.

Wayland is unaffected, since the app id is set through `xdg_toplevel`
rather
than an X11 property.

## Solution

Append the missing terminator after the class string, and size the `Vec`
capacity to match (`* 2 + 2` rather than `* 2 + 1`).

## Testing

Tested manually on Arch Linux with Hyprland v0.56.2 (wlroots) via
XWayland.

**Reproducing the bug** — Zed 1.14.2, before the fix:

```
$ env -u WAYLAND_DISPLAY zeditor some-dir
$ hyprctl clients -j | jq '.[] | select(.xwayland) | .class'
"dev.zed.Zed\u0000dev.zed.Ze"
```

The same window read with `xprop`, which does not require the
terminator, shows
the intended value — confirming the property itself is malformed rather
than the
compositor misreading it:

```
$ xprop -id 0x800001 WM_CLASS
WM_CLASS(STRING) = "dev.zed.Zed", "dev.zed.Zed"
```

**Control** — on the same compositor and the same XWayland path,
Alacritty
(winit, which writes the trailing NUL) reports its class intact:

```
$ hyprctl clients -j | jq '.[] | select(.xwayland) | .class'
"Alacritty"
```

The same truncation was reproduced independently with a third-party GPUI
application using `app_id: Some("sprite")`, which reports
`sprite\u0000sprit`.

**Platforms:** verified on Linux/XWayland only. Wayland does not use
this code
path. macOS and Windows have their own `set_app_id` implementations and
are
unaffected by this change.

**Needs more testing:** confirmation on a bare X11 session (not
XWayland) and on
a non-wlroots window manager such as i3, KWin, or Mutter would be
welcome — the
malformed property is compositor-independent, but which readers visibly
truncate
it is not.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments — *none added*
- [x] The content adheres to Zed's UI standards — *N/A, no UI change*
- [ ] Tests cover the new/changed behavior — *see note below*
- [x] Performance impact has been considered and is acceptable — *one
additional
      byte in a property set once per window*

"No automated test: asserting the property bytes requires a live X
server. Happy to add one if there's an existing pattern for X11 window
tests I've missed."

Co-authored-by: Lukas Wirth <lukas@zed.dev>
…#63012)

# Objective

`gpui_macos` implements `PlatformWindow::render_to_image` — the
MetalRenderer samples an offscreen target, so a **hidden** window can be
captured. `gpui_windows` does not implement it, so the method falls
through to the trait default and returns `Err("render_to_image not
implemented for this platform")`.

That leaves Windows consumers (tests, headless screenshot harnesses) on
`PrintWindow`-style workarounds, which require the window to actually be
on screen: a DirectComposition swap chain that never presents has no
frame to read, so you get a visible flash — or an off-screen parking
trick — for every capture.

This closes the macOS/Windows gap. Linux (`gpui_linux`) still returns
the trait default; a Blade/wgpu readback is the obvious follow-up but is
not in this PR.

## Solution

The DirectX analogue of the Metal path:

- `DirectXRenderer::draw`'s clear, scene upload and batch encoding are
factored into a shared `render(scene, background_appearance)`. `draw` is
now `render` + `present`; `render_to_image` is `render` + readback.
Nothing about how a frame is produced is duplicated between them, so the
two cannot drift.
- `render_to_image` renders into the **existing** render target —
created at window construction, so no window need ever be shown — then
copies it into a `D3D11_USAGE_STAGING` texture, `Map`s it, and converts
BGRA → RGBA. `RowPitch` padding is honoured per row; the copy loop
carries a safety comment.
- It refuses to run while `skip_draws` is set. That flag marks a pending
device-lost recovery, where the atlas still holds tile references from
the previous device — drawing before the forced re-render rebuilds them
panics in `DirectXAtlasState::texture` (the case
`WindowState::force_render_pending` documents). Returning an error beats
panicking in a capture harness.
- Gated on `cfg(any(test, feature = "test-support"))` to match the trait
method. `gpui_platform`'s `test-support` now forwards to
`gpui_windows/test-support`, the way it already does for `gpui_macos`.

No behaviour change outside `test-support`/`cfg(test)` builds beyond the
`render` factoring, which is a pure code move.

## Testing

- **Windows, functional:** an earlier revision of this patch has been in
production use since June in the `--screenshot` harness of a GPUI app I
ship ([Ferail](https://github.com/jonx/Ferail)), capturing a hidden
window (`show: false`) with no flash. BGRA→RGBA output was verified
against the on-screen rendering.
- **This exact revision** has been cross-checked from macOS only: `cargo
clippy -p gpui_windows --no-default-features --features test-support
--target x86_64-pc-windows-msvc -- -D warnings` is clean, both with and
without `test-support` (clang-cl + `xwin`; `--no-default-features` skips
only the `windows-manifest` embed-resource step, which is irrelevant
here). I'm relying on CI for a native Windows build of this revision —
happy to report back from a Windows host if that's a blocker for review.
- **Not covered by an automated test.** The behaviour needs a live D3D11
device, so it can only be exercised by a Windows-hosted test. Happy to
add one under `gpui_windows` if you'd like it — say the word and I'll
push it rather than guess at the shape you want.
- **Reviewers:** the interesting part is the staging-texture readback in
`directx_renderer.rs`. Worth a second pair of eyes on the `skip_draws`
guard and on premultiplied alpha (the swap chain is
`DXGI_ALPHA_MODE_PREMULTIPLIED`, so non-opaque captures come back
premultiplied — same as the macOS path, but it does mean
semi-transparent regions are not straight-alpha).

## 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) — n/a, no UI surface
- [ ] Tests cover the new/changed behavior — see Testing; needs a
Windows host, happy to add
- [x] Performance impact has been considered and is acceptable — the
readback path is `test-support`-only; `draw` is unchanged apart from the
`render` factoring

## Showcase

<!-- TODO: drop in the headless Windows capture (and the macOS one
beside it) -->
…(#62743)

# Objective

`LineWrapper` treats every punctuation character as a break opportunity,
so a wrap can land right before `!`, `?`, `/`, `)`, `]`, `}`, a closing
quote or an ellipsis. Text such as `please fix this plz!`, `8.0/8.0`,
`cli/install`, `(see)` or `“quoted”` then wraps with the closing mark
orphaned at the start of the next line.

## Solution

Add the "UAX 14 LB13 rule" to `LineWrapper::is_word_char`, which is to
not break before `! ? / ) ] } " ” » …`

## Testing

Added unit tests and manually tested myself with a long paragraph in a
gpui app.

## 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
extra `matches!` per character in the wrap loop)
…t DPI scaling (#62859)

# Objective

Fixes #48927. On Windows, when monitors have different DPI scaling
factors, a new window opened on a secondary monitor can be positioned
partially off-screen, with the title bar unreachable.

## Solution

`WindowsWindow::new` calls `CreateWindowExW` with `CW_USEDEFAULT` for
the window's initial position, so Windows picks a starting spot
(typically based on where the previous window was, which is often the
primary monitor) before the window is explicitly moved to its intended
monitor via `SetWindowPlacement`.

`WindowsWindowState::new` immediately reads the window's scale factor
via `GetDpiForWindow(hwnd)` at that point — i.e. the DPI of wherever
Windows initially placed it, not necessarily the target monitor.
`retrieve_window_placement` then used that scale factor to convert the
target monitor's logical bounds into physical pixels. When the two
monitors have different scaling (e.g. 150% vs 100%, as in the linked
issue), this produces the wrong physical rect, leaving the window
off-screen.

The target `WindowsDisplay` already computes its own correct
`scale_factor` from the actual monitor (`get_scale_factor_for_monitor`)
— this is also what `check_given_bounds` already uses. This PR exposes
that value via `WindowsDisplay::scale_factor()` and uses it in
`retrieve_window_placement` instead of the transient window's scale
factor, since the bounds being converted are expressed in logical pixels
for that target display.

## Testing

- Verified the logic by tracing through `WindowsWindowState::new` →
`retrieve_window_placement` → `calculate_window_rect` and confirming the
target monitor's own DPI (not the temporarily-assigned window DPI) is
now used to compute the physical placement rect, matching the approach
`WindowsDisplay::check_given_bounds` already uses for the same
target/temporary-monitor mismatch.
- I wasn't able to build/run Zed locally in this environment (missing
Windows SDK components in the local toolchain, unrelated to this change)
to reproduce the original multi-monitor/mixed-DPI repro steps
first-hand. I'd appreciate a maintainer or anyone who can reproduce
#48927 double-checking on real mixed-DPI hardware.
- Platforms: Windows only (`gpui_windows` crate); no other platform code
touched.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments (no new unsafe
blocks added)
- [ ] The content adheres to Zed's UI standards (N/A, no UI change)
- [ ] Tests cover the new/changed behavior (no existing test harness for
Windows-specific placement logic; happy to add one if pointed at the
right pattern)
- [x] Performance impact has been considered and is acceptable (no
measurable impact; same number of DPI queries, just reading from the
already-computed `WindowsDisplay` instead of the window)

Release Notes:

- Fixed: new windows on Windows could open partially off-screen when
placed on a secondary monitor with a different DPI scaling factor than
the monitor Windows initially placed them on.

---------

Co-authored-by: Lukas Wirth <lukas@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
`gpui::bench` previously required GPUI's full `test-support` feature.
Any benchmark using the supported GPUI harness therefore compiled
test-only APIs and fakes, even when the benchmark otherwise followed
production dependency paths.

This change introduces `bench-support` as GPUI's canonical benchmark
feature and keeps `bench` as a compatibility alias for existing
consumers. The benchmark feature now exposes only the existing GPUI
internals that `BenchAppContext` needs: the real threaded dispatcher,
profiler integration, and a headless platform surface. Benchmark HTTP
requests use the production `BlockedHttpClient`, so accidental network
access fails instead of silently entering a fake response path.

The current headless implementation reuses the cfg-stripped core of
`TestPlatform`. Test-only prompt state, simulation APIs, and test
executors remain unavailable under `bench-support`. Cargo feature-tree
checks confirm that both `bench-support` and the compatibility alias
remain independent of `test-support`.

This also adds a `gpui-bench` agent skill covering production-shaped
fixtures, frame and foreground responsiveness, macOS headless Metal
rendering, deterministic correctness guards, Criterion measurement,
Instruments symbolication, and the requirement that a benchmark's
complete dependency graph contain no `test-support` feature.

Two follow-ups are intentionally deferred to keep this feature-isolation
change reviewable:

- Extract the shared headless implementation into
`HeadlessPlatformCore`, with separate `BenchPlatform` and `TestPlatform`
wrappers. This will remove benchmark-related cfg branches from the
test-facing type and make their supported surfaces explicit.
- Add a shared scripted HTTP client that compiles independently under
either `http_client/test-support` or `http_client/bench-support`. Tests
and benchmarks could then serve predefined responses through the same
deterministic transport boundary without either support feature enabling
the other; the default benchmark context should remain network-blocked.

This PR only isolates GPUI itself. Migrating downstream benchmark
fixtures that explicitly request other crates' `test-support` features
remains separate work.

Testing performed:

- `cargo tree --offline --package gpui --no-default-features --features
bench-support --edges features --invert gpui`
- `cargo tree --offline --package gpui --no-default-features --features
bench --edges features --invert gpui`
- `cargo check -p gpui --no-default-features --features bench-support`
- `cargo check -p gpui --no-default-features --features bench`
- `git diff --check`

Release Notes:

- N/A
GPUI's `bench-support` feature provides the benchmark context and
headless-renderer interface without enabling `test-support`, but the
platform implementation remained available only through
`gpui_platform/test-support`. As a result, consumers could not use
`#[gpui::bench]` with a fully isolated feature graph because the
generated benchmark harness calls
`gpui_platform::current_headless_renderer()`.

This threads `bench-support` through `gpui_platform`, `gpui_macos`, and
`gpui_apple`, exposing the existing Metal headless renderer without
widening unrelated test window or prompt APIs. The existing benchmark
package now requests the platform's canonical `bench-support` feature.
Its other test-backed fixtures are intentionally unchanged and remain
outside this focused dependency fix.

Validation:

- Confirmed `gpui_apple/bench-support`, `gpui_macos/bench-support`, and
`gpui_platform/bench-support` resolve no `test-support` feature with
`cargo tree --locked --no-default-features --features bench-support -e
no-dev,features`.
- Ran `cargo check --locked -p benchmarks --benches` to compile every
existing `#[gpui::bench]` target against the real platform headless
renderer.
- Ran `cargo nextest run --locked -p gpui_apple -p gpui_macos -p
gpui_platform`.
- Ran `./script/clippy` for each changed platform package with
`--no-default-features --features bench-support`.
- Ran `cargo fmt --check`.

Release Notes:

- N/A
Deduplicates crates with different versions from the graph, drops unused
features.

`cargo tree -d duplicate` listing: 160 -> 112 lines.

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

```
base64 (v0.22.1, v0.21.7 -> v0.22.1)
convert_case (v0.11.0, v0.10.0, v0.8.0 -> v0.11.0, v0.10.0)
core-foundation (v0.10.0, v0.9.4 -> v0.10.0)
cssparser (v0.36.0, v0.35.0 -> v0.37.0, v0.36.0)
fancy-regex (v0.18.0, v0.16.2 -> v0.19.0)
fixedbitset (v0.5.7, v0.4.2 -> v0.5.7)
h2 (v0.4.12, v0.3.27 -> v0.4.12)
heck (v0.5.0, v0.4.1, v0.3.3 -> v0.5.0, v0.4.1)
html5ever (v0.39.0, v0.35.0 -> v0.39.0)
hyper (v1.7.0, v0.14.32 -> v1.7.0)
hyper-rustls (v0.27.9, v0.24.2 -> v0.27.9)
mach2 (v0.6.0, v0.5.0, v0.4.3 -> v0.6.0, v0.5.0)
markup5ever (v0.39.0, v0.35.0 -> v0.39.0)
phf (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_codegen (v0.13.1, v0.11.3 -> v0.13.1)
phf_generator (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_macros (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
phf_shared (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3)
prost (v0.12.6, v0.9.0 -> v0.14.4)
prost-build (v0.12.6, v0.9.0 -> v0.14.4)
prost-derive (v0.12.6, v0.9.0 -> v0.14.4)
prost-types (v0.12.6, v0.9.0 -> v0.14.4)
rustix (v1.1.4, v0.38.44 -> v1.1.4)
rustls (v0.23.40, v0.21.12 -> v0.23.40)
rustls-native-certs (v0.8.3, v0.6.3 -> v0.8.3)
rustls-pemfile (v2.2.0, v1.0.4 -> v2.2.0)
rustls-webpki (v0.103.13, v0.101.7 -> v0.103.13)
security-framework (v3.5.1, v2.11.1 -> v3.5.1)
socket2 (v0.6.3, v0.5.10 -> v0.6.3)
string_cache (v0.9.0, v0.8.9 -> v0.9.0)
string_cache_codegen (v0.6.1, v0.5.4 -> v0.6.1)
strum (v0.28.0, v0.27.2 -> v0.28.0)
strum_macros (v0.28.0, v0.27.2 -> v0.28.0)
tendril (v0.5.1, v0.4.3 -> v0.5.1)
tokio-rustls (v0.26.4, v0.24.1 -> v0.26.4)
tungstenite (v0.28.0, v0.27.0 -> v0.28.0)
web_atoms (v0.2.6, v0.1.3 -> v0.2.6)
which (v6.0.3, v4.4.2 -> v8.0.5)
```

</details>

Release Notes:

- N/A
Allows setting various attributes for the underlying mirror textarea on
the web. Allows GPUI app authors to specify things like "this element
should be auto-corrected"
This prepares for the keybinding hints PR.

To reproduce, press `ctrl-b` in a GPUI app with `ctrl-b h` and `ctrl-b
j` bindings, then call `window.blur()`. The live pending state clears,
but observers still report `ctrl-b`.

`Window::blur` now clears pending input and notifies observers after the
current effect cycle. I don't think we currently exercise this path in
Zed, and I was only able to reproduce it with an example GPUI app.

Release Notes:

- N/A
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`.
- Simplify PowerShell discovery, and add support for .NET global tool
installations.
- Fix Git Bash discovery in the case where Zed was launched from within
Git Bash. Git Bash prepends its internal `mingw64\bin` directory to
`PATH`, so `which git` returns a different `bash` executable that causes
the relative path lookup to fail.

Release Notes:

- N/A
Adds support to GPUI for touch events, important for mobile web
browsers, and any potential native ios/android platforms
`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
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.
…572)

# Objective

Rust 1.96 emits a warning when compiling the `block` crate, that it will
no longer compile past some future version of Rust. The `block` crate
provides `ConcreteBlock` and `RcBlock`, which are stack- and heap-based
functions often passed as callbacks to MacOS. The old `objc` crate
family is deprecated and no longer maintained.

The goal of the PR is to replace one call to `block::ConcreteBlock` by
migrating a standalone portion of code to the objc2 crate family. A full
migration to `objc2` by Zed has been long on the horizon (#22408)

Additional benefits: The new code is completely typed, uses automatic
memory management, and reduces lines of unsafe Rust from 50+ to 1. The
lingering unsafe converts a raw pointer stored by `self` to the
respective `objc2` type, since the rest of the window implementation
does not use the new crates yet.

## Solution

Migrate `PlatformWindow::prompt`'s MacOS implementation to `objc2`.

## Testing

Direct platform code is quite fragile and hard to test, however you can
exercise the codepath by running the following `gpui` example and
clicking on the prompt buttons.

```sh
cargo run -p gpui --example window
```

I've also built Zed with these changes and tried codepaths which
activate prompts, such as deleting a file.

## 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
- [x] Performance impact has been considered and is acceptable
Adds platform-specific scroll behaviour, and also exposes predicted
events for better latency
[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>
# Objective

`to_cmd_variable` and `to_powershell_variable` removed the last byte of
a
`${...}` argument assuming it was the closing brace, without checking
one was
there

```rust
// If the input starts with "${", remove the trailing "}"
format!("$env:{}", &var_str[..var_str.len() - 1])
```

# Solution

Use strip_suffix('}') and pass the input through when it isn't a
variable reference

## Testing

added tests to cover this

To reproduce on Windows, add a context server with a malformed argument
to settings.json:

```

"context_servers": {
  "crash-repro": {
    "command": "does-not-matter",
    "args": ["${"]
  }
}
}
````
Opening the agent panel and zed will crash

Release Notes:

- Fixed a panic when converting a malformed `${` shell variable
reference on Windows

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
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
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
`wayland-backend` falls back to `eprintln!` when its optional `log`
feature is disabled. If a Wayland connection fails while standard error
is unavailable, that fallback panics while trying to report the original
error.

Closes ZED-8BW

Enable the existing `log` feature on `gpui_linux`'s direct
`wayland-backend` dependency. `gpui_linux` already depends on the `log`
facade, so this introduces no new logging system; it routes backend
errors through the configured logger and avoids the secondary
standard-error panic.

Testing performed:

Release Notes:

- Fixed a Linux crash when reporting a Wayland connection error while
standard error is unavailable.
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
… (#63577)

Zed's `fs_embed!` macro hand-implements rust-embed's `RustEmbed` trait
in its dev arm so debug builds read assets from the checkout at runtime
(introduced with corgi support in #63396). That trait returns
`rust_embed::Filenames`, an enum with exactly one variant per
compilation context: `Dynamic` when rust-embed's `debug-embed` feature
is off, `Embedded` when it is on. The dev arm constructed
`Filenames::Dynamic` unconditionally.

Cargo unifies features across the entire build graph, so a downstream
workspace that consumes Zed's crates by git dependency and enables
`rust-embed/debug-embed` anywhere (Delta did, for self-contained debug
binaries) changes the enum's shape for `util` itself, and `util` stops
compiling with `E0599: no variant named Dynamic`. Zed's own CI can never
catch this because nothing in Zed's graph enables the feature; it only
surfaces in embedding workspaces, where it blocks any dependency bump
past #63396.

This change makes the combination supported. `util` gains a forwarding
`debug-embed` feature, and `__fs_embed_iter` now has two implementations
under cfgs that mirror rust-embed's variant availability: the existing
boxed-iterator path when the feature is off, and an `Embedded` path when
it is on, which scans the checkout once per embed site and leaks the
cached name list (the `Embedded` variant requires `'static` names; a
per-process list matches the macro's documented contract that dev edits
appear on the next launch, and `get` still reads file contents fresh on
every call). Consumers must enable the feature through
`util/debug-embed` rather than directly on rust-embed — enabling it
behind util's back still breaks, which only rust-embed itself could fix;
the feature's documentation says so.

A new test exercises the dev arm's `iter` and `get` through the macro,
and running util's suite with `--features debug-embed` covers the other
variant; both configurations pass 133 tests, plus clippy and fmt.

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
mikayla-maki and others added 14 commits September 7, 2026 12:36
Relicenses `zlog`, `ztracing`, and `ztracing_macro` from
GPL-3.0-or-later to Apache-2.0.

GPUI depends on `ztracing`, which depends on `zlog`, so these crates
have to be non-copyleft for GPUI to ship as a permissively licensed
project.

- Switched the `license` field to `Apache-2.0` in all three manifests.
- Added the `LICENSE-APACHE` symlink to `zlog`, and dropped the
`LICENSE-GPL` symlinks from all three. `ztracing` and `ztracing_macro`
already carried both symlinks; now the on-disk license matches the
manifest.
- Declared `license = "Apache-2.0"` for `gpui_util`, which had a
`LICENSE-APACHE` symlink but no `license` field. `script/check-licenses`
doesn't catch that, since it only inspects symlinks.

No source changes; none of these crates carry GPL headers or in-source
license references.

Checked the rest of the subtree while here: the only first-party crates
reachable from `ztracing` via `cargo tree -e normal` are `collections`,
`gpui_util`, `zlog`, and `ztracing_macro`, all Apache-2.0 now.
Third-party deps (`tracing`, `tracing-subscriber`, `chrono`, `log`,
`anyhow`, `tracy-client`) are MIT/Apache.

`script/check-licenses` passes.

Release Notes:

- N/A
Zed's `fs_embed!` macro normally reads assets from the checkout in debug
builds. The new `util/debug-embed` feature is intended to compile those
assets into debug binaries, but it previously changed only the
`rust_embed::Filenames` variant while leaving file loading on the
runtime path.

That breaks downstream workspaces such as Delta: the runtime loader
identifies Delta as the repository root, then looks for Zed grammar
assets under Delta's checkout. Tests consequently panic when language
configuration files cannot be found.

This makes `util/debug-embed` select a compile-time `RustEmbed`
expansion in every profile. Builds without the feature retain live
filesystem loading in debug mode. The runtime iterator no longer depends
on a feature-specific `rust_embed::Filenames` variant, so Cargo feature
unification remains safe when another package enables
`rust-embed/debug-embed` directly. The regression fixture uses a
deliberately invalid runtime path when `debug-embed` is enabled, so it
proves that the embedded path is used rather than passing only because
the Zed checkout contains the test assets.

Testing performed:

- `cargo fmt --all -- --check`
- `cargo nextest run -p util --lib`
- `cargo nextest run -p util --lib --features debug-embed`
- `cargo check -p remote_server --features debug-embed`
- `./script/clippy -p util`
- Delta's previously failing
`tools::edit_file::tests::test_edit_file_rejects_scratch_paths_as_read_only`
against this PR's head commit

Release Notes:

- N/A
…4ms (#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
* 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
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).
When scrolling, mispredicted touch events could cause scroll jitter. We
now ignore predictions that are "travelling the wrong direction".
Adds `TouchDragEvent` and coresponding APIs. This allows web/touch-based
code to capture long press events without having to go through
scroll-like APIs
…g 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>
…ut (#63614)

While working on zed-industries/zed#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
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>
Adds `Hitbox::is_hovered_at` to improve touch selection on delta web
…606)

# Objective

Fixes #63569

`run_docker_command` Debug-formatted the whole `docker exec` command, so
every `-e NAME=VALUE` pair forwarded into a dev container was written to
`Zed.log` in plaintext: once at DEBUG, and again in the error message
that `remote_client.rs` logs at ERROR on a failed reconnect.

## Solution

Render the command with `redact_arguments`, which replaces the value of
every `-e NAME=VALUE` argument with `<redacted>` before the arguments
are flattened, and pass the remaining arguments and stderr through
`util::redact::redact_command`.
Validate `containerEnv` and `remoteEnv` keys in `spawn_dev_container`
before any container is reused or built, because an empty key produced
`-e =VALUE`, which the Docker CLI rejects while echoing the value
verbatim to stderr.
Skip invalid names in `remote` as well, since `remote_env` is also
rehydrated from the workspace database.
The shared predicate lives in `util::redact::is_valid_environment_name`.

The DEBUG line now logs the redacted command and exit status only; the
previous stdout and stderr byte dumps are gone.

## Testing

`cargo test -p remote -p dev_container --lib`.
Unit tests cover redaction of forwarded env, argument boundaries,
assignments inside program arguments and stderr, invalid-name skipping
and rejection, and the podman CLI.

Release Notes:

- Fixed dev container environment variables being logged in full

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
# 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>
…n (#63759)

# Objective

Fixes #52884

On macOS, with **"Double-click a window's title bar"** set to **Fill**
and **"Tiled windows have margins"** enabled (System Settings > Desktop
& Dock), double-clicking Zed's title bar fills the whole visible frame
with no margins, while native apps leave the margin in place.

The `"Fill"` arm of `titlebar_double_click` currently falls back to
`zoom:`, with a comment stating that there is no documented API for the
Fill action. `zoom:` is the classic maximize: it targets the screen's
visible frame and never goes through the system tiling path, so the
margin preference cannot apply.

## Solution

AppKit does implement the action: `_zoomFill:` is the selector behind
**Window > Move & Resize > Fill**, and it goes through the system tiling
path. Prefer it for the `"Fill"` case, keeping `zoom:` as a fallback
when the window does not respond to it.

This means the margin geometry stays owned by the OS: neither
`EnableTiledWindowMargins` nor `TiledWindowSpacing` has to be read or
reimplemented in gpui, and the behavior follows the setting when the
user toggles it.

The selector is underscore-prefixed, hence the `respondsToSelector:`
guard and the `zoom:` fallback.

## Testing

Measured on macOS 26.6.2 (25G76), aarch64, on a 2560x1440 display with
the Dock on the left, so `visibleFrame` is `(80, 0, 2480, 1410)`. Probe:
a plain `NSWindow` (`titled`, `resizable`) in a standalone AppKit
binary, with `EnableTiledWindowMargins = 1` and `TiledWindowSpacing`
unset (default 8).

| action | resulting frame | insets vs `visibleFrame` |
| --- | --- | --- |
| `zoom:` | `(80, 0, 2480, 1410)` | 0 on all four sides |
| `_zoomFill:` | `(88, 8, 2464, 1394)` | 8 pt on all four sides |

`respondsToSelector: _zoomFill:` returns `YES` on that build. `cargo
check -p gpui_macos` and `cargo fmt -p gpui_macos -- --check` both pass.

To reproduce as a reviewer: enable both settings above, then
double-click the title bar. Before this change the window touches the
screen edges, after it the margin matches Finder or Safari. With "Tiled
windows have margins" off, both behave the same.

One behavior difference worth flagging: `zoom:` toggles, so a second
double-click used to restore the previous frame, while `_zoomFill:`
stays filled. AppKit exposes `_zoomUntile:` for the reverse direction,
which restores the pre-fill frame in my testing. I left it out to keep
the diff minimal, but I am happy to add the toggle if you would prefer
that a second double-click untiles.

I could not find a way to cover this with an automated test, since the
assertion would be about AppKit's own tiling geometry.

## 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
@nolight132

Copy link
Copy Markdown
Member

Hey, thanks for the PR. Could you split this into separate PRs, one for each change? Mixing an upstream sync with unrelated changes makes this difficult to review properly.

Feel free to close this PR and submit the changes individually.

@vrdons

vrdons commented Sep 7, 2026

Copy link
Copy Markdown
Author

Feel free to close this PR and submit the changes individually.

i will use this pr for sync upstream & update dependencies

  git: 22 packages
  incompatible: 93 packages
  latest: 201 packages
  local: 23 packages
  pinned: 4 packages
@vrdons vrdons changed the title Sync With upstream & Reduce Font allocations & Use Kawasian blur method Sync With upstream and Update crates version to latest Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.