Commit graph

81 commits

Author SHA1 Message Date
Kevin Bravo
7150765979
Preserve --user-data-dir across restarts (#62022)
# Objective

Fixes #57701.

When Zed is launched with `--user-data-dir`, a Zed-initiated
restart—such as `workspace: clear trusted worktrees` or Restart to
Update—can relaunch Zed without that argument. The restarted process
then uses the default data directory instead of the directory selected
by the user.

## Solution

- Store the resolved custom data directory as GPUI restart arguments
alongside the existing optional restart executable path.
- Forward those arguments when relaunching on Linux, macOS, and Windows.
- Preserve argument boundaries and native `OsString` values, including
paths containing spaces.
- On Windows updates, carry the arguments through
`auto_update_helper.exe` when it launches the updated `Zed.exe`.

Normal launches without `--user-data-dir` continue to restart without
additional arguments. This does not attempt to preserve unrelated CLI
arguments or general launch state.

## Testing

- `cargo fmt --all -- --check`
- `cargo test -p gpui`
- `cargo test -p auto_update --features workspace/test-support`
- `cargo check -p auto_update_helper --tests --target
x86_64-pc-windows-msvc`
- `./script/clippy -p gpui -p gpui_macos -p auto_update -p zed`
- `./script/clippy -p auto_update_helper --target
x86_64-pc-windows-msvc`

The regression tests cover simultaneous restart executable and argument
forwarding, Windows paths containing spaces and trailing backslashes,
updater-helper argument parsing, and the final `Zed.exe` command.

Compilation and unit tests were run on macOS. Linux and Windows runtime
behavior was reviewed but not run locally. A full `gpui_windows`
cross-target check was attempted, but its `psm` dependency requires the
MSVC `lib.exe` tool, which is not available on this macOS host; the
standalone Windows updater helper and its tests compile successfully for
the Windows target.

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

---

Release Notes:

- Fixed Zed forgetting an explicitly passed `--user-data-dir` argument
after restarting (e.g. clicking "Restart to Update")

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
2026-08-19 14:32:19 +00:00
Jakub Konka
c43e2d9734
gpui_linux: Handle XKB context initialization failure (#62868)
Release Notes:

- Added check for XKB context initialization failure
2026-08-19 11:19:10 +00:00
feeiyu
655ed1385b
Prevent inactive windows from updating the IME position on linux/Wayland (#62086)
# Objective
Fixes #62084

Fix the Wayland IME candidate window flickering between two positions
when an inactive Zed window has a terminal producing continuous output.

Terminal wakeup events in the inactive window can trigger IME position
updates, causing its cursor bounds to alternate with those from the
active window.


90d024b88a/crates/terminal_view/src/terminal_view.rs (L1130-L1136)


90d024b88a/crates/gpui/src/window.rs (L5617-L5627)

## Solution

Ignore IME position updates from inactive Wayland windows.

This ensures that only the active window can update the cursor rectangle
of the shared Wayland text-input object.

## Testing

To test manually on Linux with Wayland and Fcitx5:

1. Open two Zed windows.
2. Start continuous terminal output in the first window.
3. Use the Chinese IME in an editor in the second window.
4. Verify that the IME candidate window remains at a stable position.


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

## Showcase

after fix:


[2026-08-02
22-43-35.webm](https://github.com/user-attachments/assets/ff2e3bc7-7772-481e-82f8-92e6e3fa7275)



---

Release Notes:

- Fixed the IME candidate window flickering when another Zed window has
continuous terminal output
2026-08-05 07:30:17 +00:00
Erik W
c7aea6cbbd
gpui_linux: Add wl_data_source support for outbound drags on Wayland (#61947)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
# Objective

- Enable drag'n'drop from Zed in Wayland.
- Partially addresses #13186
- Related to #58161, #61940

## Solution

- Implement wl_data_source support for outbound drags on Wayland

## Testing

Tested on KDE Wayland, kwin 6.7.3
I dragged files to Firefox, to other Zed windows and into Dolphin.  

## Self-Review Checklist:

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

## Showcase

Can try to record if requested

Release Notes:

- Added support for dragging files from the Project Panel to external
Linux Wayland apps.
2026-07-31 10:29:47 +00:00
mTvare
ae99a867d7
x11: Request repaint after exposure instead of within blocked loop (#61162)
# Objective

Closes #61054

This PR fixes Zed window not repainting after they are uncovered on X11.
When an X11 window becomes visible after being covered, X11 sends an
`Expose` event to tell the application that the window contents need to
be presented again. Previously, Zed stored this event and waited for the
periodic refresh loop to request a presentation but, the refresh loop is
stopped while a window is fully hidden to avoid unnecessary rendering.
This meant there might be no refresh tick to handle the pending
exposure.

window is fully hidden -> periodic refresh loop stops

window is uncovered -> expose event -> waits for refresh loop -> window
may remain blank

This change requests one presentation directly after processing the
pending X11 events. Multiple `Expose` events for the same window are
coalesced, and unmapped windows are ignored.

## Solution

window is uncovered -> expose event -> presentation is requested ->
window contents are displayed

Required presentations are also excluded from inactive-window frame
throttling, so the request is not dropped when Zed is unfocused. Regular
rendering for unfocused or fully obscured windows remains throttled.

## Testing
Check the issue being closed on steps to reproduction.

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

- Fixed Zed windows sometimes not repainting after being uncovered on
X11
2026-07-30 16:52:19 +00:00
Jakub Konka
dc2a339d5d
gpui_linux: Fix Wayland serial token tracking (#61454)
Closes #58651 
Closes FR-123

https://github.com/zed-industries/zed/pull/50406/ while fixing one issue
regressed serial tracking in Wayland. What happens is we conflated
unrelated serials into a common value which is wrong. For example,
`InputMethod` serial does not come from the same source as `MousePress`
or `KeyPress`, and if Zed is running for a while and the user performs
lots of IME commits (`zwp_text_input_v3.commit`), `InputMethod` will
overtake other serial values and will be incorrectly used for clipboard
authorisation/selection by the compositor such as Mutter or kWin. This
will effectively poison the clipboard making Zed the indefinite owner
until we kill Zed. More concretely, we use `get_latest()` on the serial
tracker to extract *the largest serial REGARDLESS of kind* which is
wrong since not every serial kind comes from the same pool.

Release Notes:

- Fixed copy-paste behaviour in Wayland.
2026-07-22 12:46:55 +00:00
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
Lukas Wirth
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
ᴀᴍᴛᴏᴀᴇʀ
5079b33d65
gpui_linux: Fix unbounded memory growth when composing text with Fcitx5 under KWin/Wayland (#61079)
# Objective

Close #61034.

Fix unbounded memory growth when composing text with Fcitx5 under
KWin/Wayland.

While a non-empty preedit is cached, KWin resends it whenever it
receives a text-input-v3 `commit()` ([relevant KWin
code](0e473e87a6/src/wayland/textinput_v3.cpp (L444-L504))).

Zed handles the replayed preedit as a buffer edit. This invalidates the
IME character coordinates, causing Zed to submit the same cursor
rectangle and call `commit()` on the next frame. That commit makes KWin
replay the cached preedit again, forming an infinite feedback loop.

The observed memory growth is caused by retained CRDT state accumulating
indefinitely.

## Solution

Following [SDL's solution to the same
problem](81479d8784),
cache the last submitted cursor rectangle and compare it with the new
rectangle before calling `set_cursor_rectangle()`.

If the rectangles are equal, skip both the rectangle update and its
associated `commit()`. The initial cursor rectangle and actual rectangle
changes during an active composition are still submitted, preserving the
candidate-window positioning behavior introduced by #59911.

## Testing

Manually tested on KDE Plasma with `fcitx5-chinese-addons`. 

Before the fix, memory usage grew continuously while preedit text was
present, with `WAYLAND_DEBUG=client` showing text-input events repeating
indefinitely.

After the fix, the repeated events stopped and memory usage remained
stable.

No automated test was added because reproducing the feedback loop
requires compositor-specific KWin text-input-v3 behavior.

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

- Fixed excessive memory usage when composing text with Fcitx5 on KDE
Wayland.

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
2026-07-17 13:10:42 +00:00
Philipp Schaffrath
166f044fd0
gpui: Linux wayland set exclusive zone and edge (#60163)
# Objective

The exclusive zone and exclusive edge of a wlr-layer-shell surface could
only be set once, at creation, through `LayerShellOptions`. This adds
runtime setters so a live layer-shell window such as a panel can update
them without being recreated.

## Solution

Add two methods on `Window`:

- `set_exclusive_zone` updates how much screen space the surface
reserves. A positive value reserves that distance from the anchored
edge, 0 lets the surface be moved out of others' exclusive zones, and -1
ignores reserved space and may extend under other surfaces.
- `set_exclusive_edge` chooses which anchored edge the exclusive zone
applies to, which is needed to disambiguate a corner-anchored surface.

Setting an exclusive edge the surface is not anchored to is a fatal
protocol error, so the edge is validated (it must be a single edge that
the surface anchor contains) and an invalid edge is logged and ignored.
The same validation now also guards the creation path. Both setters only
commit the surface when a change actually applies, and are no-ops on
non-layer-shell windows and on other platforms.

This is where these 2 are documented:

https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:request:set_exclusive_zone

https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:request:set_exclusive_edge

## Testing

- Verified with a small local layer-shell window (a top bar anchored
TOP, LEFT, RIGHT) with buttons that call the setters at runtime
- No automated test was added, since this calls through to the
compositor.
- Reviewers without a layer-shell capable compositor (for example
GNOME/Mutter) cannot exercise this, as `zwlr_layer_shell_v1` is
unavailable there, I tested this on the
[Smithay](https://github.com/Smithay/smithay/) based compositor
[niri](https://github.com/niri-wm/niri)

## 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-15 08:18:46 +00:00
xhe
afc13dc8e0
gpui_linux: split xkbcommon wayland/x11 features (#60834)
# Objective

When xkbcommon compiled with either wayland or x11 only, the current
manifests will prevent it from compiling, despite gpui is already
wayland/x11 seperated.

close #60943 

## Solution

Simple changes to manifests.

## Testing

```
 cargo tree -p gpui_platform --no-default-features --features {wayland,x11} -e features -i xkbcommon
```

## Self-Review Checklist:

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

Release Notes:

- N/A

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-14 12:47:50 +00:00
Lukas Wirth
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
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
dd68454633
Update wayland-backend to fix Wayland file dialog crash (#60621)
On Wayland, closing a window in the brief gap between requesting a
portal file dialog and ashpd exporting the window's surface (used to
parent the dialog) crashed Zed with `Unknown opcode 0 for object
<anonymous>@0`
([ZED-9KB](https://zed-dev.sentry.io/issues/7568720776/)). When the
export request fails because the surface is already dead,
wayland-scanner's generated code silently returns an inert proxy, and
ashpd's `Drop` impl later sends `destroy` on it — which wayland-backend
0.3.11 answers with a panic, because it looks up the request opcode
before checking whether the object is null. wayland-backend 0.3.15 fixes
this
([Smithay/wayland-rs#890](https://github.com/Smithay/wayland-rs/issues/890))
by returning an error instead, which the generated destructor discards,
so the drop becomes a harmless no-op. This bumps the lockfile to 0.3.15
and raises the version floor in `gpui_linux` so the fix can't silently
regress via a fresh lockfile.

Closes FR-100

Release Notes:

- Fixed a crash on Linux (Wayland) when a window was closed just as a
file dialog was being opened.
2026-07-08 20:37:57 +00:00
Philipp Schaffrath
664b7ecb40
gpui: Fix hover state not clearing when mouse leaves window (#60275)
# Objective

Fix two gaps in element hover tracking at window boundaries. Hover was
only re-evaluated on `MouseMove`, so when the pointer left the window no
event fired `on_hover(false)` and the element stayed hovered.
Symmetrically on Wayland, no `Motion` follows `Enter` until the pointer
moves again, so hover was not established at the entry pixel. Both cases
are easy to miss since most hover-styled elements don't sit flush
against the window edge, but they surfaced while implementing
layer_shell popups with input_regions, which should close when stop
hovering.

## Solution

The hover compare-and-fire logic in `div` is refactored into a shared
`update_hover` closure, and a second listener on `MouseExitEvent` clears
hover when the pointer leaves the window. It clears unconditionally
because `MouseExited` doesn't update the tracked mouse position, so a
hit test during that dispatch would still report the element as hovered.

On Wayland, a `MouseMove` is synthesized at the entry position on
`wl_pointer.enter`, mirroring the `MouseExited` already dispatched on
`Leave`.

## Testing

Tested manually on Wayland/Linux: hover on a window-edge element clears
when the pointer leaves the window, and hover is established immediately
when the pointer enters a surface with an element under the entry pixel.

Not tested on other platforms. The `div` change relies on each
platform's existing `MouseExited` dispatch: macOS and X11 emit it, so
they get the exit fix too. Windows never dispatches `MouseExited`
(`WM_MOUSELEAVE` only flips the window-level hover flag), so the
stuck-hover case might remain there, unchanged from before.

Before:


https://github.com/user-attachments/assets/6af83bb3-de9d-40e2-a64c-bdefc98fc96d

After:


https://github.com/user-attachments/assets/721a9b5c-108a-499f-867e-da111836a34a


Here is an example application to test this:

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

use gpui::{
    App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size,
};
use gpui_platform::application;

struct HoverExit {
    hovered: bool,
}

impl Render for HoverExit {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        // Fills the whole window so its edge is the window edge: moving the mouse
        // out of the window is what exercises the MouseExited path.
        div()
            .id("hover-exit")
            .size_full()
            .flex()
            .justify_center()
            .items_center()
            .text_xl()
            .text_color(rgb(0xffffff))
            .bg(if self.hovered {
                rgb(0x585f58)
            } else {
                rgb(0x505050)
            })
            .child(if self.hovered { "HOVERED" } else { "not hovered" })
            .on_hover(cx.listener(|this, hovered, _, cx| {
                this.hovered = *hovered;
                cx.notify();
            }))
    }
}

fn run_example() {
    application().run(|cx: &mut App| {
        let bounds = Bounds::centered(None, size(px(240.), px(160.0)), cx);
        cx.open_window(
            WindowOptions {
                window_bounds: Some(WindowBounds::Windowed(bounds)),
                app_id: Some("gpui-hover-exit".to_string()),
                ..Default::default()
            },
            |_, cx| cx.new(|_| HoverExit { hovered: false }),
        )
        .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();
}
```


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

- Fixed element hover state not clearing when the mouse leaves the
window
2026-07-08 20:27:47 +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
迷渡
961f4f2024
gpui: Refresh mouse position after bounds changes (#60421)
## Summary

- Refresh GPUI's cached mouse position when window bounds change so
hover hit-testing uses the current cursor position after live resize.
- Return X11 mouse positions in window-relative logical pixels to keep
`PlatformWindow::mouse_position()` consistent with other backends.

Fixes #57354

## Testing

- `cargo fmt -p gpui -p gpui_linux`
- `cargo check -p gpui_linux`
- `cargo check -p gpui`

## Suggested .rules additions

- In GPUI platform backends, `PlatformWindow::mouse_position()` should
return window-relative logical pixels; use separate APIs or fields for
global/device-pixel coordinates.

Release Notes:

- Fixed incorrect hover state while resizing GPUI windows.
2026-07-07 10:59:45 +00:00
Philipp Schaffrath
a29c0d41f4
gpui: Add input region support for Wayland windows (#60161)
# Objective

Wayland windows have no way to restrict which parts of the surface
accept pointer and touch input. This adds support for setting an input
region, so events outside it pass through to whatever is below the
window. This is useful for shaped or partially click-through windows.


Clicks in green area can pass through the window, clicks in red area do
not:
<img width="1057" height="395" alt="image"
src="https://github.com/user-attachments/assets/2039af62-e43b-4834-b877-edad2a8f5ccf"
/>

## Solution

Add `Window::set_input_region`, which takes `Option<&[Bounds<Pixels>]>`:

- `Some(rects)` restricts pointer and touch input to the union of the
rectangles, in window coordinates.
- `Some(&[])` is an empty region, so the window receives no input at all
and is fully click-through.
- `None` resets the region to the default, so the whole window receives
input again.

On Wayland this maps to `wl_surface.set_input_region`, building a
`wl_region` from the rectangles or clearing it for `None`, and commits
so the change applies immediately rather than waiting for the next
frame. The method is a no-op on other platforms.


## Testing

Tested on Linux with Wayland.

- Tested in my own GPUI application, which uses a fullscreen layer for
overlays while allowing clicks outside of the rendered elements to be
passed through to the underlying windows.
- No automated test was added, since this calls through to the
compositor and is checked by observing input routing.


## 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-07 08:54:07 +00:00
Gavin Luo
c56646ffdf
terminal: Fix IME candidate window not following cursor in TUI apps (#59911)
# Objective

Fix IME candidate window not following cursor position in the integrated
terminal when running fullscreen TUI applications like opencode.

When using IME (Input Method Editor) in Zed's terminal with fullscreen
TUI applications (e.g., opencode), the candidate window does not follow
the cursor position. This issue does not occur in normal terminal usage
(e.g., bash shell).

# Solution

The root cause was three-layer blocking preventing IME position updates
in ALT_SCREEN mode:

1. **ALT_SCREEN blocking**: `selected_text_range()` returned `None` in
ALT_SCREEN mode, causing `selected_bounds()` to return `None`
2. **Missing trigger**: `Event::Wakeup` did not call
`invalidate_character_coordinates()`, so cursor movement did not trigger
IME position updates
3. **Composition blocking**: `update_ime_position()` skipped updates
when `state.composing` was true

Fixes:
- Remove ALT_SCREEN check in `selected_text_range()` so IME position
updates work in fullscreen TUI apps
- Add `window.invalidate_character_coordinates()` in `Event::Wakeup` to
trigger IME position updates when terminal cursor moves
- Remove `state.composing` check in `update_ime_position()` to allow IME
position updates during text-input-v3 composition
- Remove unused `terminal` field from `TerminalInputHandler` struct

# Testing

**Did you test these changes? If so, how?**
- Yes, tested on Linux GNOME Wayland with iBus input method
- Verified IME candidate window correctly follows cursor in opencode
- Verified normal terminal usage with IME still works correctly

**Are there any parts that need more testing?**
- Other IMEs (fcitx, etc.) may need testing

**How can other people (reviewers) test your changes?**
1. Open Zed's integrated terminal
2. Run a fullscreen TUI application like `opencode`
3. Activate IME (e.g., iBus with Chinese input)
4. Type text and observe the IME candidate window follows the cursor

**What platforms did you test these changes on?**
- Linux (GNOME Wayland) - tested
- macOS - not tested (may have different IME behavior)
- Windows - not tested (different code path)

# Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards (UX/UI and icon
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

# Showcase

<details>
  <summary>Before</summary>
<video
src="https://github.com/user-attachments/assets/ee2fac4e-801b-49af-a57e-32ce25e01db5"
width="320" height="180" />
</details>

<details>
  <summary>After</summary>
<video
src="https://github.com/user-attachments/assets/c669ea99-2ffc-4179-b587-a47873e33e70"
width="320" height="180" />
</details>

---

Release Notes:

- Fixed IME candidate window not following cursor in terminal TUI apps
2026-07-03 20:25:16 +00:00
Jakub Konka
f4364d870e
gpui_linux: Add support for open_window in headless client (#60359)
This actually makes it possible for Linux headless client to have
working windows for computation (well, we are in headless mode after
all). This also matches macOS headless client behaviour.

Release Notes:

- N/A
2026-07-03 15:20:09 +00:00
Anthony Eid
7c3160b7bf
gpui_linux: Consume Wayland startup activation token (#59995)
When opening Zed from GNOME on Wayland, the cursor can stay stuck in the
launch spinner state for several seconds because GPUI never tells the
compositor that the launched app's first window has loaded. Desktop
launchers pass this information through `XDG_ACTIVATION_TOKEN`, which
Wayland clients are expected to consume once their first toplevel
surface is ready.

This PR fixes that by reading and removing `XDG_ACTIVATION_TOKEN` during
Wayland client startup, storing it on the client state, and consuming it
on the first XDG toplevel surface via the existing
`xdg_activation_v1.activate(token, surface)` plumbing. Anthony manually
verified this on GNOME Wayland.


docs ref: https://wayland.app/protocols/xdg-activation-v1

Release Notes:

- Fixed Linux Wayland cursor being stuck as a spinner for a couple of
seconds.
2026-06-29 15:16:26 +00:00
Marshall Bowers
441de84a77
gpui_linux: Suppress dead code warning on wake_sender (#60090)
This PR adds a conditional `allow(dead_code)` to the `wake_sender` field
to fix this error when building Collab:

```
error: field `wake_sender` is never read
   --> crates/gpui_linux/src/linux/platform.rs:126:5
    |
116 | pub(crate) struct LinuxCommon {
    |                   ----------- field in this struct
...
126 |     wake_sender: Sender<()>,
    |     ^^^^^^^^^^^
    |
    = note: `-D dead-code` implied by `-D warnings`
    = help: to override `-D warnings` add `#[expect(dead_code)]` or `#[allow(dead_code)]`

error: could not compile `gpui_linux` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
```


https://github.com/zed-industries/zed/actions/runs/28374439219/job/84060893437

Release Notes:

- N/A
2026-06-29 13:31:03 +00:00
mTvare
35eaeb94a7
gpui: Fix xdg_toplevel app_id set to None at first commit on Wayland (#55583)
This PR fixes the default behaviour of setting `app_id` to `None` which
breaks the rules based management by KWin as the first commit doesn't
have the actual `app_id` and apply initially setting stops checking for
the window by when it updates.

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

Release Notes:

- Fixed KWin not respecting Zed's rules due to mismatch of toplevel
app_id at startup
2026-06-25 20:10:31 +00:00
Zax71
dae3e574e4
gpui_linux: Improve error message when X11 and Wayland feature flags are missing (#58685)
Improves `gpui_linux` error messages for missing feature flags.
Currently, you'd need to look at the source & Rust backtrace to diagnose
the error shown when the feature flags are missing.

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:

- Improve `gpui_linux` error messages for missing feature flags

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
2026-06-25 16:28:21 +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
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
Smit Barmase
bda5ac3626
linux: Fix Wayland clipboard reads blocking indefinitely (#58826)
Closes FR-44

Unlike X11, where Zed already times out clipboard reads, on Wayland we
had no timeout at all. We read the clipboard from a pipe the source app
writes into, and we were doing a blocking `read_to_end` on it. So if the
other app opened the pipe but never wrote anything, or stalled partway
through, the read would block forever and hang Zed.

This PR replaces it with a non-blocking read driven by `poll` with a 4s
timeout, so:

- a stalled writer fails cleanly instead of freezing us.
- a slow writer that's still making progress on a large payload keeps
working.

This roughly mirrors what the X11 path already does. I have tested
pasting text, large image, drag-n-drop, etc cases.

To Reproduce:

1. Copy text from a web page in Firefox.
2. `kill -STOP "$(pgrep -o firefox)"`
3. Paste into Zed.

Zed hangs indefinitely.

<img width="400"
src="https://github.com/user-attachments/assets/532d1c55-1500-4143-8227-127e0024efba"
/>


Release Notes:

- Fixed a freeze on Linux Wayland when reading the clipboard from a slow
or unresponsive application.
2026-06-08 12:23:04 +00:00
feeiyu
137e677a05
Fix Wayland IME handling with multiple windows (#58712)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
Self-Review Checklist:

- [X] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] 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
- [ ] Performance impact has been considered and is acceptable

Fix an issue introduced by PR #58237 where IME could not be enabled when
multiple windows were open.
The fix ensures that `update_ime_enabled` only updates IME state for the
active window.

Release Notes:

- N/A
2026-06-06 09:16:05 +00:00
feeiyu
126c0ee41a
Disable the IME on linux/wayland when text input is unexpected (#58237)
Self-Review Checklist:

- [X] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] 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
- [ ] Performance impact has been considered and is acceptable

This PR follows the approach from #51041 and currently includes only the
Wayland implementation.

[录屏 2026-06-01
23-11-17.webm](https://github.com/user-attachments/assets/c9f87503-4d64-4868-b9d8-5b832ade3e5a)



Release Notes:

- On Linux wayland, the IME is disabled in Vim normal and visual modes.
2026-06-05 15:39:59 +00:00
Wanten
737f55a1a1
gpui: Anchor IME candidate window to the start of the visual line (#55876)
## Summary

This PR fixes horizontal jumping of the IME candidate window during text
composition.

On the shared `selected_bounds` path used by Windows, the candidate
window no longer follows the preedit caret character-by-character.
Instead, it anchors to the start of the current visual line, which keeps
the candidate window stable while typing.

Linux Wayland uses a different IME positioning path, so it was not
affected by the original implementation in this PR. This PR now also
includes a Wayland-specific adjustment so that Wayland uses the same
visual-line anchoring behavior.

## Changes

1. **Shared / Windows path**
Updated `selected_bounds` in `crates/gpui/src/platform.rs` to use a
visual-line-aware anchor for preedit text.

This removes the distracting horizontal movement of the candidate window
while typing and keeps the anchor aligned with the active visual line.

2. **Linux Wayland path**
Updated the Wayland IME area calculation in
`crates/gpui_linux/src/linux/wayland/window.rs` to use the same
visual-line-start anchoring strategy for preedit text.

This brings Linux Wayland in line with the Windows behavior while
preserving Wayland's platform-specific IME handling.

## Notes

I had previously tried a separate Wayland-specific fix in
5d0c96872b, but later reverted it in
8cfe7a2a54 because the behavior was not
good enough and it regressed the original positioning behavior.

The current Wayland implementation is a new, simpler approach that keeps
the original behavior intact while also removing horizontal
candidate-window jumping.

## Visuals

### Windows / shared path

* **Before the fix:** (The candidate box moves along with the preedit
text, which is distracting)
    
<img width="918" height="675" alt="before"
src="https://github.com/user-attachments/assets/29cb05e4-3e99-4b54-9ce3-78710b307ce6"
/>

<img width="478" height="682" alt="before_1"
src="https://github.com/user-attachments/assets/cff38b65-96dd-4ed7-b06b-7fbcd448fab9"
/>

* **After the fix:** (Candidate box stays fixed at the line start during
typing, correctly jumps to new lines or follows active segments)

<img width="918" height="675" alt="after"
src="https://github.com/user-attachments/assets/4f50a710-dc0d-4959-a313-1184122ab759"
/>

<img width="478" height="683" alt="after_1"
src="https://github.com/user-attachments/assets/8e9df121-ffcc-45ad-ba0b-f1ad3cef87bc"
/>

### Linux Wayland

*  **Before / previous behavior**

<img width="552" height="796" alt="before"
src="https://github.com/user-attachments/assets/e3e84312-c626-41cb-945f-66c13aa96df6"
/>


*  **After / current implementation**

<img width="546" height="772" alt="after"
src="https://github.com/user-attachments/assets/a01ab6d7-a3b6-4d56-a1cb-b2b112b6b914"
/>


---

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

Release Notes:

- N/A
2026-06-03 08:36:05 +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
Cameron Mcloughlin
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
Higor Prado
980a294292
gpui: Prefer Mailbox present mode on Wayland to avoid FIFO stalls (#57077)
The WgpuRenderer defaults to VK_PRESENT_MODE_FIFO_KHR (vsync), which
blocks vkQueuePresentKHR until the compositor releases a buffer via
wl_surface.frame. On some Wayland compositor+driver combinations
(notably NVIDIA proprietary + Hyprland, but also observed on KDE/GNOME +
AMD RADV), these frame callbacks can be delayed or lost, stalling the
entire calloop event loop for tens of seconds.

VK_PRESENT_MODE_MAILBOX_KHR does not block on vblank: it replaces the
pending frame in a single-entry queue. This avoids the stall entirely.
The renderer already falls back to Fifo automatically if Mailbox is
unsupported by the driver.

The WgpuSurfaceConfig has had a preferred_present_mode field since
#50815 (added for Android lifecycle transitions with the same
rationale). This commit sets it to Mailbox in the Wayland window
creation path only. X11 is not affected.

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

Note on tests: This change is in the Wayland platform's window creation
path (WaylandWindowState::new). The surface configuration is delegated
to WgpuRenderer which already has test coverage for
preferred_present_mode fallback logic. A full integration test would
require a running Wayland compositor in CI. Verified manually and tested
against the renderer's unwrap_or(Fifo) safety net by inspecting
surface_caps.present_modes on both NVIDIA proprietary and Mesa RADV
drivers.

Closes: #50229
Closes: #55345
Closes: #39097
Closes: #50734

Refs: #38497, #52009, #52403, #50574, #49961, #47750, #46203, #50195,
#50283, #42164, #39156, #39234, #35948, #32618

Release Notes:

- Fixed UI freezes on Linux (Wayland) when on certain GPU/driver
combinations

---------

Co-authored-by: Neel <neel@zed.dev>
2026-05-18 23:57:51 +00:00
Locke Bircher
61e23fdb51
Fix text copy via mouse click on Wayland (#50406)
I've been working on a GPUI application which has a button for copying
text. After starting the app in Wayland in Linux I noticed that when I
click the button to copy text it does not work. After interacting with
other buttons and/or copying text via keyboard shortcuts then my copy
button works.

I thought I was handling something wrong, but then I noticed that Zed
also exhibits this behavior: upon starting Zed if you highlight text and
right-click and select "Copy" then nothing happens. After you interact
with other UI elements and/or keyboard shortcuts then copy buttons seem
to work fine.

This paper cut has been annoying me and with the help of Claude Code I
arrived at this small fix. This solves the problem and this appears to
be the way the serial should be handled for clipboard actions via button
clicks in Wayland, as far as I've been able to learn. Here are a couple
related Wayland documentation pages that I double checked:

1.
https://wayland.app/protocols/wayland#wl_data_device:request:set_selection
2.
https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-data-sharing-devices

- [x] Added ~a solid test coverage and/or~ screenshots from doing manual
testing

    - Here's a screen recording of the behavior without this fix:

[wayland-clipboard-problem.webm](https://github.com/user-attachments/assets/6c7d3b3b-56fe-4083-a011-4906ee9bfbec)

    - Here's a screen recording of the behavior with this fix:

[wayland-clipboard-fix.webm](https://github.com/user-attachments/assets/167ee731-118a-4f67-8489-6cfaca4389ce)

    - Here's a screen recording of the problem in Zed itself:

[wayland-clipboard-problem-zed.webm](https://github.com/user-attachments/assets/e41a40e1-54aa-4b3f-a2c6-f3e90d06d50f)


- [x] Done a self-review taking into account security and performance
aspects
    - None that I could find or think of

- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
    - I don't believe this is applicable...

Release Notes:

- Improved first mouse-driven text copy action on Wayland
2026-05-15 14:29:14 +00:00
Lukas Wirth
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
b5l
923f315f26
gpui_linux: Fix Wayland flickering under CPU load by skipping redundant surface commit (#54214)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
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

Closes #32792 
Closes #38266 
Closes #54133

Release Notes:

- Fixed graphical corruption that could occur when using Wayland

----

**What**: Fixes flickering on Wayland (Sway/wlroots) under CPU load
(e.g. rust-analyzer running). The bug only reproduces in release builds
- debug builds are too slow to hit the race window.

Environment where this was reproduced: Intel GPU (both Xe KMD and i915),
Mesa 26.0.4, Sway 1.11.

**Why**: When wgpu presents a frame on Wayland+Vulkan, it calls
`vkQueuePresentKHR,` which - as required by the Vulkan spec -
synchronously issues `wl_surface.attach`, `wl_surface.damage`, and
`wl_surface.commit` to the compositor before returning. The commit also
picks up any pending frame callbacks.

Zed's `completed_frame()` independently calls `state.surface.commit()`.
This is a redundant second commit on the same surface. Under load, the
Wayland socket dispatch can be delayed enough that both commits are in
flight in close succession, and the ordering becomes timing-dependent.
When Zed's commit reaches the compositor before Mesa's attach+commit
sequence has been fully flushed, the compositor sees a commit with no
buffer attached, fires `wl_callback::Done` immediately, and Zed starts
the next frame too early - Mesa's real buffer arrives late, causing the
visible flicker.

Under no load, Mesa's synchronous commit consistently reaches the
compositor first, so the bug doesn't appear.

**Fix**: Track whether `renderer.draw()` actually called
`frame.present()`. When it did, Mesa owns the `wl_surface.commit()` for
that frame - skip Zed's commit in `completed_frame()`. Only commit
ourselves when wgpu didn't present (surface not configured, lost,
occluded, etc.) - in those cases Mesa won't commit, and we need to keep
the frame callback alive.

---------

Co-authored-by: Benjamin Laib <b5l@users.noreply.github.com>
Co-authored-by: John Tur <john-tur@outlook.com>
2026-05-06 03:40:02 +00:00
Conrad Irwin
008d54299b
Try to reduce linux wGPU crashes better (#55343)
Updates #54349

There were two problems:
* The crash never happened, instead we'd always retry.
* When re-trying it seemed like we were picking llvmpipe. Claude's
suggestion was that immediately after wake, the real GPU isn't yet
awake, and so we pick llvm. Avoid this by disallowing llvmpipe on retry

Release Notes:

- linux: Reduced crash rate when recovering GPUs
2026-05-05 02:24:23 +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
Moulberry
4d668fa368
Fix showing unsupported window controls on Linux Wayland (#50609)
Release Notes:

- Fixed showing unsupported window controls on Linux Wayland

Before:
<img width="207" height="84" alt="image"
src="https://github.com/user-attachments/assets/174d3488-7c40-4b36-a1b5-76b85e19b796"
/>

After:
<img width="185" height="90" alt="image"
src="https://github.com/user-attachments/assets/82f10cbb-a834-4db9-a8e7-9e5156b3397e"
/>

Co-authored-by: Ben Kunkle <ben@zed.dev>
2026-04-24 10:10:12 +00:00
Finn Evers
9b40411c6a
Fix bad GitHub merge queue merge (#54721)
No, sadly, the title is not a typo. See
https://www.githubstatus.com/incidents/zsg1lk7w13cf for the context.
I'll read with joy and popcorn through that root cause analysis.

It makes literally zero sense what happened here, but for some completly
bonkers reason GitHub completely messed up the merge queue with
https://github.com/zed-industries/zed/pull/54632.

I have no idea how it happened. It makes literally zero sense. A PR
going into the merge queue should have the same LoC when getting out of
it. GitHub obviously does not check this. GitHub causes extra work with
a feature that is supposed to save time.

Thanks, I guess.

Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-04-23 23:47:30 +00:00
Danilo Leal
0ab64d6414
branch_picker: Add button to filter remote branches (#54632)
This PR brings back the button to filter remote branches when accessing
the title bar's branch picker with the mouse. It was unintentionally
removed when we introduced the new worktree picker.

Release Notes:

- N/A
2026-04-23 18:26:44 +00:00
Kirill Bulatov
5f68479937
Stop showing backtraces in default logging (#54660)
When using `.log_err()` or `.detach_and_log_err(cx)` or similar.

See also https://github.com/zed-industries/zed/pull/36404,
https://github.com/zed-industries/zed/pull/46383,
https://github.com/zed-industries/zed/pull/44896,
https://github.com/zed-industries/zed/pull/43917 and many more.

Before, a
62bd61a679/crates/languages/src/go.rs (L568)
line would show a backtrace even for `.context("no cached binary")?;`
case, same as many other usages around the code:

<img width="2032" height="1162" alt="before"
src="https://github.com/user-attachments/assets/ef2188b3-74c9-4c86-82b8-9fdaed3c26ae"
/>

After:

<img width="1896" height="157" alt="after"
src="https://github.com/user-attachments/assets/a1067d9f-61f4-4833-aeab-9f1042d2514a"
/>



To show a backtrace as before, use `log_err_with_backtrace`.

Release Notes:

- Improved Zed's log output on errors
2026-04-23 14:14:11 +00:00
Kirill Bulatov
c92833611e
Handle more already supported image formats across the codebase (#54326) 2026-04-22 20:02:27 +03:00
Conrad Irwin
5102ac14ba
Try to recover even harder from linux GPU errors (#54349)
Release Notes:

- N/A
2026-04-21 09:55:14 +02:00
Vinícius Dutra
4d78f26c27
Add support for Netpbm image previews (#54256)
This PR adds support for rendering **Netpbm** image formats (`.pbm`,
`.ppm`, `.pgm`) within Zed's built-in image viewer.

These formats are particularly useful for projects that want minimal
external dependencies, a common scenario in academic environments and
low-level graphics programming.

Since the underlying `image` crate and `GPUI` already provide support
for these codecs, this change explicitly exposes the `Pnm` variant
within `gpui::ImageFormat` by mapping it to `image::ImageFormat::Pnm`.

## Screenshots/Examples

Below is an example of `.pbm`, `.ppm`, and `.pgm` files being rendered
correctly in the image preview (images taken from
https://filesamples.com):
<img width="1917" height="1012" alt="pnm_example"
src="https://github.com/user-attachments/assets/0056133f-908c-4c91-ba9d-53aef0657b05"
/>



Release Notes:
  - Added support for PNM image previews (`.pbm`, `.ppm`, `.pgm`).
2026-04-20 16:51:13 +03:00
Smit Barmase
6a3111de79
gpui_linux: Fix X11 keyboard state synchronization (#53903)
Closes #49329

This area has regressed a few times across #34514, #35361, and #44234.
The problem is that we were still mixing XKB client-side and server-side
state handling on the same `xkb::State`.

On X11, `XkbStateNotify` already keeps the client state synchronized.
But the key event path was still doing two extra things on the shared
`state.xkb`:
  - calling `update_key()`
  - rewriting the same state from `KeyPress` / `KeyRelease.state`

The libxkbcommon X11 docs say that `XkbStateNotify` is the more accurate
source of truth for X11 clients and that there is no need to call
`xkb_state_update_key()` once the client state is synchronized. This
follows the libxkbcommon X11 client model more closely by keeping
persistent state notify-driven and using event-local state only for
lookup.

This PR fixes that by:
- removing the remaining `update_key()` calls from X11 `KeyPress` /
`KeyRelease`
- keeping the long-lived `state.xkb` driven only by `XkbStateNotify` and
keymap notifications
  - creating a temporary event-local `xkb::State` for per-event lookup

I also added regression tests around the historical bugs in this area:
  - #14282: Caps Lock / Neo 2 regressions from the earlier X11 fixes
  - #31193: German key resolution
- #26468: `space` with Cyrillic and Czech layouts / non-locked layout
groups
  - #40678: macro-style shifted input like `Shift+]`

Release Notes:

- Fixed issue on Linux X11 where you coundn't input space key in some
cases.
2026-04-16 10:46:47 +03:00
kitt
24a304c140
Set window icon on X11 (#40096)
Closes #30644

Many X11 environments expect a window icon to be supplied [as pixel data
on a window property
`_NET_WM_ICON`](https://specifications.freedesktop.org/wm-spec/1.4/ar01s05.html#id-1.6.13).

I confirmed this change fixes the icon in xfce4 for me, I think its
likely it also fixes https://github.com/zed-industries/zed/issues/37961
but I haven't tested it.

## Questions
* [`image::RgbaImage` is exposed to the public API of
gpui](https://github.com/zed-industries/zed/pull/40096/files#diff-318f166d72ad9476bd0a116446f5db3897fc1a4eb1d49aaf8105608bcf49ea53R1136).
I would guess this is undesirable, but I wasn't sure of the best way to
use gpui's native `Image` type..
* Currently [the icon is embedded into the
binary](https://github.com/zed-industries/zed/pull/40096/files#diff-89af0b4072205c53b518aa977d6be48997e1a51fa4dbf06c7ddd1fec99fc510eR101).
If this is undesirable, zed could alternatively implement [icon
lookup](https://specifications.freedesktop.org/icon-theme-spec/latest/#icon_lookup)
and try and find its icon from the system at runtime.

## Future work
* It might be nice to expose a `set_window_icon` method also (it could
be used for example to show dirty state in the icon somehow), but I'm
unfamiliar with what other platforms support and if this could be beyond
X11 (there is a [wayland
protocol](https://wayland.app/protocols/xdg-toplevel-icon-v1) though!).

Release Notes:

- Fixed missing window icon on X11

---------

Co-authored-by: Yara <git@yara.blue>
2026-04-14 16:21:28 +02:00
CanWang
23830d5946
Fix crash on startup when the X11 server supports XInput < 2.4 (#53582)
## Summary

- Fix crash on startup when the X11 server supports XInput < 2.4 (e.g.
XInput 2.3)
- Gesture event mask bits (pinch begin/update/end) are now only
requested when the server advertises XInput >= 2.4
- Zed previously failed to open any window on affected systems, printing
`Zed failed to open a window: X11 XiSelectEvents failed`

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









## Problem

On X11 systems where the XInput extension version is older than 2.4, Zed
crashes immediately on startup with:

```
Zed failed to open a window: X11 XiSelectEvents failed.

Caused by:
    X11 error X11Error { error_kind: Value, error_code: 2, sequence: 277,
    bad_value: 27, minor_opcode: 46, major_opcode: 131,
    extension_name: Some("XInputExtension"),
    request_name: Some("XISelectEvents") }
```

This makes Zed completely unusable on any X11 display server that only
supports XInput 2.3 or earlier, which includes many current Ubuntu
20.04/22.04 systems, remote X11 sessions, and VNC/Xvfb setups.

### Root cause

During window creation, `X11WindowState::new` calls `XISelectEvents`
with an event mask that unconditionally includes gesture event bits
(`GESTURE_PINCH_BEGIN`, `GESTURE_PINCH_UPDATE`, `GESTURE_PINCH_END`).
These gesture events were introduced in **XInput 2.4**.

When the X server only supports XInput 2.3 (or older), it does not
recognize these mask bits and rejects the entire `XISelectEvents`
request with a `BadValue` error. This is fatal because the error is
propagated up and prevents the window from being created.

A comment in the original code stated:

> If the server only supports an older version, gesture events simply
won't be delivered.

This is incorrect. The X11 protocol does **not** silently ignore unknown
mask bits in `XISelectEvents` — it rejects the whole request.

### How XInput version negotiation works

The client calls `XIQueryVersion(2, 4)` to announce the highest version
it supports. The server responds with the highest version **it**
supports (e.g. `2.3`). The client is then responsible for not using
features beyond the negotiated version. The existing code ignored the
server's response and used 2.4 features unconditionally.

## Fix

### Approach

Check the XInput version returned by the server. Only include gesture
event mask bits in `XISelectEvents` when the negotiated version is >=
2.4. On older servers, basic input events (motion, button press/release,
enter, leave) still work normally — only touchpad pinch gestures are
unavailable.

### Changed files

**`crates/gpui_linux/src/linux/x11/client.rs`**

1. Added `supports_xinput_gestures: bool` field to `X11ClientState`.
2. After the existing `xinput_xi_query_version(2, 4)` call, compute
whether the server version is >= 2.4:
   ```rust
   let supports_xinput_gestures = xinput_version.major_version > 2
|| (xinput_version.major_version == 2 && xinput_version.minor_version >=
4);
   ```
3. Added an `info!` log line reporting the detected XInput version and
gesture support status.
4. Pass `supports_xinput_gestures` through `open_window` into
`X11Window::new`.

**`crates/gpui_linux/src/linux/x11/window.rs`**

1. Added `supports_xinput_gestures: bool` parameter to both
`X11Window::new` and `X11WindowState::new`.
2. The `XISelectEvents` call now builds the event mask conditionally:
- Always includes: `MOTION`, `BUTTON_PRESS`, `BUTTON_RELEASE`, `ENTER`,
`LEAVE`
- Only when `supports_xinput_gestures` is true: `GESTURE_PINCH_BEGIN`,
`GESTURE_PINCH_UPDATE`, `GESTURE_PINCH_END`

### What is NOT changed

- The gesture event **handlers** in `client.rs`
(`XinputGesturePinchBegin`, `XinputGesturePinchUpdate`,
`XinputGesturePinchEnd`) are left as-is. They simply won't be triggered
on servers without gesture support, since the events are never
registered.
- No behavioral change on systems with XInput >= 2.4 — gesture events
continue to work exactly as before.

## Testing

| Test | Before fix | After fix |
|------|-----------|-----------|
| `./target/release/zed .` on XInput 2.3 | Immediate crash (exit code 1)
| Window opens successfully (runs until killed) |
| XInput version detection | Version queried but response ignored |
Version checked and logged |

Verified on an X11 system with XInput 2.3 (X.Org 1.20.13, Ubuntu 20.04).

## Test plan

- [x] Build succeeds (`cargo build --release`)
- [x] Zed launches and opens a window on XInput 2.3 system
- [x] No regression on the basic input event path (motion, clicks,
enter/leave still registered)
- [ ] Verify gesture pinch events still work on a system with XInput >=
2.4

Release Notes:

- Fixed Zed failing to start on X11 systems with XInput version older
than 2.4, which includes many Linux distributions and remote desktop
setups.
2026-04-10 08:05:39 +00:00