Commit Graph
44 Commits
Author SHA1 Message Date
tidely 2e2fb0a218 zed: Unify dependencies (#61381)
# Objective

Unify dependencies inside of the root `Cargo.toml` to prevent versions
from going out of sync and creating copies of dependencies.

## Testing

- All tests pass, nothing touches the `Cargo.lock`

## Review

Review is easiest by going through commit by commit.

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-21 07:58:16 +00:00
John Tur 0c51c7fd24 Reduce overdraw for border-only quads (#61274)
Restore an optimization that I mistakenly removed in
https://github.com/zed-industries/zed/pull/54728.

Drawing a quad with a border but no fill color will run the quad
fragment shader for every transparent interior pixel, which is
especially costly when the quad is large. Instead, split these quads
into four non-overlapping strips that cover the regions where borders
are painted. The side strips own the straight left and right edges,
while the top and bottom strips own the horizontal edges and the rounded
corners.

Previously, this optimization only applied to borders drawn by the Taffy
layout. I've decided to reinstate the logic directly in `paint_quad` so
that the optimization can be applied more generally... though if this
feels like too much policy, we can move it back.

This reduces the GPU time spent painting a representative Zed scene by
about 20% or so.

Release Notes:

- N/A
2026-07-19 06:52:53 +00:00
John Tur 7eb8af27a6 gpui: Remove ExitProcess shutdown workaround (#61219)
The issue with aws-lc that necessitated this workaround has been fixed
upstream: https://github.com/aws/aws-lc/issues/3197.

Release Notes:

- N/A
2026-07-17 19:16:49 +00:00
Lukas WirthandJohn Tur de827bce2f gpui: Add system notification platform APIs (#61189)
Release Notes:

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

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-07-17 18:52:23 +00:00
tidely f1280b64a4 gpui: Unify raw-window-handle dependency (#61193)
Just something I noticed while skimming through dependencies

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-17 13:41:05 +00:00
John Tur 72656afa6d Use more efficient thread pool API on Windows (#60917)
This interface uses fewer syscalls and has less internal synchronization
(since the `TP_WORK` object is not exposed).

Release Notes:

- N/A
2026-07-14 16:40:22 +00:00
Lukas Wirthandzed-zippy[bot] 905e955a70 gpui: Implement window attention (#58779)
Release Notes:

- On agent notifications, the corresponding zed window will now mark
itself for OS level attention

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-13 11:03:51 +00:00
Richard Feldman 89e8a4b9ec gpui_windows: Harden DirectWrite and DirectX text rendering (#60124)
This hardens the Windows text rendering path in gpui_windows against
undefined behavior and out-of-bounds access. DirectWrite hands back
glyph-run arrays (glyph indices, advances, offsets) and cluster maps as
raw pointers that may be null; these are now interpreted through a
shared `slice_from_nullable` helper that treats a null pointer with zero
length as an empty slice and returns `E_INVALIDARG` when a null pointer
arrives with a nonzero length, instead of constructing a slice from a
null pointer. It also fixes a provenance bug: the renderer context
passed to `IDWriteTextLayout::Draw` was derived via `&raw const` from a
non-mut binding, but the `DrawGlyphRun` callback recovers that pointer
and writes through it, which is undefined behavior under Stacked/Tree
Borrows; the binding is now `mut` and the pointer is derived from `&raw
mut` so its provenance matches the write (codegen is unchanged).

On the DirectX side, the atlas upload is now bounded by the source slice
length so a mismatched destination region cannot read past the end of
the source, and the color-glyph staging texture is unmapped after
readback so the mapping is no longer leaked and the resource pinned. The
color-glyph rasterizer drives the shared, non-thread-safe D3D11
immediate context that `DirectXRenderer` and `DirectXAtlas` also use, so
it must stay on the main UI thread — which it always is today; a comment
documents that invariant.

Since gpui_windows is a Windows-only crate, it cannot be compiled on
non-Windows hosts, so Windows CI is the compile gate for these changes.

Release Notes:

- N/A
2026-07-13 09:54:38 +00:00
John Tur 2c4e44704c Fix "Task polled after completion" panic (#60693)
Dropping a scheduled runnable cancels its task and makes the next poll
of any awaiter panic with "Task polled after completion." The only paths
where we drop these runnables seem to be during shutdown or extreme
resource exhaustion, so, let's leak the runnables instead of crashing.

On Windows, we also moved to calling the Win32 thread pool API directly,
because 1) WinRT thread pool API is just a wrapper that adds overhead we
don't need, and 2) the closure we pass to the `WorkItemHandler` object
takes ownership of the runnable object, so if the WinRT thread pool
releases the delegate, it can free the runnable without our control.

Release Notes:

- N/A
2026-07-09 18:06:00 +00:00
Richard Feldman f281770034 gpui: Store GPU-facing bools as PaddedBool32 to avoid uninitialized padding (#60482)
`PolychromeSprite` in `crates/gpui/src/scene.rs` is `#[repr(C)]` and had
a `grayscale: bool` field followed by 3 compiler-inserted padding bytes
that were never written. The wgpu renderer's `instance_bytes`
reinterprets `&[PolychromeSprite]` as `&[u8]` via
`slice::from_raw_parts` and passes it to `queue.write_buffer`, so those
uninitialized padding bytes were exposed behind a shared `&[u8]` on
every frame that draws an image or emoji, which is undefined behavior.

Rather than widening the field to a raw `u32` (which would suggest
values other than 0 and 1 are meaningful), this introduces
`PaddedBool32`: a `#[repr(transparent)]` wrapper around `u32` whose only
public constructor is `From<bool>`, so the 0-or-1 invariant is enforced
by the type while the layout has no padding. `Underline.wavy`, which was
already a raw `u32` for the same reason, is converted too.

cbindgen emits the wrapper as `typedef uint32_t PaddedBool32;`, so the
generated Metal header and shaders are unchanged. The WGSL and HLSL
shaders already declared these fields as `u32`/`uint`; their `& 0xFFu`
masks, which existed to ignore the garbage padding bytes, are now
simplified to plain comparisons.

Release Notes:

- N/A
2026-07-09 05:37:35 +00:00
Richard Feldman 23c0080d1d gpui_windows: Check composition attribute lookup (#60122)
Checks that SetWindowCompositionAttribute was found before transmuting
and calling the function pointer, making the composition setup a no-op
when the undocumented export is unavailable.

Release Notes:

- N/A
2026-07-08 19:27:01 +00:00
Philipp Schaffrath 546a16d64f gpui: Add parent-anchored native popup windows (with wayland xdg_popup implementation only so far) (#60232)
# Objective

gpui can't show UI that extends past the window it belongs to. Menus,
dropdowns and tooltips are drawn as elements inside the window, so they
clip at its edges. This PR adds a window kind for platform-native popups
anchored to a parent window, as groundwork for real native menus,
dropdowns and tooltips.

## Solution

`WindowKind::AnchoredPopup(PopupOptions)` opens a popup positioned
relative to a parent window. Instead of giving the popup an absolute
position, you describe where it should go and the platform figures out
the rest:

- `parent`: the window to anchor to
- `anchor_rect`: a rectangle in the parent, e.g. the button that opened
the menu
- `anchor` and `gravity`: which point of that rect to attach to, and
which direction to grow
- `constraint_adjustment`: what the platform may do if the popup would
leave the screen (slide, flip, resize)
- `grab`: menu behavior, the popup takes focus and is dismissed when
clicking outside the app

The popup's size comes from `WindowOptions::window_bounds`.

This model mirrors Wayland's `xdg_positioner`, where the compositor owns
positioning and the client can only describe intent. Since that's the
most restrictive case, the other platforms can implement the same
description later with simple math against screen bounds.

Only Wayland is implemented so far, via `xdg_popup` on top of the
existing surface implementation. Popups can be parented to toplevels,
layer-shell surfaces (a menu opened from a panel) and other popups
(nested menus). macOS, Windows, X11 and web reject the kind with
`PopupNotSupportedError`, so callers can detect that and fall back to
in-window popovers.

Some Wayland details that might help during review:

- Anchor rects are translated from gpui coordinates into the parent's
window geometry space and clamped to it. A rect outside the geometry, or
with zero size, is a fatal protocol error
- Resizing a mapped popup goes through `xdg_popup.reposition`
- Mouse press serials are now recorded on press only, not release.
Compositors decline grabs and interactive moves that reference a release
serial

## Testing

Tested manually on Wayland with an example app: the menu opens anchored
below its button, extends past the parent window, flips above the button
near the bottom of the screen, and a grabbing popup is dismissed when
clicking into another application.

Nested menus were tested in one of my projects (ignore that they are
ugly, that's just a prototype 😛):


https://github.com/user-attachments/assets/2cd3e2e9-87f7-4b02-986f-48e5633e205c




I also have a complete runnable example demonstrating it. I did not add
it to the PR, because this might give the impression that
`WindowKind::AnchoredPopup` are a complete implementation, despite only
working on wayland so far:

<details>
  <summary>Click to view example</summary>

```rust
//! Example and manual test for platform-native popups (`WindowKind::AnchoredPopup`).
//!
//! A native popup is a real, parent-anchored window that can extend beyond its parent onto the
//! screen, unlike gpui's in-window popovers. Run it, open the menu, and confirm the points listed
//! in the window. On a platform without an implementation the button reports that popups are not
//! supported instead of opening anything.
//!
//! Run with: cargo run -p gpui --example popup

#![cfg_attr(target_family = "wasm", no_main)]

use gpui::{
    AnyWindowHandle, App, Bounds, Context, MouseButton, SharedString, Window, WindowBounds,
    WindowHandle, WindowKind, WindowOptions, div, point, popup::*, prelude::*, px, rgb, size,
};
use gpui_platform::application;

/// The trigger button, at a fixed position so the popup can anchor to a known rectangle. Real code
/// would anchor to the measured bounds of whatever element opens the popup.
const BUTTON_BOUNDS: Bounds<gpui::Pixels> = Bounds {
    origin: point(px(24.), px(24.)),
    size: size(px(200.), px(32.)),
};

const POPUP_SIZE: gpui::Size<gpui::Pixels> = size(px(260.), px(320.));

struct Menu;

impl Render for Menu {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        let item = |label: &str| {
            div()
                .id(label.to_string())
                .px_3()
                .py_1()
                .rounded_sm()
                .hover(|this| this.bg(rgb(0x3a3a3a)))
                .cursor_pointer()
                .child(label.to_string())
                .on_click(|_, window, _| window.remove_window())
        };

        div()
            .id("menu-root")
            .size_full()
            .p_1()
            .flex()
            .flex_col()
            .gap_0p5()
            .bg(rgb(0x2a2a2a))
            .text_color(gpui::white())
            .rounded_md()
            .border_1()
            .border_color(rgb(0x454545))
            .child(item("Foo"))
            .child(item("Bar"))
            .child(item("Baz"))
            .child(item("Qux"))
            .child(item("Alice"))
            .child(item("Bob"))
    }
}

struct PopupExample {
    menu: Option<WindowHandle<Menu>>,
    status: SharedString,
}

impl Default for PopupExample {
    fn default() -> Self {
        Self {
            menu: None,
            status: "Click \"Open menu\" to open a native popup.".into(),
        }
    }
}

impl PopupExample {
    /// Closes the menu if it is open. Returns true if a menu was actually open.
    fn close_menu(&mut self, cx: &mut App) -> bool {
        match self.menu.take() {
            Some(menu) => menu
                .update(cx, |_, window, _| window.remove_window())
                .is_ok(),
            None => false,
        }
    }

    fn toggle_menu(&mut self, parent: AnyWindowHandle, cx: &mut App) {
        if self.close_menu(cx) {
            return;
        }
        match open_menu(parent, cx) {
            Ok(menu) => {
                self.menu = Some(menu);
                self.status = "Menu open. Dismiss it by selecting an item, clicking elsewhere in \
                    this window, or clicking another application."
                    .into();
            }
            // A real application would fall back to an in-window popover here.
            Err(error) => {
                self.status = format!("Failed to open a native popup: {error}").into();
                log::error!("failed to open popup: {error}");
            }
        }
    }
}

impl Render for PopupExample {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        let bullet = |text: &str| div().child(format!("• {text}"));

        div()
            .id("root")
            .size_full()
            .bg(rgb(0xf7f7f7))
            .text_color(rgb(0x222222))
            // Same-app clicks don't auto-dismiss a grabbing popup (see `PopupOptions::grab`).
            .on_mouse_down(
                MouseButton::Left,
                cx.listener(|this, _, _window, cx| {
                    this.close_menu(cx);
                }),
            )
            .child(
                div()
                    .size_full()
                    .p_5()
                    .pt(px(76.))
                    .flex()
                    .flex_col()
                    .gap_3()
                    .child(div().text_xl().child("Native popup test"))
                    .child(div().text_sm().child(
                        "WindowKind::AnchoredPopup opens a real, parent-anchored window that can \
                         extend past this window onto the screen. Only some platforms implement \
                         it so far.",
                    ))
                    .child(
                        div()
                            .flex()
                            .flex_col()
                            .gap_1()
                            .text_sm()
                            .text_color(rgb(0x555555))
                            .child(div().child("Verify:"))
                            .child(bullet("The menu opens anchored below the button."))
                            .child(bullet(
                                "The menu extends past the bottom edge of this window.",
                            ))
                            .child(bullet(
                                "Near the bottom of the screen, the menu flips above the button.",
                            ))
                            .child(bullet("Clicking another application dismisses the menu."))
                            .child(bullet(
                                "Selecting an item or clicking in this window dismisses it.",
                            )),
                    )
                    .child(
                        div()
                            .text_sm()
                            .text_color(rgb(0x333333))
                            .child(self.status.clone()),
                    ),
            )
            .child(
                div()
                    .absolute()
                    .left(BUTTON_BOUNDS.origin.x)
                    .top(BUTTON_BOUNDS.origin.y)
                    .w(BUTTON_BOUNDS.size.width)
                    .h(BUTTON_BOUNDS.size.height)
                    .flex()
                    .items_center()
                    .justify_center()
                    .bg(rgb(0xffffff))
                    .border_1()
                    .border_color(rgb(0xd0d0d0))
                    .rounded_md()
                    .cursor_pointer()
                    .id("open-menu")
                    .active(|this| this.bg(rgb(0xeeeeee)))
                    .child("Open menu ▾")
                    // Open on mouse-down, not on click, so the grab is taken while the button is still held.
                    .on_mouse_down(
                        MouseButton::Left,
                        cx.listener(|this, _, window, cx| {
                            // Don't let the window handler above close the menu we are opening.
                            cx.stop_propagation();
                            this.toggle_menu(window.window_handle(), cx);
                        }),
                    ),
            )
    }
}

fn open_menu(parent: AnyWindowHandle, cx: &mut App) -> anyhow::Result<WindowHandle<Menu>> {
    cx.open_window(
        WindowOptions {
            titlebar: None,
            // Sizes the popup. The platform decides the position, so the origin is ignored.
            window_bounds: Some(WindowBounds::Windowed(Bounds {
                origin: point(px(0.), px(0.)),
                size: POPUP_SIZE,
            })),
            kind: WindowKind::AnchoredPopup(PopupOptions {
                parent,
                anchor_rect: BUTTON_BOUNDS,
                // Anchor to the button's bottom-left and grow down-right so the menu drops beneath it.
                anchor: PopupAnchor::BottomLeft,
                gravity: PopupGravity::BottomRight,
                // Slide horizontally and flip vertically if the menu would leave the screen.
                constraint_adjustment: PopupConstraintAdjustment::SLIDE_X
                    | PopupConstraintAdjustment::FLIP_Y,
                offset: point(px(0.), px(4.)),
                // Grab input so the compositor dismisses the popup on clicks into other applications.
                grab: true,
            }),
            ..Default::default()
        },
        |_, cx| cx.new(|_| Menu),
    )
}

fn run_example() {
    application().run(|cx: &mut App| {
        cx.open_window(
            WindowOptions {
                window_bounds: Some(WindowBounds::Windowed(Bounds {
                    origin: point(px(100.), px(100.)),
                    size: size(px(420.), px(300.)),
                })),
                ..Default::default()
            },
            |_, cx| cx.new(|_| PopupExample::default()),
        )
        .unwrap();
        cx.activate(true);
    });
}

#[cfg(not(target_family = "wasm"))]
fn main() {
    run_example();
}

#[cfg(target_family = "wasm")]
#[wasm_bindgen::prelude::wasm_bindgen(start)]
pub fn start() {
    gpui_platform::web_init();
    run_example();
}
```

</details>

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

---

Release Notes:

- N/A
2026-07-08 19:22:23 +00:00
迷渡 7194f987a7 Fix disabled Windows window controls (#60440)
## Summary

- Store Windows window minimizable and resizable capabilities on
`WindowsWindowInner`.
- Prevent custom titlebar hit testing from returning minimize/maximize
button hit targets when the corresponding capability is disabled.
- Swallow disabled native non-client minimize/maximize button mouse
events so they cannot fall through to the default window procedure or
GPUI's manual `ShowWindowAsync` handling.

Fixes #52067.

## Validation

- `cargo fmt --package gpui_windows`
- `cargo check -p gpui_windows`
- `git diff --check`

Release Notes:

- Fixed disabled minimize and maximize window controls still activating
on Windows.
2026-07-07 09:01:58 +00:00
ArtinandSmit Barmase 5aa6e8a0b3 Reduce OAuth scope to avoid Windows credential size limit (#58541)
I encountered an issue where I couldn't sign in to ChatGPT Subscription
on Windows:

```
ChatGPT subscription sign-in failed to persist credentials: 
Failed to write credentials to Windows Credential Manager: 
占位程序接收到错误数据。 (0x800706F7)
```

Interestingly, only one of my three ChatGPT accounts had this problem —
the other two signed in successfully.

## What I Found

After investigating, I noticed that the OAuth scope in
`openai_subscribed.rs` requests 6 permissions:

```
openid profile email offline_access api.connectors.read api.connectors.invoke
```

I wrote a test script to measure token sizes and found that:
- With 6 scopes: my problematic account's token was **2578 bytes**
- With 4 scopes (removing `api.connectors.read` and
`api.connectors.invoke`): the same token was **2516 bytes**

Since Windows Credential Manager has a 2560-byte limit
(`CRED_MAX_CREDENTIAL_BLOB_SIZE`), this could explain why some accounts
fail while others succeed — it depends on the base token size.

## My Hypothesis

The issue seems to be that:
- Error code `0x800706F7` = `RPC_X_BAD_STUB_DATA` (size limit, not
format)
- Accounts with larger base tokens exceed the limit when the extra 48
chars are added
- Accounts with smaller base tokens still fit, which is why this isn't
universally reproducible

I'm not 100% certain this is the root cause, but the evidence seems to
point in this direction.

## Proposed Fix

I removed `api.connectors.read` and `api.connectors.invoke` from the
OAuth scope, since:
- These scopes don't appear to be used by Zed's current ChatGPT
integration
- OpenCode (another tool using the same OAuth provider) successfully
uses only 4 scopes
- This fix allowed my problematic account to sign in

However, I'd like to ask the maintainers:
- Are there plans to use OpenAI Connectors API in the future?
- Are there security or compliance reasons for requesting these extra
scopes?

If the answer is yes to either, we'd need a different approach (e.g.,
splitting credentials, using encrypted file storage, or checking token
size before storage).

## Testing

- [x] Verified my problematic account now signs in successfully
- [x] Verified my other accounts still work
- [x] Ran `cargo check -p language_models` (compilation successful)
- [ ] Would appreciate help testing on macOS/Linux

## Questions

1. Does this analysis make sense?
2. Are there any other considerations I'm missing?
3. Would it be helpful to add a size check with a clearer error message
for future cases?

I'm happy to adjust this approach based on your feedback.

Release Notes:

- Fixed ChatGPT Subscription sign-in failing on Windows for some
accounts by removing unused OAuth scopes (`api.connectors.read`,
`api.connectors.invoke`) that pushed JWT tokens over Windows Credential
Manager's limit.

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-03 19:38:42 +00:00
Agus Zubiaga ee571d3c69 gpui: Add system wake callback (#59831)
# Objective

GPUI apps currently don't have a cross-platform way to react when the
system wakes from sleep.

## Solution

Add `Application::on_system_wake`, backed by platform hooks for macOS,
Windows, and Linux. The platform listeners are registered lazily once an
app installs a wake callback.

## Testing

- N/A

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

Release Notes:

- N/A
2026-06-24 19:59:34 +00:00
Lukas Wirth 9ac117693b gpui_windows: Fix immovable windows skipping hit testing entirely (#59816)
Prior to this, marking a window as immovable would prevent the title bar
buttons working on windows.

Release Notes:

- N/A
2026-06-24 16:31:35 +00:00
Cole Miller a873cf402c Remove gpui's dependency on async-process (#59358)
This removes gpui's dependency on the `util` crate, which depends on
async process. It now depends on `gpui_util` only, and uses
`std::process::Command` for the two cases where it was previously using
an async `Command`. This lifts the requirement of non-Zed consumers of
gpui to depend on our forked async-process (see #59156).

Release Notes:

- N/A
2026-06-16 13:47:55 +00:00
Konstantinos St bb59dc59fa Fix miscellaneous typos (#58979)
Some typos I found while reading the code

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:

- N/A
2026-06-09 22:46:22 +00:00
Anthony Eid 0d8a4d4292 gpui: Free atlas tile space when removing tiles (#58874)
Partially addresses #54659

`PlatformAtlas::remove` removed the tile from `tiles_by_key` and
decremented the texture's refcount, but never returned the tile's
rectangle to the etagere allocator. Removed tiles' space could only be
reclaimed if the entire texture was dropped, which doesn't happen if
glyph/emoji share the texture. Because we don't have correct glyph/emoji
removal

I added regression tests on all three platforms to prevent this from
occurring as well.

Note: this doesn't fix glyph eviction or the nil-texture panic from
#54659; those are follow ups.

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

Closes #ISSUE

Release Notes:

- gpui: Fix GPUI memory growing unboundedly when images are repeatedly
loaded and released
2026-06-08 23:09:47 +00:00
Yara 🏳️‍⚧️ 39f7849a0f Log worst hanging tasks and actions (#57835)
We have a lot of long blocking tasks on both the foreground and
background, this is a start of getting some insight into those.

We will now log tasks running longer then 100ms on the foreground or
background. Hanging actions will also be logged including their name. We
simultaneously collect statistics on task and action performance and
send those to telemetry. This includes quantiles and averages for each
hanging task.

Finally this adds tree dev actions: 
- hang action
- hang foreground
- hang background

These cause a hang to check if hang reporting is working and in the
future telemetry.

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

Closes #ISSUE

Release Notes:

- Added logging and telemetry of tasks and actions with performance
issues
2026-06-02 12:03:05 +00:00
1d029c5ff5 gpui: Accesskit support (#56065)
GPUI AccessKit integration

This PR is replacing #51097 , and is much more limited in scope. This PR
*ONLY* adds AccessKit support to GPUI, and doesn't touch Zed. Once this
lands, we can start adding aria attributes to Zed's components.

This PR is the first step to addressing #41138 .

Release Notes:

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

---------

Co-authored-by: John Tur <john-tur@outlook.com>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Agus Zubiaga <agus@zed.dev>
2026-05-27 18:17:59 +00:00
Danilo LealandAgus Zubiaga eb944cfd7a gpui: Add support for inset shadow (#57685)
This PR adds support for inset shadows in the box shadow through the
`inset: true` field. It includes support for both the macOS as well WGSL
shaders. For now, there is no immediate application of it in Zed, so
nothing should change in the app.

<img width="600" alt="Screenshot 2026-05-25 at 8  46@2x"
src="https://github.com/user-attachments/assets/db564a6b-8af5-491a-a573-17c060a3647c"
/>

Run the example above with `cargo run --example shadow -p gpui`.

Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
2026-05-26 14:32:45 +00:00
Lukas WirthandZed Zippy 5c0b33f72e gpui_windows: Avoid process-wide priority elevation (#56050)
We were incorrectly calling this with a thread handle, additionally
changing the process priority here doesn't make sense, so just drop
this.

Release Notes:

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

---------

Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-05-07 14:09:39 +00:00
Ben Brandt 7d19e89988 Fix DirectX atlas panic after GPU device recovery (#55878)
## Problem

A Sentry-reported crash on Windows (Intel Iris Xe Graphics, v1.0.1):

```
index out of bounds: the len is 1 but the index is 1
```

panicking at `DirectXAtlasState::texture` in

[`crates/gpui_windows/src/directx_atlas.rs`](https://github.com/zed-industries/zed/blob/main/crates/gpui_windows/src/directx_atlas.rs):

```rust
AtlasTextureKind::Subpixel => {
    &self.subpixel_textures[id.index as usize].as_ref().unwrap()
}
```

## Root cause

After a GPU device-lost recovery, GPUI's view cache replays stale
`AtlasTile`
references from the previous frame's `paint_operations` via
`Scene::replay`.

1. **Atlas grows past one texture.** A long enough session pushes
`subpixel_textures.textures.len() ≥ 2` (easy on Iris Xe at the default
1024×1024 atlas size). Top-level views in Zed use `cached(...)`, so
their
`AnyViewState.paint_range` records into
`rendered_frame.scene.paint_operations`,
   referencing both index `0` and index `1`.
2. **Device lost.** `handle_device_lost` clears every `AtlasTextureList`
(`textures.len() == 0`)
   and `tiles_by_key`, then sets `skip_draws = true`.
3. **`WM_GPUI_FORCE_UPDATE_WINDOW` arrives.** `mark_drawable()` flips
`skip_draws` back to `false` and `request_frame` runs with
`force_render: true`.
4. **The cache hit.** Inside `Window::draw`, `AnyView::prepaint`'s cache
check (`!dirty_views.contains(...) && !window.refreshing`) succeeds for
every cached view because the recovery doesn't touch invalidator state
and
`force_render` doesn't propagate into `Window`. `AnyView::paint` calls
`window.reuse_paint` → `Scene::replay` → `primitive.clone()`, which
(since
   `SubpixelSprite`/`AtlasTile` are `Copy`) verbatim copies a
`Primitive::SubpixelSprite { tile: { texture_id: { index: 1, ... }, ...
} }`
   into `next_frame.scene`.
5. **Atlas regrows to one.** Dirty/uncached parts of the same frame
   (caret, animations, anything that called `cx.notify`) fall through to
   `paint_glyph` → `get_or_insert_with` → `push_texture`, growing
`subpixel_textures.textures` from `0` to **`1`** with index `0` valid.
6. **Panic.** After `mem::swap`, `rendered_frame.scene` contains a mix
of
   fresh `index = 0` and replayed `index = 1` sprites. `Scene::batches`
emits separate batches per `texture_id`; the `index = 1` batch reaches
   `atlas.get_texture_view` → `subpixel_textures[1]` → panic with
   `len = 1, index = 1`.

The two earlier related fixes do not catch this:

- **#52389 / dbd95ea7** (`if force_render { mark_drawable }`) protects
the
200 ms recovery sleep — pending `WM_PAINT`s carry `force_render = false`
  and so do not clear `skip_draws`. But `WM_GPUI_FORCE_UPDATE_WINDOW`
  carries `force_render = true`, so `mark_drawable` runs, then
  `Window::draw`'s `reuse_paint` still reproduces stale tiles.
- The unmerged Windows draft `2e5d890e37`
(`force_render_after_recovery`)
  similarly only forces the forced-render branch — it doesn't bypass the
  view cache.

## Fix

Two parts:

**1. Bypass the view cache on a forced draw (cross-platform).**

In the platform-agnostic `request_frame` closure in `Window::new`, call
`window.refresh()` whenever `RequestFrameOptions::force_render` is
`true`.
`Window::refresh` is the documented escape hatch for cached views (per
the
`AnyView::cached` docs: *"The one exception is when [Window::refresh] is
called, in which case caching is ignored."*). With `refreshing = true`
every `AnyView::prepaint` cache check fails, every cached view fully
repaints, and `paint_glyph` allocates fresh tiles for every glyph, so
`rendered_frame.scene` ends up free of stale `AtlasTile`s.

**2. Add the `force_render_after_recovery` flag on Windows.**

Mirror the Linux fix from #52389: a per-window `Cell<bool>` set after
`WindowsWindowInner::handle_device_lost` succeeds and consumed at the
top
of `draw_window`. Together with the GPUI change above, the first frame
after recovery (whether a stray `WM_PAINT` during the 200 ms recovery
sleep or the explicit `WM_GPUI_FORCE_UPDATE_WINDOW`) is treated as a
forced render that both clears `skip_draws` and bypasses the view cache.

## Testing

- `script/clippy -p gpui` is clean.
- I do not have a Windows toolchain available locally, so I have not
  cross-compiled `gpui_windows`. Reviewers with Windows access — please
  smoke-test on a machine where the device-lost path can be exercised
  (Intel iGPU, suspend/resume, or running a TDR-inducing test on a GPU
  driver).

## Related

- Sentry issue ID 7457971403 (DirectX subpixel atlas crash, Intel Iris
Xe).
- Builds on / fixes the residual gap in #52389 (`gpui_linux: Force scene
  rebuild after GPU device recovery"). The GPUI change here also hardens
  the corresponding Linux path against the same `reuse_paint` mechanism.

Release Notes:

- Fixed a crash on Windows when the GPU device is lost and recovered
during use (typically driver crash, suspend/resume, or display
reconfiguration, most commonly on Intel iGPUs)
2026-05-07 10:22:52 +00:00
Lukas WirthandJohn Tur f5945344cc gpui(windows): Fix unwrap panic when monitor goes missing (#55630)
Fixes ZED-5K1

Release Notes:

- Fixed a panic on windows when a monitor disappears from windows
monitor enumeration

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-05-06 07:35:40 +00:00
Agus Zubiaga a03729b6c0 Handle hiding cursor on keyboard input at GPUI level (#55664)
Instead of manually handing hiding the cursor on keyboard input at the
editor level, GPUI will now take care of it.

This makes it significantly easier to handle the edge cases, and allows
delegating the cursor restoration to the platform itself in the macOS
case. On Linux and Windows, we still have to restore the cursor on
movement ourselves, but this now happens at the platform-specific level.

Bugs fixed by this change:
- No cursor when "Unsaved edits" prompt appears
- Cursor disappears when clicking a panel button if it contains a search
bar (e.g. collab panel)

### Setting rename

The `hide_mouse` setting value `"on_typing_and_movement"` has been
renamed to `"on_typing_and_action"` to better reflect what it actually
does — it hides the cursor when a keystroke resolves to an action (e.g.
cursor movement, deletion). Existing settings are migrated
automatically.

### Tested platforms
- [x] macOS
- [x] Wayland
- [x] X11
- [x] Windows
- [x] Web

Self-Review Checklist:

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

Release Notes:

- Renamed the `hide_mouse` setting value `on_typing_and_movement` to
`on_typing_and_action` to better describe its behavior (existing
settings are auto-migrated)
- Fixed a few situations where the mouse cursor would be incorrectly
hidden
2026-05-04 22:51:56 +00:00
John Tur ee3b65773e Support BGR subpixel layout (#55174)
Release Notes:

- Added text rendering support for BGR subpixel layouts.
2026-04-29 12:26:19 +00:00
John Tur 067ec60e1a Fix process teardown deadlock on Windows (#55065)
AWS-LC registers an `atexit` handler that intentionally acquires a lock
without releasing it. AWS-LC also has `thread_local` objects which
acquire this lock in their destructor. Destructors for `thread_local`s
run under the loader lock. So, there is a race condition where, if a
thread exits after `atexit` handlers have run, the TLS destructors will
block indefinitely on this lock while holding the loader lock. Since
`ExitProcess` also requires the loader lock, process teardown will
deadlock.


Closes #54856

Release Notes:

- Fixed an issue where the Zed process wouldn't exit after closing all
windows
2026-04-28 08:19:03 +00:00
John Tur 847510ca4b Fix broken is_maximized check on Windows (#54436)
Bad change from https://github.com/zed-industries/zed/pull/54321

Fixes https://github.com/zed-industries/zed/issues/54418

Release Notes:

- N/A
2026-04-21 13:35:13 -04:00
Lukas Wirth a62ae579ab Performance tweaks (#54321)
Release Notes:

- N/A or Added/Fixed/Improved ...
2026-04-21 07:25:22 +00:00
HuaGu-Dragon 38270bc027 Fix Alt modifier stuck after Alt-Tab on Windows (#52220)
## Context

Fixes a bug on Windows where the Alt modifier key becomes stuck in the
pressed state after using Alt-Tab to switch away from and back to the
Zed application.

### Root Cause
In `crates/gpui_windows/src/events.rs`, when the window loses focus
during Alt-Tab, the WM_KEYUP event for the Alt key is never delivered to
the application. The pending modifier state in GPUI remains as
`alt=true`. When the window regains focus, there is no synchronization
point to reset this stale state.

## How to Review

In `handle_activate_msg()` (WM_ACTIVATE handler), when the window is
activated:
1. Reset the cached modifier tracking state (`last_reported_modifiers`
and `last_reported_capslock` set to `None`)
2. Query the actual current modifier state from Windows using
`GetKeyState()` APIs
3. Dispatch a `ModifiersChanged` event with the true state to
synchronize GPUI

## Self-Review Checklist

<!-- Check before requesting review: -->
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

I think it's difficult to add tests for this because it's
platform-dependent, but I recorded a video for comparison — sorry I only
have an anime‑style app to show the key presses.

<details>
  <summary>Video</summary>
  


https://github.com/user-attachments/assets/b545178c-b360-4e2b-8d60-d6f95a0b4b79



https://github.com/user-attachments/assets/bc4d41eb-6f42-4040-a588-0fc46c576db7


</details>

Closes #45485

Release Notes: 

- Fixed Alt modifier key stuck after Alt-Tab on Windows. Modifier state
is now synchronized when the window regains focus, ensuring correct key
interpretation after window switching.
2026-04-18 01:11:47 +02:00
Bowen Xu 5375ca0ae2 gpui: Add display_handle implementation for Windows, update it for macOS (#52867)
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:

- N/A
2026-04-04 16:10:22 -04:00
Ian Chamberlain 971775e3b2 gpui: Implement audible system bell (#47531)
Relates to #5303 and
https://github.com/zed-industries/zed/issues/40826#issuecomment-3684556858
although I haven't found anywhere an actual request for `gpui` itself to
support a system alert sound.

### What

Basically, this PR adds a function that triggers an OS-dependent alert
sound, commonly used by terminal applications for `\a` / `BEL`, and GUI
applications to indicate an action failed in some small way (e.g. no
search results found, unable to move cursor, button disabled).

Also updated the `input` example, which now plays the bell if the user
presses <kbd>backspace</kbd> with nothing behind the cursor to delete,
or <kbd>delete</kbd> with nothing in front of the cursor.

Test with `cargo run --example input --features gpui_platform/font-kit`.

### Why
If this is merged, I plan to take a second step:
- Add a new Zed setting (probably something like
`terminal.audible_bell`)
- If enabled, `printf '\a'`, `tput bel` etc. would call this new API to
play an audible sound

This isn't the super-shiny dream of #5303 but it would allow users to
more easily configure tasks to notify when done. Plus, any TUI/CLI apps
that expect this functionality will work. Also, I think many terminal
users expect something like this (WezTerm, iTerm, etc. almost all
support this).

### Notes
~I was only able to test on macOS and Windows, so if there are any Linux
users who could verify this works for X11 / Wayland that would be a huge
help! If not I can try~

Confirmed Wayland + X11 both working when I ran the example on a NixOS
desktop

Release Notes:

- N/A
2026-04-01 02:50:01 +00:00
iam-liam a46858ac21 gpui: Add dithering to linear gradient shader (#51211)
Linear gradients in dark color ranges (5-15% lightness) show visible
banding due to 8-bit quantization — only ~7 distinct values exist in
that range, producing hard steps instead of smooth transitions. This
affects every dark theme in Zed.

## What this does

Adds triangular-distributed dithering after gradient interpolation in
both the Metal and HLSL fragment shaders. The noise breaks up
quantization steps at the sub-pixel level, producing perceptually smooth
gradients.

## How it works

Two hash-based pseudo-random values (seeded from fragment position x
golden ratio) are summed to produce a triangular probability
distribution. This is added to the RGB channels at +/-1/255 amplitude.

- **Triangular PDF** — mean-zero, so no brightness shift across the
gradient
- **+/-1/255 amplitude** — below perceptual threshold, invisible on
bright gradients where 8-bit precision is already sufficient
- **Deterministic per-pixel** — seeded from position, no temporal
flickering
- **Zero-cost** — a couple of `fract`/`sin` per fragment, negligible vs.
the existing gradient math

### Channel-specific amplitudes

  | Channel | Amplitude | Rationale |

|---------|-----------|----------------------------------------------------------------------------------------------------|
| RGB | ±2/255 | Breaks dark-on-dark banding where adjacent 8-bit values
are perceptually close |
| Alpha | ±3/255 | Alpha gradients over dark backgrounds need stronger
noise — α × dark color = tiny composited steps |

The higher alpha amplitude is necessary because when a semi-transparent
gradient (e.g., 0.4 → 0.0 alpha) composites over a dark background, the
effective visible difference per quantization step is smaller than the
RGB case. ±3/255 is still well below the perceptual threshold on
bright/opaque elements.

## Scope

Two files changed, purely additive:

| File | Change |
|------|--------|
| `crates/gpui_macos/src/shaders.metal` | 13 lines after `mix()` in
`fill_color()` |
| `crates/gpui_windows/src/shaders.hlsl` | 13 lines after `lerp()` in
`gradient_color()` |

No changes to Rust code, no API changes, no new dependencies.

## Screenshots

<img width="1886" height="1003" alt="gradient_dithering_before"
src="https://github.com/user-attachments/assets/f75ae93b-b142-4d0e-9b61-e08f30fe1758"
/>

_Before_

<img width="1902" height="1052" alt="gradient_dithering_after"
src="https://github.com/user-attachments/assets/7aee9a36-f578-4e08-a846-44d092bcf043"
/>

_After_

## Test plan

This is a shader-level fix; no Rust test harness exists for visual
output. Manual testing is appropriate here. Visual regression tests
cover UI layout, not sub-pixel rendering quality.

**Manual (macOS):**

- [x] Dark gradients (5-13% lightness range) — banding eliminated
- [x] Bright gradients — no visible difference (dither amplitude below
precision threshold)
- [x] Oklab and sRGB color spaces — both paths dithered
- [x] Solid colours, pattern fills, checkerboard — unaffected (dither
only applies to LinearGradient case)
- [x] Alpha gradients (semi-transparent over dark bg) — banding
eliminated with alpha dithering
- [x] Path gradients (paint_path) — same fill_colour() function,
dithering applies

**Windows:** HLSL change is identical logic with HLSL built-ins
(`frac`/`lerp` vs `fract`/`mix`) — not tested locally.

Release Notes:

- Improved linear gradient rendering by adding dithering to eliminate
visible banding in dark color ranges

Liam
2026-03-30 16:23:07 +00:00
MostlyKandJohn Tur 6694a3bd14 gpui: Implement pinch event support for X11 and Windows (#51354)
Closes #51312 

- Remove platform-specific #[cfg] gates from PinchEvent, event
  listeners, and dispatch logic in GPUI
- Windows: Intercept Ctrl+ScrollWheel (emitted by precision trackpads
  for pinch gestures) and convert them to GPUI PinchEvents
- Image Viewer: remove redundant platform-specific blocks
- X11: Bump XInput version to 2.4 and implement handlers for
  XinputGesturePinch events


- [x] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Pinching gestures now available on all devices.

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-03-28 18:41:33 -04:00
a92283111b Don't preallocate 600MB for GPUI profiler (#45197)
Previously, the GPUI profiler allocates one CircularBuffer per thread,
and `CircularBuffer<N>` always preallocates space for N entries. As a
result it allocates ~20MB/thread, and on my machine about 33 threads are
created at startup for a total of 600MB used.

In this PR I change it to use a VecDeque that can gradually grow up to
20MB as data is written. At least in my experiments it seems that this
caps overall usage at about 21MB perhaps because only one thread writes
very much usage data.

Since this is fixed overhead for everyone running Zed it seems like a
worthwhile gain.

This also folds duplicated code across platforms into the common gpui
profiler.

Before:

<img width="4804" height="2192" alt="Image"
src="https://github.com/user-attachments/assets/7060ee5b-ef80-49cb-b7be-de33e9a2e7a5"
/>

After:

<img width="5052" height="1858" alt="image"
src="https://github.com/user-attachments/assets/513494df-0974-4604-9796-15a12ef1c134"
/>

I got here from #35780 but I don't think this is tree-size related, it
seems to be fixed overhead.

Release Notes:

- Improved: Significantly less memory used to record internal profiling
information.

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-27 10:20:21 +00:00
Lukas Wirth dbd95ea742 gpui_linux: Force scene rebuild after GPU device recovery (#52389)
After GPU device recovery clears the atlas, the next frame could
re-present a stale scene via the needs_present path (which skips scene
rebuilding). The stale scene references texture IDs that no longer exist
in the cleared atlas, causing an index-out-of-bounds panic.

Fix this by setting a force_render_after_recovery flag when device
recovery completes. The platform refresh loop reads this flag and passes
force_render: true in RequestFrameOptions, ensuring GPUI rebuilds the
scene before presenting.

Fixes ZED-5QT

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-03-25 11:32:57 +01:00
Lukas Wirth 6d9e28586a zed: Add track-project-leak feature for easier leak debugging (#52172)
Release Notes:

- N/A or Added/Fixed/Improved ...
2026-03-25 09:15:29 +00:00
Lukas Wirth 34807eb146 gpui_macos: Fix stale atlas key causing crash on None texture lookup (#51996)
MetalAtlas::remove() used tiles_by_key.get(key) to look up the texture
ID but only called tiles_by_key.remove(key) when the texture became
fully unreferenced. When a tile was removed while other tiles remained
on the same texture, the key stayed in tiles_by_key as a stale entry.

Once subsequent removals deleted the texture, get_or_insert_with could
return the stale tile referencing a now-deleted texture slot, causing an
unwrap panic in MetalAtlasState::texture().

Fix: change .get(key) to .remove(key) unconditionally, matching the WGPU
and DirectX atlas implementations which already do this correctly.

Closes ZED-5KV

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-03-24 20:25:35 -06:00
John Tur 2aa3666063 Improve clipboard support on Windows (#51807)
- Simplify and improve Windows clipboard handler.
- Fixed components that weren't handling multiple formats on the
clipboard properly.

Closes https://github.com/zed-industries/zed/issues/51278

Release Notes:

- windows: Fixed an issue where text copied from Office applications
couldn't be pasted into Zed.
2026-03-18 22:09:26 -04:00
John Tur 4031db17df Disable the IME on Windows when text input is unexpected (#51041)
Fixes #42444

- Changed `accepts_text_input` on the editor to be more precise.
Previously, it returned `true` only in insert mode. Now it also returns
`true` when an operator is pending.
- On Windows, we disable the IME whenever there is no input handler
which `accepts_text_input`.
- How this improves Vim mode: in insert mode, the IME is enabled; in
normal mode, it is disabled (command keys are not intercepted); when an
operator is pending, the IME is re-enabled.

Release Notes:

- On Windows, the IME is disabled in Vim normal and visual modes.
2026-03-08 04:54:05 +00:00
Conrad IrwinandEric Holk 6c9b813f38 Remove Executor::close() (#50970)
Co-Authored-By: Eric Holk <eric@zed.dev>

In app drop we had been calling `.close()` on the executors. This caused
problems with the BackgroundExecutor on Linux because it raced with
concurrent work: If task A was running and about to poll task B, the
poll to task B would panic with "Task polled after completion". This
didn't really matter (because the app was shutting down anyway) but
inflated our panic metrics on Linux.

It turns out that the call to `.close()` is not needed. It was added to
prevent foreground tasks being scheduled after the app was dropped; but
on all platforms the App run method does not return until after the
ForegroundExecutor is stopped (so no further tasks will run anyway).

The background case is more interesting. In test code it didn't matter
(the background executor is simulated on the main thread so tests can't
leak tasks); in app code it also didn't really make a difference. When
`fn main` returns (which it does immediately after the app is dropped)
all the background threads will be cancelled anyway.

Further confounding debugging, it turns out that the App does not get
dropped on macOS and Windows due to a reference cycle; so this was only
happening on Linux where the app quit callback is dropped instead of
retained after being called. (Fix in #50985)

Release Notes:

- N/A

---------

Co-authored-by: Eric Holk <eric@zed.dev>
2026-03-07 04:11:45 +00:00
John TurandMarshall Bowers c06aab84c0 Fix Windows build (#49665)
Fix regressions from https://github.com/zed-industries/zed/pull/49277:

- The fusion manifest was not being embedded for Zed.exe, making it
non-functional.
- The relative path used to load shaders in debug mode was incorrect.

Release Notes:

- N/A

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2026-02-19 19:15:59 -05:00
Piotr OsiewiczandEric Holk bc31ad4a8c gpui: Extract gpui_platform out of gpui (#49277)
#2874 on steroids

Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [ ] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- N/A

---------

Co-authored-by: Eric Holk <eric@zed.dev>
2026-02-19 18:57:49 +01:00