diff --git a/Cargo.lock b/Cargo.lock index f665eb0928..921a61631b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,7 +852,7 @@ dependencies = [ "bitflags 2.13.1", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools 0.11.0", "log", "prettyplease", "proc-macro2", @@ -1466,7 +1466,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "gpui_util", "indexmap", @@ -2113,7 +2113,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "proc-macro2", "quote", @@ -2481,7 +2481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3276,7 +3276,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "accesskit", "anyhow", @@ -3362,7 +3362,7 @@ dependencies = [ [[package]] name = "gpui-base" version = "0.5.2" -source = "git+https://github.com/zeronsh/gpui-component?rev=5086ff4fb162ae97ca9d806876e7c6694ac3a81f#5086ff4fb162ae97ca9d806876e7c6694ac3a81f" +source = "git+https://github.com/zeronsh/gpui-component?rev=103f13da91ff2c7c52941bdc2b1910f29716dc19#103f13da91ff2c7c52941bdc2b1910f29716dc19" dependencies = [ "aho-corasick", "anyhow", @@ -3392,7 +3392,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "accesskit", "accesskit_unix", @@ -3444,7 +3444,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "accesskit", "accesskit_macos", @@ -3493,7 +3493,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3504,7 +3504,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "console_error_panic_hook", "gpui", @@ -3517,7 +3517,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "schemars", "serde", @@ -3527,7 +3527,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "gpui", @@ -3538,7 +3538,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "log", @@ -3548,7 +3548,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3572,7 +3572,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "bytemuck", @@ -3601,7 +3601,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "accesskit", "accesskit_windows", @@ -3933,7 +3933,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "async-compression", @@ -4352,7 +4352,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5061,7 +5061,7 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "anyhow", "bindgen", @@ -5541,7 +5541,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.119", @@ -6204,7 +6204,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "collections", "serde", @@ -6932,7 +6932,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6945,7 +6945,7 @@ dependencies = [ "libc", "log", "socket2", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7275,7 +7275,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "derive_refineable", ] @@ -7839,7 +7839,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -7852,7 +7852,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7961,7 +7961,7 @@ checksum = "c62751faa8bc286982334a082fe125184a29fc89d17775766e4f891b7d726980" [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "async-task", "backtrace", @@ -8720,7 +8720,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "heapless 0.9.3", "log", @@ -9005,7 +9005,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -10005,7 +10005,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=1561532176f54262e360acbb8bc00c6fcf183975#1561532176f54262e360acbb8bc00c6fcf183975" +source = "git+https://github.com/zeronsh/zui?rev=18a89af04cfe079d55275b111ac349d5640d9cda#18a89af04cfe079d55275b111ac349d5640d9cda" dependencies = [ "perf", "quote", @@ -10713,7 +10713,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f2467b435f..e7ccb09e77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,15 +68,15 @@ loro-protocol = "0.3" # Linux — the Metal path's snapshot/blur/composite, ported). # Paint-time rounded image masks (#9), bounded Windows backdrop blur and # translucent compositing, plus blur-aware scene batching (#10). -gpui = { git = "https://github.com/zeronsh/zui", rev = "1561532176f54262e360acbb8bc00c6fcf183975" } -gpui_platform = { git = "https://github.com/zeronsh/zui", rev = "1561532176f54262e360acbb8bc00c6fcf183975", features = [ +gpui = { git = "https://github.com/zeronsh/zui", rev = "18a89af04cfe079d55275b111ac349d5640d9cda" } +gpui_platform = { git = "https://github.com/zeronsh/zui", rev = "18a89af04cfe079d55275b111ac349d5640d9cda", features = [ "wayland", "x11", "font-kit", "runtime_shaders", ] } -gpui_tokio = { git = "https://github.com/zeronsh/zui", rev = "1561532176f54262e360acbb8bc00c6fcf183975" } -gpui-base = { git = "https://github.com/zeronsh/gpui-component", rev = "5086ff4fb162ae97ca9d806876e7c6694ac3a81f" } +gpui_tokio = { git = "https://github.com/zeronsh/zui", rev = "18a89af04cfe079d55275b111ac349d5640d9cda" } +gpui-base = { git = "https://github.com/zeronsh/gpui-component", rev = "103f13da91ff2c7c52941bdc2b1910f29716dc19" } # diffs similar = "2" diff --git a/crates/ui/src/files/search.rs b/crates/ui/src/files/search.rs index 8d83d25565..c17905d723 100644 --- a/crates/ui/src/files/search.rs +++ b/crates/ui/src/files/search.rs @@ -634,11 +634,9 @@ impl FilesSurface { this.search_state.active = index; this.activate_search_result(cx); })) - .when(crate::click_activation_drag_enabled(), |element| { - element.on_drag(drag_payload, |payload, _, _, cx| { - cx.stop_propagation(); - workspace_path_drag_ghost(payload, cx) - }) + .on_drag(drag_payload, |payload, _, _, cx| { + cx.stop_propagation(); + workspace_path_drag_ghost(payload, cx) }) .child( div() diff --git a/crates/ui/src/files/tree.rs b/crates/ui/src/files/tree.rs index 7cffa193eb..0f219e0f83 100644 --- a/crates/ui/src/files/tree.rs +++ b/crates/ui/src/files/tree.rs @@ -272,11 +272,9 @@ impl FilesSurface { this.tree_focus.focus(window, cx); this.activate_tree_path(path.clone(), cx); })) - .when(crate::click_activation_drag_enabled(), |element| { - element.on_drag(drag_payload, |payload, _, _, cx| { - cx.stop_propagation(); - workspace_path_drag_ghost(payload, cx) - }) + .on_drag(drag_payload, |payload, _, _, cx| { + cx.stop_propagation(); + workspace_path_drag_ghost(payload, cx) }) .child( div() diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 69d097341a..8e12850086 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -69,16 +69,6 @@ use gpui::{App, AppContext as _, Bounds, TitlebarOptions, WindowBounds, WindowOp pub use state::EngineBootConfig; pub use zeron_proto::HarnessId; -/// Whether a control whose primary action is click activation may also start -/// a GPUI drag from the same hitbox. GPUI promotes pointer travel above 2 px -/// to a drag. Normal Windows click jitter can cross that threshold, cancel the -/// click, and leave the drag ghost following the pointer instead of activating -/// the control. Drag-first controls (resize handles, scrollbars, queue rows) -/// intentionally do not use this policy. -pub(crate) const fn click_activation_drag_enabled() -> bool { - !cfg!(target_os = "windows") -} - /// Everything the headed binary passes in (config/env resolution lives in /// `apps/zeron`, not here). #[derive(Debug, Clone)] diff --git a/crates/ui/src/shell.rs b/crates/ui/src/shell.rs index 7cb73267ab..78c37a06f6 100644 --- a/crates/ui/src/shell.rs +++ b/crates/ui/src/shell.rs @@ -9847,21 +9847,43 @@ impl Shell { this.close_right_surface(surface, window, cx); }), ) - .when(crate::click_activation_drag_enabled(), |el| { - el.on_drag( - RightTabDrag { - panel_key: self.panel_key(cx), - from: ix, - title: ghost_title, - workspace_path, - }, - |payload, _point, _, cx| { - let title = payload.title.clone(); - cx.stop_propagation(); - cx.new(|_| SurfaceTabGhost { title }) - }, - ) - }) + .on_drag( + RightTabDrag { + panel_key: self.panel_key(cx), + from: ix, + title: ghost_title, + workspace_path, + }, + |payload, _point, _, cx| { + let title = payload.title.clone(); + cx.stop_propagation(); + cx.new(|_| SurfaceTabGhost { title }) + }, + ) + // The chip's BlockMouse hitbox (the titlebar/scroll carve-out + // below) cuts the strip out of the hover stack, so the + // strip's own on_drop can never fire while the pointer is + // over a chip — tabs tile the strip. Receiving the drop on + // the chip itself keeps drag-reorder working without giving + // up the carve-out. The bubble dispatch reaches the chip + // before the strip, and the handler consumes the drag, so + // the two never double-apply. + .on_drop::(cx.listener( + move |this, payload: &RightTabDrag, _, cx| { + if payload.panel_key != this.panel_key(cx) { + this.right_tab_drag = None; + cx.notify(); + return; + } + let to = this + .right_tab_drag + .as_ref() + .map(|d| d.over) + .unwrap_or(payload.from); + this.right_tab_drag = None; + this.reorder_right_tabs(payload.from, to, cx); + }, + )) .child( // Leading slot: icon normally, ✕ on tab hover — two // stacked layers opacity-swapped by the group hover. @@ -13973,11 +13995,7 @@ mod right_tab_mouse_regressions { gpui::Modifiers::default(), ); cx.update(|_, cx| { - assert_eq!( - cx.has_active_drag(), - crate::click_activation_drag_enabled(), - "tab drag policy does not match the current platform" - ) + assert!(cx.has_active_drag(), "tab drag did not start") }); cx.simulate_mouse_up(start, MouseButton::Left, gpui::Modifiers::default()); cx.simulate_mouse_down(start, MouseButton::Middle, gpui::Modifiers::default()); @@ -13993,7 +14011,10 @@ mod right_tab_mouse_regressions { fn subagent_tab_click_jitter_selects_without_starting_a_drag(cx: &mut TestAppContext) { let (shell, cx) = setup(cx); let start = cx.debug_bounds("right-surface-tab-0").unwrap().center(); - let end = start + gpui::point(px(8.), px(0.)); + // Sub-threshold pointer jitter (the Windows drag rectangle is 4px, + // matching the system SM_CXDRAG default): a jittery click must stay + // a click — no drag ghost, tab still activates on release. + let end = start + gpui::point(px(3.), px(0.)); cx.simulate_mouse_down(start, MouseButton::Left, gpui::Modifiers::default()); cx.simulate_mouse_move(end, Some(MouseButton::Left), gpui::Modifiers::default()); @@ -14009,6 +14030,40 @@ mod right_tab_mouse_regressions { assert_eq!(shell.resolved_right_active(cx), RightSurface::Subagent(1)); }); } + + /// The user-visible contract: dragging a surface tab onto another slot + /// reorders the strip. On Windows the chip's `on_drag` used to be gated + /// off entirely (`click_activation_drag_enabled`), so the drag could + /// never start; on every platform the drop could not land on a chip + /// (BlockMouse carve-out). This test is the regression lock for both. + #[gpui::test] + fn surface_tab_drag_reorders_the_strip(cx: &mut TestAppContext) { + let (shell, cx) = setup(cx); + let from = cx.debug_bounds("right-surface-tab-0").unwrap().center(); + let to = cx.debug_bounds("right-surface-tab-1").unwrap().center(); + + cx.simulate_mouse_down(from, MouseButton::Left, gpui::Modifiers::default()); + // First move crosses the threshold and promotes the press into a + // drag (bubble phase). The DragMoveEvent dispatch that computes the + // drop slot only fires on the NEXT move (capture phase, after the + // drag is already active) — a real pointer always produces both. + cx.simulate_mouse_move(to, Some(MouseButton::Left), gpui::Modifiers::default()); + cx.update(|_, cx| { + assert!(cx.has_active_drag(), "surface tab drag never started"); + }); + cx.simulate_mouse_move(to, Some(MouseButton::Left), gpui::Modifiers::default()); + cx.simulate_mouse_up(to, MouseButton::Left, gpui::Modifiers::default()); + + shell.read_with(cx, |shell, cx| { + let key = shell.panel_key(cx); + let tabs = shell.right_tabs.get(&key).expect("panel has surface tabs"); + assert_eq!( + tabs, + &vec![RightSurface::Subagent(2), RightSurface::Subagent(1)], + "tab drag did not reorder the strip" + ); + }); + } } #[cfg(test)] diff --git a/crates/ui/src/terminal/panel.rs b/crates/ui/src/terminal/panel.rs index 772b670bf3..bdfaa6e71a 100644 --- a/crates/ui/src/terminal/panel.rs +++ b/crates/ui/src/terminal/panel.rs @@ -1549,20 +1549,18 @@ impl TerminalPanel { this.close_tab(&chat_close, key, window, cx); }), ) - .when(crate::click_activation_drag_enabled(), |el| { - el.on_drag( - TabDragPayload { - chat: chat_drag, - from: ix, - title: ghost_title, - }, - |payload, _point, _, cx| { - let title = payload.title.clone(); - cx.stop_propagation(); - cx.new(|_| TabGhost { title }) - }, - ) - }) + .on_drag( + TabDragPayload { + chat: chat_drag, + from: ix, + title: ghost_title, + }, + |payload, _point, _, cx| { + let title = payload.title.clone(); + cx.stop_propagation(); + cx.new(|_| TabGhost { title }) + }, + ) .when(exited, |el| el.opacity(0.55)) .child( crate::icons::icon(crate::icons::TERMINAL)