2de1cf55a3df8aecb09ffd27bb1dcfb3a138a4c8
74
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
22a3412edf |
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. https://github.com/zed-industries/zed/blob/db73efafe4240e69f80eca2857758eaf8151a0b1/crates/terminal_view/src/terminal_view.rs#L1130-L1136 https://github.com/zed-industries/zed/blob/db73efafe4240e69f80eca2857758eaf8151a0b1/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 |
||
|
|
1ce15ce1fe |
gpui_linux: Add wl_data_source support for outbound drags on Wayland (#61947)
# 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. |
||
|
|
922d2dd05c |
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 |
||
|
|
d5a4de9392 |
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. |
||
|
|
cd91c84675 |
gpui: Add system notification platform APIs (#61189)
Release Notes: - N/A or Added/Fixed/Improved ... --------- Co-authored-by: John Tur <john-tur@outlook.com> |
||
|
|
6c4862e1f2 |
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](https://github.com/KDE/kwin/blob/0e473e87a64d5d404c2fecf5516a9a5c3cf17d91/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](https://github.com/libsdl-org/SDL/commit/81479d8784d0e1a61eafb3a444dd3865ad762fb2), 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> |
||
|
|
e963df8029 |
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 |
||
|
|
a932df5550 |
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> |
||
|
|
756116c2b0 |
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 |
||
|
|
01d5096a3f |
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 |
||
|
|
636e764737 |
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 |
||
|
|
3699843254 |
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. |
||
|
|
b992659378 |
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 |
||
|
|
885d599cc1 |
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 |
||
|
|
2fff6597d6 |
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 |
||
|
|
8f6e462a9b |
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. |
||
|
|
2ef7f39587 |
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
|
||
|
|
fea22b3934 |
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 |
||
|
|
5824dca06e |
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> |
||
|
|
e85a546880 |
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 |
||
|
|
8aca6b1eda |
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 |
||
|
|
53367edf64 |
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. |
||
|
|
b1f9188767 |
Fix Wayland IME handling with multiple windows (#58712)
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 |
||
|
|
a39afde4ac |
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. |
||
|
|
2991e00e5e |
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
|
||
|
|
a0d71a483a |
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 |
||
|
|
761fda75cd |
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> |
||
|
|
ec4517faf3 |
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> |
||
|
|
083d16624c |
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 |
||
|
|
156a47d0d0 |
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> |
||
|
|
2ae08181de |
gpui_linux: Fix Wayland flickering under CPU load by skipping redundant surface commit (#54214)
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> |
||
|
|
c6514d7397 |
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 |
||
|
|
ba6d258b0f |
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 |
||
|
|
f01d6816cb |
Support BGR subpixel layout (#55174)
Release Notes: - Added text rendering support for BGR subpixel layouts. |
||
|
|
ae7a265a20 |
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> |
||
|
|
c49ffd1e88 |
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> |
||
|
|
184e1d93e3 |
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 |
||
|
|
e9d727015b |
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 https://github.com/zed-industries/zed/blob/77c74db82e35b2e3aeebea9629b644cf43137f16/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 |
||
|
|
0c44029c32 | Handle more already supported image formats across the codebase (#54326) | ||
|
|
b4406f52c6 |
Try to recover even harder from linux GPU errors (#54349)
Release Notes: - N/A |
||
|
|
6d69bf731f |
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`). |
||
|
|
186465348e |
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. |
||
|
|
bb990ab9ac |
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> |
||
|
|
909ac66c0a |
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. |
||
|
|
acce768299 |
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 |
||
|
|
a56a3d084c |
gpui_wgpu: Add surface lifecycle methods for mobile platforms (#50815)
## Summary - Add `unconfigure_surface()` and `replace_surface()` methods to `WgpuRenderer` for mobile platform window lifecycle management - Prefer `PresentMode::Mailbox` (triple-buffering) over `Fifo` to avoid blocking during lifecycle transitions - Early return in `draw()` when surface is unconfigured to prevent driver hangs ## Motivation On Android, the native window (`ANativeWindow`) is destroyed when the app goes to the background and recreated when it returns to the foreground. The same happens during orientation changes. Without surface lifecycle methods, the only option is to destroy the entire `WgpuRenderer` and create a new one on resume. The problem: GPUI's scene cache holds `AtlasTextureId` references from the old renderer's atlas. A new renderer has an empty atlas, so those cached IDs cause index-out-of-bounds panics. The fix: Keep the renderer (device, queue, atlas, pipelines) alive across surface destruction. Only the wgpu `Surface` needs to be replaced. ### `unconfigure_surface()` Marks the surface as unconfigured so `draw()` skips rendering via the existing `surface_configured` guard. Drops intermediate textures that reference the old surface dimensions. The renderer stays fully alive. ### `replace_surface()` Creates a new `wgpu::Surface` from fresh window handles using the **same** `wgpu::Instance` that created the original adapter/device. Reconfigures the surface and marks it as configured so rendering resumes. All cached atlas textures remain valid. ### PresentMode::Mailbox `Fifo` (VSync) blocks in `get_current_texture()` and can deadlock if the compositor is frozen during a lifecycle transition (e.g. `TerminateWindow` → `InitWindow` on Android). Mailbox (triple-buffering) avoids this. Falls back to `AutoNoVsync` → `Fifo` if unsupported. ### draw() early return Some drivers (notably Adreno) block indefinitely when acquiring a texture from an unconfigured surface. The early return prevents this. ## Context This is needed by [gpui-mobile](https://github.com/itsbalamurali/gpui-mobile), a project bringing GPUI to Android and iOS. The Android implementation needs these methods to handle: 1. **Background/foreground transitions** — `TerminateWindow` destroys the native window, `InitWindow` recreates it 2. **Orientation changes** — Surface is destroyed and recreated with new dimensions 3. **Split-screen transitions** — Similar surface recreation Without this change, we maintain a local fork of `gpui_wgpu` with just these additions. Upstreaming them would let mobile platform implementations use the official crate directly. ## Test plan - [x] Tested on Android (Motorola, Adreno 720 GPU) — 3 consecutive background/foreground cycles, zero panics, atlas textures preserved - [x] Tested orientation changes (portrait→landscape→portrait) — surface replacement completed in <40ms per rotation - [x] Verified `draw()` correctly skips rendering when surface is unconfigured - [x] Verified no regression on desktop — methods are additive, existing code paths unchanged - [x] PresentMode fallback chain works on devices that don't support Mailbox ## Release Notes - N/A |
||
|
|
c072c41c66 |
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> |
||
|
|
0369904e23 |
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> |
||
|
|
c8f20c78e0 |
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 ... |
||
|
|
7b325a0734 |
Use the most recent serial of kinds KeyPress or MousePress when copying (#52053)
Release Notes: - Fix copy for some Wayland users |