From 35e6c842d22c680cae81214697fa4c18d81ae08c Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 22:02:18 +0800 Subject: [PATCH 01/14] feat(webview): render GPUI overlays above WebView Enable the layered GPUI scene on macOS, move root overlays into the deferred plane, expand the WebView example, and document the platform composition architecture. Co-authored-by: Codex --- Cargo.lock | 124 +++- Cargo.toml | 10 +- crates/ui/src/root.rs | 26 +- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 732 +++++++++++++++++++++ crates/webview/src/lib.rs | 7 +- examples/webview/src/main.rs | 90 ++- 6 files changed, 936 insertions(+), 53 deletions(-) create mode 100644 crates/webview/WEBVIEW_OVERLAY_RESEARCH.md diff --git a/Cargo.lock b/Cargo.lock index c821b99424..b88a9caa75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "proc-macro2", "quote", @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "accesskit", "anyhow", @@ -3148,7 +3148,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "accesskit", "accesskit_unix", @@ -3170,6 +3170,7 @@ dependencies = [ "itertools 0.14.0", "libc", "log", + "notify-rust", "oo7", "open", "parking_lot", @@ -3199,13 +3200,14 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "accesskit", "accesskit_macos", "anyhow", "async-task", "block", + "block2 0.6.2", "cbindgen", "cocoa 0.26.0", "collections", @@ -3233,6 +3235,7 @@ dependencies = [ "objc2 0.6.4", "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", + "objc2-user-notifications", "parking_lot", "pathfinder_geometry", "raw-window-handle", @@ -3246,7 +3249,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3257,7 +3260,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "console_error_panic_hook", "gpui", @@ -3270,7 +3273,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "schemars", "serde", @@ -3280,7 +3283,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "log", @@ -3290,7 +3293,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3302,7 +3305,6 @@ dependencies = [ "log", "parking_lot", "raw-window-handle", - "smallvec", "uuid", "wasm-bindgen", "wasm-bindgen-futures", @@ -3314,7 +3316,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "bytemuck", @@ -3332,6 +3334,7 @@ dependencies = [ "raw-window-handle", "smallvec", "swash", + "unicode-bidi", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -3343,7 +3346,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "accesskit", "accesskit_windows", @@ -3659,7 +3662,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "async-compression", @@ -3679,7 +3682,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "rustls", "rustls-platform-verifier", @@ -4574,6 +4577,20 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mac-notification-sys" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca" +dependencies = [ + "cc", + "log", + "objc2 0.6.4", + "objc2-foundation 0.3.2", + "time", + "uuid", +] + [[package]] name = "mach" version = "0.3.2" @@ -4700,7 +4717,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "bindgen", @@ -4950,6 +4967,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "notify-rust" +version = "4.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b4c1b4f2aa9f25f63a7a49d3dd0ed567b3670da15330a66b29434be899b891" +dependencies = [ + "futures-lite", + "log", + "mac-notification-sys", + "serde", + "tauri-winrt-notification", + "zbus", +] + [[package]] name = "notify-types" version = "1.0.1" @@ -5111,7 +5142,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5281,6 +5312,16 @@ dependencies = [ "objc2-foundation 0.3.2", ] +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-core-text" version = "0.3.2" @@ -5429,6 +5470,19 @@ dependencies = [ "objc2-foundation 0.3.2", ] +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "bitflags 2.11.1", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-core-location", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-web-kit" version = "0.3.2" @@ -5669,7 +5723,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "collections", "serde", @@ -6667,7 +6721,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "derive_refineable", ] @@ -6719,7 +6773,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "bytes", @@ -7156,7 +7210,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "async-task", "backtrace", @@ -7777,7 +7831,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "heapless", "log", @@ -8042,9 +8096,9 @@ dependencies = [ [[package]] name = "taffy" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73afc801dd6bd47529eaa7c7e90557f107527d1b7c9c7ed7d7803c7b8d0c357f" +checksum = "340a09581f29809fc0df82a3955501dc7f2a21f887e5d1c13dbe288fe1c0bef4" dependencies = [ "arrayvec", "grid", @@ -8087,6 +8141,17 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "tauri-winrt-notification" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed071c670382e85fc2f48ae706492d8c338f4f89bf72520d32f8abfe880aade" +dependencies = [ + "thiserror 2.0.18", + "windows 0.61.3", + "windows-version", +] + [[package]] name = "tempfile" version = "3.27.0" @@ -9247,7 +9312,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "perf", "quote", @@ -9510,8 +9575,7 @@ dependencies = [ [[package]] name = "wasm_thread" version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7516db7f32decdadb1c3b8deb1b7d78b9df7606c5cc2f6241737c2ab3a0258e" +source = "git+https://github.com/zed-industries/wasm_thread?rev=0cf96c7708dfb97ccf3da50347e25edcf75d6937#0cf96c7708dfb97ccf3da50347e25edcf75d6937" dependencies = [ "futures", "js-sys", @@ -11247,7 +11311,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "anyhow", "chrono", @@ -11264,7 +11328,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" dependencies = [ "tracing", "tracing-subscriber", @@ -11275,7 +11339,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#1a246efd7e1b83ab568ec5e3e6c1a43a42e1abba" +source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index 8eadcc8798..a075f28970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,11 +33,11 @@ gpui-component-macros = { path = "crates/macros", version = "0.5.1" } gpui-component-assets = { path = "crates/assets", version = "0.5.1" } story = { path = "crates/story" } -gpui = { git = "https://github.com/zed-industries/zed" } -gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit", "x11", "wayland", "runtime_shaders"] } -gpui_web = { git = "https://github.com/zed-industries/zed" } -gpui_macros = { git = "https://github.com/zed-industries/zed" } -reqwest_client = { git = "https://github.com/zed-industries/zed" } +gpui = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } +gpui_platform = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda", features = ["font-kit", "x11", "wayland", "runtime_shaders"] } +gpui_web = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } +gpui_macros = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } +reqwest_client = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } sum-tree = { version = "0.2.0", package = "zed-sum-tree" } # reqwest = { version = "0.12.15-zed", package = "zed-reqwest" } reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662463bda39148ba154100dd44d3fba5873a4", default-features = false, features = [ diff --git a/crates/ui/src/root.rs b/crates/ui/src/root.rs index 7d531b8838..0d1d1a2dbc 100644 --- a/crates/ui/src/root.rs +++ b/crates/ui/src/root.rs @@ -14,7 +14,7 @@ use gpui::{ Anchor, AnyView, App, AppContext, Bounds, ClipboardItem, Context, DefiniteLength, ElementId, Entity, EntityId, FocusHandle, Hitbox, InteractiveElement, IntoElement, KeyBinding, ParentElement as _, Pixels, Render, StyleRefinement, Styled, WeakEntity, WeakFocusHandle, - Window, actions, div, prelude::FluentBuilder as _, + Window, actions, deferred, div, prelude::FluentBuilder as _, }; use std::{any::TypeId, collections::HashMap, rc::Rc}; @@ -159,6 +159,15 @@ impl Root { cx: &mut App, ) -> Option> { let root = window.root::()??; + if root + .read(cx) + .notification + .read(cx) + .notifications() + .is_empty() + { + return None; + } let active_sheet_placement = root.read(cx).active_sheet.clone().map(|d| d.placement); @@ -173,7 +182,7 @@ impl Root { let placement = cx.theme().notification.placement; - Some( + Some(deferred( div() .absolute() .when(matches!(placement, Anchor::TopRight), |this| { @@ -199,7 +208,7 @@ impl Root { .when_some(mb, |this, offset| this.mb(offset)) .when_some(ml, |this, offset| this.ml(offset)) .child(root.read(cx).notification.clone()), - ) + )) } /// Render the Sheet layer. @@ -217,12 +226,9 @@ impl Root { let size = sheet.size; - return Some( - div() - .relative() - .child(sheet) - .on_prepaint(move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size))), - ); + return Some(deferred(div().relative().child(sheet).on_prepaint( + move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size)), + ))); } None @@ -273,7 +279,7 @@ impl Root { } } - Some(div().children(dialogs)) + Some(deferred(div().children(dialogs))) } pub fn open_dialog(&mut self, build: F, window: &mut Window, cx: &mut Context<'_, Root>) diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md new file mode 100644 index 0000000000..70752c0676 --- /dev/null +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -0,0 +1,732 @@ +# Rendering GPUI Elements Above Native WebViews: Platform Composition Research + +> Research date: 2026-07-30 +> Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit +> `896e7f138b385f745b3f58aba1cb66c647fa1dda`. This document records the +> native composition research, the implemented macOS layered-scene spike, and +> the remaining Windows and Linux architecture. + +## Conclusion + +Adding a `z-index` to an existing wry WebView cannot solve this problem across +platforms. GPUI elements are composed into one GPU surface, while wry creates a +platform-native child view or window by default. Paint order inside GPUI cannot +cross the native window hierarchy. + +The recommended end state is a GPUI **native surface slot**: + +1. After prepaint, GPUI submits the native surface bounds, clip, visibility, + and stacking information every frame. +2. The platform backend inserts the WebView into that platform's compositable + visual or view tree. +3. GPUI continues to draw its overlays, but the platform backend guarantees + that their GPU visual is above the WebView visual. Input is routed to the + overlay or WebView according to GPUI hit testing. +4. Validate the design on macOS first. Windows must use WebView2 composition + hosting. Linux cannot promise an implementation with the same cost. + +GPUI already has a better natural split point than an arbitrary `z-index`. +`Window::draw_roots` paints the root, calls `paint_deferred_draws`, and finally +paints the window prompt, active drag, or core tooltip +([GPUI `Window::draw_roots`](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui/src/window.rs#L2839-L2923)). +The preferred model is therefore: + +```text +base scene paint + | +native portal (WebView visual) + | +deferred overlay scene + | +prompt / active drag / core tooltip scene +``` + +This follows the existing GPUI paint pipeline more closely than hard-coding +component names as overlays. + +| Platform | Default wry representation | Reordering siblings directly | Recommendation | +| --- | --- | --- | --- | +| macOS | `WKWebView` as an `NSView` subview | **Promising; validate first** | Put WKWebView and the GPUI Metal views in an explicit sibling view/layer hierarchy; validate transparent overlays, input, and resize | +| Windows | WebView2 controller hosted in a separate `WS_CHILD` HWND | **Unreliable; not a final design** | Fork or extend wry to use WebView2 Composition Controller and attach the WebView visual to GPUI's DirectComposition tree | +| Linux | X11 child window or GTK `WebKitWebView` widget | X11 child window: **no**; a unified GTK tree may work | Wayland requires the window and layout to join the GTK widget tree; otherwise only a limited snapshot/offscreen fallback is possible | + +## Why the Current Implementation Always Covers GPUI + +`WebViewElement::paint` does not draw the WebView; it only registers a hitbox. +wry's native object displays the page, while `prepaint` only calls +`set_bounds`. Later GPUI paint ordering for Popover, Dialog, or Notification +can only reorder pixels inside the same GPUI scene. It cannot reorder an +external `NSView`, child `HWND`, or GTK widget. + +wry defines `build_as_child` in native platform terms: a child window on +Windows, an `NSView` under the content view on macOS, and an X11-only child +window on Linux. Wayland requires a GTK container. These are explicit wry API +semantics, not a GPUI-specific effect +([official wry `WebViewBuilder::build_as_child` API](https://docs.rs/wry/0.53.3/wry/struct.WebViewBuilder.html#method.build_as_child), +[official wry child WebView example](https://github.com/tauri-apps/wry/tree/v0.53.3#child-webviews)). + +The pinned wry Windows source creates `WRY_WEBVIEW` with +`WS_CHILD | WS_CLIPCHILDREN`, calls `SetWindowPos(..., HWND_TOP, ...)`, and +then creates an ordinary `ICoreWebView2Controller`. It does not use a +composition controller +([wry 0.53.3 child HWND creation](https://github.com/tauri-apps/wry/blob/v0.53.3/src/webview2/mod.rs#L310-L376), +[wry 0.53.3 ordinary WebView2 controller creation](https://github.com/tauri-apps/wry/blob/v0.53.3/src/webview2/mod.rs#L545-L594)). +This directly explains why the WebView remains in front of the GPUI scene on +Windows. + +## What `Application::run_embedded` Solves + +Zed PR [#60574](https://github.com/zed-industries/zed/pull/60574) added +`Application::run_embedded` and `ApplicationHandle`. They invert ownership of +the event loop and GPUI application: when an external host owns the run loop +and `Platform::run` returns immediately after its launch callback, +`ApplicationHandle` keeps the application alive and lets the host re-enter +GPUI through `update()` and `to_async()`. The PR did not add an embeddable +`NSView`, `HWND`, `CAMetalLayer`, GPU texture, or scene-stacking API. + +Its first consumer, `embedded_gpui`, lets guest UI participate like ordinary +GPUI elements because the guest outputs a retained display list that the host +replays as **the host's own GPUI primitives**. It does not insert a guest +native window or surface into the GPUI scene +([`embedded_gpui` README](https://github.com/zed-industries/embedded_gpui#readme)). +WKWebView, WebView2, and WebKitGTK do not expose a browser display list that an +application can replay every frame, so this mechanism cannot be applied +directly to a wry WebView. + +It can still be reused indirectly: + +- If the macOS spike uses an external native shell that owns the run loop and + embeds a GPUI overlay renderer in a selected `NSView` or `CAMetalLayer`, + `run_embedded` can manage application lifetime. +- If GPUI later gains a truly embedded `PlatformWindow`, it can be the entry + point through which the host drives GPUI. +- It does not create the `base GPUI < WebView < overlay GPUI` layers or handle + scene separation, alpha, hit testing, focus, IME, or WebView input + forwarding. + +This problem still requires a native surface slot and overlay plane. +`run_embedded` is a reusable startup and lifetime building block, not the +composition solution. + +## macOS: One NSView / CALayer Tree + +### Primary-source facts + +- AppKit's `addSubview(_:positioned:relativeTo:)` inserts a view immediately + above or below a sibling. A `nil` relative view places it above or below all + siblings + ([Apple `NSView.addSubview` ordering API](https://developer.apple.com/documentation/appkit/nsview/addsubview%28_%3Apositioned%3Arelativeto%3A%29)). +- Apple's view hierarchy guide says that a view which must draw in front of + another should be a subview or descendant of the rear view, and that the + positioned API controls ordering + ([Apple, Working with the View Hierarchy](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaViewsGuide/WorkingWithAViewHierarchy/WorkingWithAViewHierarchy.html)). +- A layer-backed view caches drawing in its `CALayer`; enabling `wantsLayer` + on a parent makes the subtree layer-backed. Apple also warns against adding + ordinary subviews to a layer-hosting view, which must be managed entirely + through Core Animation + ([Apple `NSView.wantsLayer`](https://developer.apple.com/documentation/appkit/nsview/wantslayer)). +- wry 0.53.3 inserts `WKWebView` into its parent with `addSubview` and exposes + no relative sibling-order policy + ([wry WKWebView insertion source](https://github.com/tauri-apps/wry/blob/v0.53.3/src/wkwebview/mod.rs#L615-L674)). +- GPUI's macOS backend creates `GPUIView`, explicitly enables `wantsLayer`, + and adds it to `NSWindow.contentView` + ([GPUI macOS window source](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_macos/src/window.rs#L880-L984)). + Its renderer uses `CAMetalLayer` + ([GPUI Metal renderer source](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_macos/src/metal_renderer.rs#L151-L177)). + +### Viable design + +The smallest prototype is not a new transparent GPUI window. It explicitly +rebuilds sibling order below the same content view: + +```text +NSWindow.contentView ++-- GPUI container NSView + +-- GPUI base CAMetalLayer / view + +-- WKWebView NSView + +-- GPUI overlay CAMetalLayer / view (transparent) +``` + +GPUI currently has one complete scene and one `CAMetalLayer`. Putting that +entire view above WKWebView also puts the GPUI background above the page. +There are two options: + +1. **Two GPUI surfaces:** render base and overlay scenes separately, with the + WebView between them. +2. **Transparent hole punching:** keep one GPUI surface above the WebView, + clear base pixels inside WebView bounds to transparent, and retain only + overlay pixels in that region. + +The second option touches less code but must validate a non-opaque +`CAMetalLayer`, clear alpha, window background, and text antialiasing together. +The current renderer derives `CAMetalLayer.opaque` from the window's +`transparent` option, so an ordinary opaque window cannot be assumed to +support local transparency. The first option has clearer, more durable +boundaries, but requires routing the GPUI scene by stacking plane. + +### macOS prototype acceptance criteria + +- Popovers, dialogs, and notifications cross WebView bounds with correct + shadows and translucency. +- The WebView outside an overlay still receives mouse, scroll, keyboard, and + drag/drop input. +- GPUI hit testing intercepts input inside the overlay and immediately returns + it to the WebView after dismissal. +- Retina scale, live resize, fullscreen, multiple WebViews, WebView focus, and + IME all work. +- Native bounds and clip remain consistent with the GPUI content mask when the + WebView enters or leaves scrolling and clipping containers. + +## Windows: Join the DirectComposition Visual Tree + +### Why HWND z-order is insufficient + +An ordinary wry WebView is a child HWND. Moving it behind the GPUI HWND has two +structural problems: + +1. All GPUI pixels remain in one surface, which cannot represent + `GPUI base < WebView < GPUI overlay`. +2. A child HWND is a rectangular native window. HWND z-order cannot express + GPUI clipping, rounded corners, translucency, or per-element hit testing. + +`SetWindowPos(HWND_BOTTOM)`, temporarily hiding the WebView, or creating a +transparent top-level window for each popover are only workarounds. The last +also creates cross-window focus, IME, movement, DPI, taskbar, and accessibility +consistency problems. + +### Primary-source facts + +- Microsoft provides `CreateCoreWebView2CompositionControllerAsync` for visual + hosting. The host must set `RootVisualTarget` and forward mouse/pointer input + to WebView + ([Microsoft CreateCoreWebView2CompositionControllerAsync](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2environment.createcorewebview2compositioncontrollerasync)). +- `RootVisualTarget` may be an `IDCompositionVisual` or + `Windows::UI::Composition::ContainerVisual`. WebView attaches its visual + tree there; the application controls position, commit, and input + ([Microsoft `ICoreWebView2CompositionController`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2compositioncontroller)). +- Microsoft's API overview also states that a WebView2 composition tree can + attach to `IDCompositionVisual`, `IDCompositionTarget`, or `ContainerVisual` + ([Microsoft WebView2 API overview: Rendering using Composition](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/overview-features-apis#rendering-webview2-using-composition)). +- GPUI's Windows renderer already creates an `IDCompositionDevice`, + `IDCompositionTarget`, and root `IDCompositionVisual`, then sets the GPUI + swap chain as the visual content + ([GPUI `DirectComposition` source](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L898-L917)). +- GPUI's composition swap chain uses `DXGI_ALPHA_MODE_PREMULTIPLIED` + ([GPUI composition swap-chain source](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L1180-L1203)). + This provides the alpha mode needed for transparent visual composition, but + does not prove that the current scene produces correct hole or overlay + alpha. Rendering must still be split and tested. + +### Recommended visual tree + +```text +IDCompositionTarget (GPUI HWND) ++-- root + +-- GPUI base visual (swap chain) + +-- WebView slot visual + | +-- WebView2 composition tree + +-- GPUI overlay visual (transparent swap chain) +``` + +This requires changing wry or implementing a Windows-specific WebView2 host. +wry 0.53.3 does not expose a composition controller. Beyond pixels, the host +must implement `SendMouseInput` / `SendPointerInput`, cursor, drag/drop, focus, +IME, accessibility provider, and DPI coordinate conversion. Visual output +without input is not a complete implementation. + +### Windows implementation note + +#### `lb-wry 0.53.3` capability boundary + +Inspection of the pinned source gives a precise result: **it exposes an +ordinary controller to callers, but does not create, store, or expose a +Composition Controller**. + +- `WebViewBuilderExtWindows` offers additional browser arguments, data + directory, browser accelerator keys, theme, HTTPS scheme, environment, and + incognito options, but no composition-hosting option + ([wry 0.53.3 Windows builder extension](https://github.com/tauri-apps/wry/blob/v0.53.3/src/lib.rs#L1668-L1810)). +- `WebViewExtWindows::controller()` returns `ICoreWebView2Controller` + ([wry 0.53.3 Windows WebView extension](https://github.com/tauri-apps/wry/blob/v0.53.3/src/lib.rs#L2224-L2263)). + An already-created ordinary controller cannot be upgraded to a composition + controller. The environment must create one through + `CreateCoreWebView2CompositionController[WithOptions]`. +- The internal `WebView` stores `ICoreWebView2Controller`, but its construction + path only calls `CreateCoreWebView2Controller` or + `CreateCoreWebView2ControllerWithOptions` + ([wry 0.53.3 controller construction](https://github.com/tauri-apps/wry/blob/v0.53.3/src/webview2/mod.rs#L549-L643)). +- Its drag/drop helper registers `IDropTarget` around wry's child HWND. It is + not composition-controller drag forwarding + ([wry 0.53.3 drag/drop controller](https://github.com/tauri-apps/wry/blob/v0.53.3/src/webview2/drag_drop.rs#L39-L97)). + +It is therefore impossible to obtain `webview.controller()` outside +`gpui-wry` and add a `RootVisualTarget` afterward. The smallest correct change +must occur before wry constructs the controller. Maintain a narrow wry fork +rather than copying all initialization, protocol, navigation, IPC, and +lifecycle logic into `crates/webview`. + +#### Composition Controller host responsibilities + +Microsoft defines the following composition-hosting contract: + +- `RootVisualTarget` accepts `IDCompositionVisual`, `IDCompositionTarget`, or + `Windows::UI::Composition::ContainerVisual` + ([WebView2 composition overview](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/overview-features-apis#connecting-to-the-visual-tree)). + Since GPUI already uses DirectComposition, pass a slot + `IDCompositionVisual` created by **the same GPUI `IDCompositionDevice`**. + Do not create an independent target tree for the same HWND. +- After `put_RootVisualTarget` connects the WebView tree, the host must still + set the ordinary controller's `Bounds` and commit visual-tree changes on its + device + ([Microsoft `ICoreWebView2CompositionController`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2compositioncontroller)). +- Mouse, touch, and pen first reach the parent HWND. The host converts them to + WebView client coordinates and calls `SendMouseInput` or + `SendPointerInput`. WebView reports cursor changes through `CursorChanged`; + the host updates `WM_SETCURSOR` or the parent HWND. It must also send mouse + leave events or cursor state becomes incorrect + ([Microsoft composition input contract](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/overview-features-apis#forwarding-input), + [Microsoft cursor contract](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2compositioncontroller)). +- External drops do not enter WebView automatically. The host registers + `IDropTarget`, forwards `DragEnter`, `DragOver`, `DragLeave`, and `Drop` to + `ICoreWebView2CompositionController3`, and converts points to WebView client + coordinates + ([Microsoft `ICoreWebView2CompositionController3`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2compositioncontroller3)). +- WebView remains a child of the parent HWND in the accessibility tree by + default. Correct spatial and hierarchical integration with GPUI AccessKit + may use the `IRawElementProviderSimple` provider returned by + `ICoreWebView2CompositionController2::get_AutomationProvider` + ([Microsoft `ICoreWebView2CompositionController2`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2compositioncontroller2), + [WebView2 composition accessibility overview](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/overview-features-apis#accessibility)). +- Focus, visibility, bounds, and keyboard behavior use the ordinary + `ICoreWebView2Controller` that the composition controller also implements: + `MoveFocus`, Got/LostFocus, MoveFocusRequested, AcceleratorKeyPressed, and + related APIs. The host must call `NotifyParentWindowPositionChanged` when + the WebView parent or ancestor HWND moves; Microsoft says this is required + for accessibility and WebView dialogs + ([Microsoft `ICoreWebView2Controller`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller)). +- Microsoft does not require forwarding `WM_IME_*` through a + composition-specific API, because the interface has no IME forwarding + method. Keyboard and IME still depend on the controller's internal HWND and + focus. **GPUI must not continue consuming or rewriting these messages while + WebView has focus.** Runtime validation with CJK input methods is required; + successful COM compilation alone is not proof. + +The last two points mean the input boundary is not simply "when GPUI hit +testing misses, call SendMouseInput." Pointer input can be forwarded +explicitly, but keyboard and IME require real controller focus. When Tab +leaves the WebView, the host must handle `MoveFocusRequested` and restore GPUI +focus. + +#### Concrete changes to GPUI Windows DirectComposition + +`DirectComposition` currently contains: + +```text +IDCompositionTarget ++-- comp_visual(content = GPUI swap chain) +``` + +Its constructor creates one target and one visual, and `set_swap_chain` makes +that visual the root +([current GPUI DirectComposition wrapper](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L898-L917)). +It must become: + +```text +IDCompositionTarget ++-- root_visual + +-- base_visual(content = base GPUI swap chain) + +-- portal_container + | +-- webview_slot_visual(s) + +-- overlay_visual(content = transparent overlay GPUI swap chain) +``` + +Concrete change points: + +1. Add `root_visual`, `base_visual`, `portal_container`, and `overlay_visual` + to `DirectComposition`. Call `comp_target.SetRoot` only during construction + and device recovery; `set_swap_chain` must no longer replace the root. +2. Add an overlay swap chain, texture, and RTV to `DirectXResources`. The + existing composition swap chain already uses + `DXGI_ALPHA_MODE_PREMULTIPLIED`, which the overlay can reuse + ([GPUI composition swap chain](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L1180-L1203)). +3. Render the base scene and + `paint_deferred_draws + prompt/drag/tooltip` scene to separate RTVs. The + overlay clear must be `[0, 0, 0, 0]`, not `[1, 1, 1, 1]` as used by the + current opaque-window path + ([current GPUI `draw` clear selection](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L301-L355)). +4. In one frame, portal update sets slot visual offset, clip, visibility, and + order, then commits them with GPUI visual changes. `RootVisualTarget` + attaches the tree; WebView `Bounds` still controls raster size. +5. Device-loss recovery currently drops and rebuilds all DirectComposition + state and the swap chain + ([GPUI renderer recovery path](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui_windows/src/directx_renderer.rs#L232-L300)). + A portal handle must carry a generation. After recovery, the old slot visual + is invalid and the WebView host must rebind `RootVisualTarget`; it cannot + retain a raw COM pointer forever. +6. `GPUI_DISABLE_DIRECT_COMPOSITION` falls back to an HWND swap chain. This + mode has no visual slot and must report that capability as unavailable. It + must not silently fall back to the old child WebView while claiming overlay + support. + +`crates/webview` must not call `CreateTargetForHwnd` again for the GPUI HWND. +Microsoft permits at most one composition target per layer for an HWND, and +`topmost` decides whether the visual tree is above or below child windows +([Microsoft `CreateTargetForHwnd`](https://learn.microsoft.com/en-us/windows/desktop/api/dcomp/nf-dcomp-idcompositiondevice-createtargetforhwnd)). +GPUI already owns the topmost target; extend its root tree. + +#### Transparent child HWND overlay versus Composition Controller + +Keeping the wry child HWND and creating a transparent GPUI child or owned HWND +above it is suitable for a short spike, not a product architecture: + +| Dimension | Transparent overlay HWND | Composition Controller | +| --- | --- | --- | +| Visual order | Depends on two HWNDs' z-order; the GPUI scene still needs splitting or duplication | Natively expresses base / WebView / overlay visual order | +| Clip, corners, animation | HWND region, layered window, and GPUI clip need duplicate synchronization | Visual offset, clip, and opacity commit in one transaction | +| Input | An extra WndProc must decide hit testing and pass-through | Pointer forwarding is an official WebView2 contract; still complex, but bounded | +| Focus, IME, accessibility | Cross-HWND focus, IME, and UIA spatial relationships are fragile | The controller retains official focus and UIA APIs | +| Resize and DPI | Two native windows require tear-free synchronization | Visual tree and swap chains commit together | +| Multiple WebViews and nested overlays | HWND count and z-order state grow rapidly | A portal container manages multiple slot visuals | + +Windows 8 and later permit child `WS_EX_LAYERED` windows +([Microsoft extended window styles](https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles)), +but this proves only that the API can create one, not that it satisfies GPUI +per-element hit testing, focus, and atomic composition. +`WS_EX_TRANSPARENT` is not general input pass-through; Microsoft limits its +classic use to same-thread child hierarchies, while top-level use also requires +a layered style +([Microsoft DWM best practices](https://learn.microsoft.com/en-us/windows/win32/dwm/bestpractices-ovw)). + +**Decision: use Composition Controller for the final implementation.** +A transparent overlay HWND is allowed only for early visual validation or an +"open a separate popup window" fallback when DirectComposition is disabled. +It must not implement the claim that arbitrary GPUI elements can cover a +WebView in the same window. + +#### Minimum compilable API and module boundaries + +Keep WebView2 initialization in a narrow wry fork and visual-tree ownership in +GPUI: + +```rust +// gpui: cross-platform, no COM types +pub struct NativeSurfacePortal { /* opaque id + generation */ } + +impl Window { + pub fn create_native_surface_portal( + &mut self, + cx: &mut App, + ) -> Result; +} + +impl NativeSurfacePortal { + pub fn capabilities(&self) -> NativeSurfaceCapabilities; + pub fn set_geometry(&self, bounds: Bounds, clip: Bounds); + pub fn set_visible(&self, visible: bool); +} + +// gpui_windows: Windows-only extension trait exposing the COM attachment point +pub trait NativeSurfacePortalExtWindows { + fn parent_hwnd(&self) -> HWND; + fn root_visual_target(&self) -> IUnknown; + fn generation(&self) -> u64; +} + +// wry fork: Windows builder extension +pub trait WebViewBuilderExtWindowsComposition { + fn build_as_composition_child( + self, + parent: HWND, + root_visual_target: IUnknown, + ) -> Result; +} + +pub trait WebViewExtWindowsComposition { + fn composition_controller( + &self, + ) -> Option; +} +``` + +Responsibilities: + +- `gpui` / `gpui_windows`: visual creation and ordering, geometry and clip, + overlay swap chain, commit, and device-loss generation. +- wry fork: environment and controller creation, existing WebView handlers and + lifecycle, `RootVisualTarget` binding, and composition-controller exposure. +- `crates/webview/src/platform/windows.rs`: adapt GPUI mouse, pointer, focus, + and drag events to the composition controller; observe cursor and focus; and + rebind when the portal generation changes. +- `WebViewElement`: submit only declarative bounds, clip, visibility, and a + GPUI hitbox; never manipulate the DComp tree directly. + +`root_visual_target()` exposes a COM object rather than +`IDCompositionDevice`, preventing wry from modifying the full GPUI tree. The +portal handle guarantees the slot visual's lifetime. + +#### Phased Windows implementation checklist + +1. **Compilation gate:** add a composition construction path to the wry fork + while reusing all existing WebView initialization. Type checks prove the + ordinary path is unchanged and the composition path returns + `ICoreWebView2CompositionController`. +2. **Visual-only gate:** GPUI creates the `base / slot / overlay` tree. Use a + solid-color test visual instead of WebView to prove order, clip, resize, + DPI, and device recovery. +3. **WebView picture gate:** bind WebView `RootVisualTarget` to the slot. + Validate multiple WebViews, move/resize/visibility, scrolling clip, + transparent overlay, and absence of one-frame z-order flashes. +4. **Mouse/cursor gate:** cover move, down, up, double-click, wheel, + horizontal wheel, and leave; coordinate conversion, capture, and + CursorChanged. Do not forward when overlay hit testing succeeds. +5. **Touch/pen/drag gate:** implement `SendPointerInput` and + `ICoreWebView2CompositionController3` drag/drop. Validate internal WebView + dragging and drag-in from other applications. +6. **Focus/IME gate:** validate click-to-focus, Tab/Shift-Tab, + `MoveFocusRequested`, accelerators, CJK IME composition and candidate + windows, and WebView dialogs. Call `NotifyParentWindowPositionChanged` when + the window moves. +7. **Accessibility gate:** attach the WebView automation provider at the + correct GPUI/AccessKit parent and screen bounds; validate Narrator order. +8. **Recovery/capability gate:** recreate and rebind slots after GPU device + loss. Return explicit unsupported status when DComp is disabled and use a + separate WebView window or popup fallback. + +The first three stages prove only that WebView can display with an overlay. +Interactive, accessible, recoverable product support requires stages 4-8 too. + +## Linux: GTK/WebKitGTK and Native Child-Window Constraints + +### Primary-source facts + +- wry explicitly states that `build_as_child` supports only X11 on Linux. + Wayland should use `WebViewBuilderExtUnix::new_gtk` with `gtk::Fixed` + ([wry build_as_child platform notes](https://docs.rs/wry/0.53.3/wry/struct.WebViewBuilder.html#method.build_as_child)). +- `GtkFixed` positions child widgets in pixels and performs no automatic + layout + ([GTK 3 `GtkFixed`](https://docs.gtk.org/gtk3/class.Fixed.html)). +- `GtkOverlay` places overlay widgets above its main child, and an overlay + child's index determines draw order when children overlap + ([GTK 3 `GtkOverlay`](https://docs.gtk.org/gtk3/class.Overlay.html), + [GTK 3 `reorder_overlay`](https://docs.gtk.org/gtk3/method.Overlay.reorder_overlay.html)). +- Normal GTK 3 drawing propagates from the toplevel through the widget + hierarchy in back-to-front order. The documentation also recognizes that a + toplevel may contain multiple native subwindows. Only content in the same + GTK/GDK hierarchy is naturally governed by GTK overlay ordering + ([GTK 3 Drawing Model](https://docs.gtk.org/gtk3/drawing-model.html)). +- WebKitGTK's public snapshot API asynchronously captures a visible region or + full document and returns a static snapshot. It does not expose WebKit's + live GPU surface to GPUI + ([WebKitGTK `WebView.get_snapshot`](https://webkitgtk.org/reference/webkit2gtk/stable/method.WebView.get_snapshot.html)). +- GTK explicitly limits `OffscreenWindow` to snapshots of widgets outside a + normal widget hierarchy. It is itself a toplevel and cannot be embedded in + another toplevel + ([GTK 3 `OffscreenWindow` index entry](https://docs.gtk.org/gtk3/index.html#classes)). + +### Feasibility + +On X11, treating the WebKitGTK/X11 child window and GPUI surface as two +rectangular native windows and changing stacking still cannot express +arbitrary overlays inside GPUI. wry explicitly does not support this child +window route on Wayland. + +In theory, WebKitWebView can be the main child of `GtkOverlay`, with a GTK +widget capable of presenting the GPUI overlay surface above it. That requires +the GPUI Linux window backend itself to integrate with GTK/GDK surface +lifetime and coordinate renderer surfaces, event loops, input, and Wayland +subsurfaces. It is not a local `crates/webview` change. + +The snapshot route can draw a WebView image as a GPUI texture and obtain +arbitrary GPUI z-order. The official API is asynchronous, however, with no +evidence that it supports real-time scrolling, video, animation, or +low-latency input. It is only a preview or frozen-state fallback, not the final +interactive WebView implementation. + +## Recommended GPUI Core Abstraction + +Do not expose platform details as a vague `z_index(i32)`. Introduce a limited, +testable stacking plane: + +```rust +enum NativeSurfacePlane { + BelowGpui, + BetweenBaseAndOverlay, + AboveGpui, +} +``` + +`BetweenBaseAndOverlay` is the main path. GPUI also needs to: + +- Collect window-space bounds, content mask or clip, and visibility for each + native slot every frame. +- Define the native portal insertion point between the end of + `root_element.paint` and the start of `paint_deferred_draws`. `Deferred` + already promises to paint after its ancestors, with higher priority closer + to the viewer + ([GPUI `Deferred` source](https://github.com/zed-industries/zed/blob/66d95fb1945b7a7be671427f11ebfb42c339bdb4/crates/gpui/src/elements/deferred.rs#L7-L96)). +- Continue collecting the window prompt, active drag, and core tooltip after + the deferred overlay scene; the current pipeline paints them later. +- Avoid submitting an additional surface when the overlay plane is empty. +- Hit-test before native input forwarding, so a transparent overlay view does + not consume all WebView input. +- Create, update, and destroy native slots on the platform UI thread in sync + with the GPUI frame lifecycle. + +The platform trait should describe capabilities instead of pretending all +platforms are identical: + +```rust +struct NativeSurfaceCapabilities { + can_embed_between_gpui_planes: bool, + can_clip_non_rectangular: bool, + requires_forwarded_pointer_input: bool, +} +``` + +Linux can then report missing capabilities instead of silently degrading to +"WebView is always on top." + +### Existing overlay coverage audit + +The current split directly covers: + +- `Popover`, `ContextMenu`, `PopupMenu`, and fallback native menu. +- Popups for `Select`, `Combobox`, and `DatePicker`. +- Input completion, code-action, and hover popups. +- `gpui-component::Tooltip` and plot tooltip. + +These implementations use `gpui::deferred`; examples include +[`Popover`](https://github.com/longbridge/gpui-component/blob/be3c8413766cafc736a0c1c80306ff0f293e04f3/crates/ui/src/popover.rs#L335-L350), +[`PopupMenu`](https://github.com/longbridge/gpui-component/blob/be3c8413766cafc736a0c1c80306ff0f293e04f3/crates/ui/src/menu/popup_menu.rs#L1330-L1345), +and +[`Tooltip`](https://github.com/longbridge/gpui-component/blob/be3c8413766cafc736a0c1c80306ff0f293e04f3/crates/ui/src/tooltip.rs#L489-L515). + +Not every visually overlay-like component was originally in the deferred +plane: + +- The GPUI window prompt, active drag, and core tooltip are not in + `deferred_draws`, but `draw_roots` paints them separately afterward. The + final phase must also target the top surface. +- `Root::render_dialog_layer`, `render_sheet_layer`, and + `render_notification_layer` return ordinary absolute or relative elements + and do not wrap themselves in `deferred` + ([Root layer source](https://github.com/longbridge/gpui-component/blob/be3c8413766cafc736a0c1c80306ff0f293e04f3/crates/ui/src/root.rs#L157-L277)). + If a caller adds them as ordinary later root children, they paint after the + WebView element but remain in the base scene and cannot cross the native + portal automatically. +- Dialog, Sheet, and Notification therefore need explicit migration to + deferred or a more direct GPUI `OverlayPlane` element. Migration must test + content masks, modal hitboxes, focus traps, animation, and nested popovers. + Splitting the renderer without migrating these Root layers is incomplete. + +The current spike wraps all three Root layers in `deferred`. This is required +to validate the architecture, but sheet animation, notification placement, +nested popups, and modal focus traps still need dedicated regression testing +before upstreaming. + +`draw_roots` calculates `mouse_hit_test` only after prepainting all deferred +elements, prompts, drags, and tooltips. This is useful for native input routing: +run the existing GPUI hit test first and forward an unhandled event to the +composition WebView. Platform events still reach the GPUI window first, so +Windows must explicitly convert unconsumed events to `SendMouseInput` or +`SendPointerInput`. + +## Implementation Order and Decision Gates + +1. **macOS spike:** prove + `GPUI base / WKWebView / GPUI overlay` pixels and input in one window. Hole + punching may validate the API if stable, but still compare it with two + surfaces. +2. **GPUI scene separation:** use + `root paint / native portal / deferred paint / prompt-drag-tooltip paint` + as the existing skeleton. Promote the overlay plane from a platform hack + into a renderer/window abstraction, move Dialog, Sheet, and Notification + into the top plane, and validate alpha, resize, and hit testing with a + non-WebView test visual. +3. **Windows composition host:** reuse GPUI's `IDCompositionDevice` and root + tree, create a WebView2 composition controller, and complete pointer, + drag/drop, IME, and accessibility support. +4. **Linux feasibility spike:** test a GTK-hosted WebKitWebView with a GPUI + overlay widget on X11 and Wayland separately. Promise support only after + live pixels and input both work; snapshots do not pass. + +Re-evaluate the unified native-embedding route if any of these occur: + +- macOS cannot produce stable local transparent GPUI overlays in an ordinary + opaque window. +- The Windows WebView2 composition visual cannot safely share the lifecycle of + GPUI's device and target. +- Wayland requires a complete GPUI event/window-backend rewrite with + unacceptable maintenance cost. + +Even if Linux cannot reach parity, macOS and Windows can share native-slot and +overlay-plane semantics while reporting different platform capabilities. + +## 2026-07-30 macOS Spike Results + +The current worktree implements and has run the first phase: + +- A GPUI frame records a scene-operation boundary after the root and inspector + but before deferred and window overlays. +- `PlatformWindow::draw_layered` preserves single-surface behavior by default. + The macOS backend replays operations on either side of the boundary into + base and transparent-overlay Metal renderers. +- Both renderers share one Metal device and sprite atlas so atlas tile IDs + remain valid in the second renderer. +- After WKWebView joins the view hierarchy, the macOS window creates a + transparent sibling overlay `NSView/CAMetalLayer`, producing + `base CAMetalLayer / WKWebView / overlay CAMetalLayer`. +- When the overlay has no drawable primitives, `hitTest:` returns `nil` and + WebView receives input. With Popover, Dialog, or similar content, input goes + to GPUI so outside clicks can dismiss the overlay. +- Dialog, Sheet, and Notification have moved into the deferred/top plane. +- The WebView example uses an 800x600 window and provides both Popover and + Dialog scenarios. + +Runtime validation covered: + +1. A Popover renders completely above a real `WKWebView`. +2. Clicking the WebView area outside the Popover closes it without a crash. +3. Dialog, translucent backdrop, text, and buttons render above WebView. +4. The Dialog close hitbox works, and WebView continues working afterward. +5. Notification renders completely above a running WebView page. +6. PopupMenu background, labels, separators, and link items render completely + above WebView. +7. WebView remains clickable while the overlay is empty. +8. Resize and drawable-size updates reach both renderers. + +The Notification layer creates a deferred element only when the list is +non-empty. This avoids a permanent empty top-plane node and unnecessary scene +operations. After opening a Dialog or Notification, the WebView example +explicitly invalidates itself because the example entity currently composes +these Root layers while the state lives in the `Root` entity. + +The spike found and fixed three non-obvious issues: + +- An independent renderer with an independent atlas fails because replayed + tile IDs do not exist in the second atlas. +- Re-locking window state inside Objective-C `hitTest:` causes a re-entrant + deadlock. +- Passing the overlay `NSView` itself to GPUI input processing violates + `NSTextInputContext` assumptions and causes a null-pointer abort. Events must + borrow the original GPUI native view's input context. + +To keep a transparent overlay from permanently intercepting input, +`Scene::is_empty` checks actual drawable primitives rather than paint-operation +count. Empty `StartLayer/EndLayer` operations still increase `Scene::len()`. +Unit tests cover empty layers, drawable primitives, and replay. + +### What the spike has not proved + +- The top plane is currently a window-level switch and one scene split point, + not a complete native-surface-slot API. Multiple WebViews in one window and + interleaved ordering between them are not expressible. +- If the overlay has any drawable primitive, the full transparent NSView takes + input. This supports modal and outside-click behavior, but the production + API should carry top-plane hit regions and explicit `capture`, + `dismiss-then-consume`, and `pass-through` policies. +- macOS still needs regression testing for IME, drag/drop, accessibility, + fullscreen, scale-factor changes, multiple windows, WebView focus, and live + resize. +- Windows CompositionController and Linux GTK/WebKitGTK paths are not + implemented. macOS success does not prove cross-platform completion. diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index f747c3c0ef..16b7c94713 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -29,9 +29,14 @@ impl Drop for WebView { impl WebView { /// Create a new WebView from a wry WebView. - pub fn new(webview: wry::WebView, _: &mut Window, cx: &mut App) -> Self { + pub fn new(webview: wry::WebView, window: &mut Window, cx: &mut App) -> Self { let _ = webview.set_bounds(Rect::default()); + #[cfg(target_os = "macos")] + window + .enable_scene_overlay() + .expect("macOS WebView requires GPUI layered scene support"); + Self { focus_handle: cx.focus_handle(), visible: true, diff --git a/examples/webview/src/main.rs b/examples/webview/src/main.rs index b47e7f27b4..5a224b2ea0 100644 --- a/examples/webview/src/main.rs +++ b/examples/webview/src/main.rs @@ -1,7 +1,11 @@ use gpui::*; use gpui_component::{ - ActiveTheme as _, Root, h_flex, + ActiveTheme as _, Root, WindowExt as _, + button::{Button, ButtonVariants as _}, + h_flex, input::{Input, InputEvent, InputState}, + menu::DropdownMenu as _, + popover::Popover, v_flex, }; use gpui_wry::WebView; @@ -95,6 +99,43 @@ impl Example { webview.back().unwrap(); }); } + + fn show_dialog(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) { + window.open_dialog(cx, |dialog, _, _| { + dialog.title("WebView overlay dialog").child( + v_flex() + .gap_3() + .w(px(520.)) + .child("This modal, its translucent backdrop, text, and controls are all GPUI.") + .child( + div() + .p_4() + .rounded_lg() + .border_1() + .child("The native WKWebView must remain visible behind the backdrop."), + ) + .child( + h_flex() + .gap_2() + .child(Button::new("dialog-secondary").label("Secondary action")) + .child( + Button::new("dialog-primary") + .primary() + .label("Primary action"), + ), + ), + ) + }); + cx.notify(); + } + + fn show_notification(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) { + window.push_notification( + "This GPUI notification is rendered above the native WebView.", + cx, + ); + cx.notify(); + } } impl Focusable for Example { @@ -104,7 +145,7 @@ impl Focusable for Example { } impl Render for Example { - fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let webview = self.webview.clone(); v_flex() @@ -115,7 +156,33 @@ impl Render for Example { h_flex() .gap_2() .items_center() - .child(Input::new(&self.address_input)), + .child(Input::new(&self.address_input)) + .child( + Popover::new("webview-overlay-proof") + .trigger(Button::new("overlay-trigger").label("Overlay proof")) + .w(px(320.)) + .child("This GPUI popover is rendered above the native WebView."), + ) + .child( + Button::new("dialog-trigger") + .label("Open dialog") + .on_click(cx.listener(Self::show_dialog)), + ) + .child( + Button::new("notification-trigger") + .label("Notify") + .on_click(cx.listener(Self::show_notification)), + ) + .child( + Button::new("popup-menu-trigger") + .label("Popup menu") + .dropdown_menu(|menu, _, _| { + menu.label("GPUI above WebView").separator().link( + "Open GPUI Component", + "https://longbridge.github.io/gpui-component/", + ) + }), + ), ) .child( div() @@ -125,6 +192,8 @@ impl Render for Example { .border_color(cx.theme().border) .child(webview.clone()), ) + .children(Root::render_dialog_layer(window, cx)) + .children(Root::render_notification_layer(window, cx)) } } @@ -138,12 +207,19 @@ fn main() { gpui_platform::application().run(move |cx| { // This must be called before using any GPUI Component features. gpui_component::init(cx); + let window_bounds = WindowBounds::centered(size(px(800.), px(600.)), cx); cx.spawn(async move |cx| { - cx.open_window(WindowOptions::default(), |window, cx| { - let view = Example::new(window, cx); - cx.new(|cx| Root::new(view, window, cx)) - }) + cx.open_window( + WindowOptions { + window_bounds: Some(window_bounds), + ..Default::default() + }, + |window, cx| { + let view = Example::new(window, cx); + cx.new(|cx| Root::new(view, window, cx)) + }, + ) .expect("Failed to open window"); }) .detach(); From 9698041bb9e0ac62fa1ca5511e7569b112f48db5 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 22:08:21 +0800 Subject: [PATCH 02/14] fix(webview): avoid unused window parameter off macOS Co-authored-by: Codex --- crates/webview/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index 16b7c94713..8ee0e2d12a 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -29,11 +29,11 @@ impl Drop for WebView { impl WebView { /// Create a new WebView from a wry WebView. - pub fn new(webview: wry::WebView, window: &mut Window, cx: &mut App) -> Self { + pub fn new(webview: wry::WebView, _window: &mut Window, cx: &mut App) -> Self { let _ = webview.set_bounds(Rect::default()); #[cfg(target_os = "macos")] - window + _window .enable_scene_overlay() .expect("macOS WebView requires GPUI layered scene support"); From c36a0e19a8960e37ecd5f78678bb8e19e3f3ce29 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 22:11:13 +0800 Subject: [PATCH 03/14] fix(webview): clear stale GPUI focus on overlay click Co-authored-by: Codex --- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 35 ++++++++++++++++++++++ crates/webview/src/lib.rs | 11 +++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index 70752c0676..cb4d167290 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -695,6 +695,41 @@ Runtime validation covered: 7. WebView remains clickable while the overlay is empty. 8. Resize and drawable-size updates reach both renderers. +### Focus ownership is part of the portal contract + +A native WebView and GPUI maintain separate focus systems. Giving native +keyboard focus to the WebView does not automatically clear GPUI's focused +element. Without an explicit handoff, a GPUI `Input` can keep drawing its +blinking caret after the user clicks the WebView, even though subsequent +typing belongs to the WebView. The result presents two apparent input targets +and makes keyboard ownership ambiguous. + +When GPUI receives a mouse-down inside WebView bounds, the WebView element now +treats it as a focus boundary and clears GPUI window focus. This covers the +top-plane path where the event dismisses a Popover over the WebView region. +When the top plane is empty, however, AppKit sends the event directly to +`WKWebView`; GPUI does not observe that mouse-down. The production native-slot +API must therefore also report native focus acquisition back to the GPUI +window and blur its focus tree. Returning from WebView to GPUI must perform the +inverse handoff through the normal GPUI focus path. + +This is not example-only polish. Any native-surface-slot API must define: + +- which focus system owns keyboard and IME input at every point; +- how pointer, Tab, Shift-Tab, programmatic focus, and overlay dismissal + transfer that ownership; +- that the losing system immediately removes visible focus indicators, + including carets and focus rings; +- that only the owner receives text, composition, and accessibility focus + events. + +Regression validation must first focus the address `Input`, confirm its caret +is visible, and then click the WebView both with no overlay and while a Popover +is open. The overlay-dismiss path now clears the GPUI caret; the direct native +path remains an explicit acceptance gate. In both cases the final +implementation must stop the GPUI caret as WebView receives focus. The reverse +transition must restore exactly one GPUI focus target. + The Notification layer creates a deferred element only when the list is non-empty. This avoids a permanent empty top-plane node and unnecessary scene operations. After opening a Dialog or Notification, the WebView example diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index 8ee0e2d12a..d4f3b20c7c 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -221,9 +221,14 @@ impl Element for WebViewElement { let bounds = hitbox.clone().map(|h| h.bounds).unwrap_or(bounds); window.with_content_mask(Some(ContentMask { bounds }), |window| { let webview = self.view.clone(); - window.on_mouse_event(move |event: &MouseDownEvent, _, _, _| { - if !bounds.contains(&event.position) { - // Click white space to blur the input focus + window.on_mouse_event(move |event: &MouseDownEvent, _, window, _| { + if bounds.contains(&event.position) { + // Native WebView focus is outside GPUI's focus tree. Clear + // GPUI focus so text inputs stop showing a stale caret. + window.blur(); + } else { + // Return native focus to the GPUI parent when clicking + // elsewhere in the GPUI window. let _ = webview.focus_parent(); } }); From 3906d1e748751115db61a61e42e72d2e68cadba0 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 22:45:32 +0800 Subject: [PATCH 04/14] fix(webview): integrate native focus and edit shortcuts Co-authored-by: Codex --- Cargo.lock | 50 +++++++++++----------- Cargo.toml | 10 ++--- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 41 +++++++++++++----- examples/webview/src/main.rs | 8 +++- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b88a9caa75..999d9eb706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "proc-macro2", "quote", @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "accesskit", "anyhow", @@ -3148,7 +3148,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "accesskit", "accesskit_unix", @@ -3200,7 +3200,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "accesskit", "accesskit_macos", @@ -3249,7 +3249,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3260,7 +3260,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "console_error_panic_hook", "gpui", @@ -3273,7 +3273,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "schemars", "serde", @@ -3283,7 +3283,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "log", @@ -3293,7 +3293,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3316,7 +3316,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "bytemuck", @@ -3346,7 +3346,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "accesskit", "accesskit_windows", @@ -3662,7 +3662,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "async-compression", @@ -3682,7 +3682,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "rustls", "rustls-platform-verifier", @@ -4717,7 +4717,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "bindgen", @@ -5142,7 +5142,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.117", @@ -5723,7 +5723,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "collections", "serde", @@ -6721,7 +6721,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "derive_refineable", ] @@ -6773,7 +6773,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "bytes", @@ -7210,7 +7210,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "async-task", "backtrace", @@ -7831,7 +7831,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "heapless", "log", @@ -9312,7 +9312,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "perf", "quote", @@ -11311,7 +11311,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "anyhow", "chrono", @@ -11328,7 +11328,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" dependencies = [ "tracing", "tracing-subscriber", @@ -11339,7 +11339,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?rev=896e7f138b385f745b3f58aba1cb66c647fa1dda#896e7f138b385f745b3f58aba1cb66c647fa1dda" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index a075f28970..19f2dddce1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,11 +33,11 @@ gpui-component-macros = { path = "crates/macros", version = "0.5.1" } gpui-component-assets = { path = "crates/assets", version = "0.5.1" } story = { path = "crates/story" } -gpui = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } -gpui_platform = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda", features = ["font-kit", "x11", "wayland", "runtime_shaders"] } -gpui_web = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } -gpui_macros = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } -reqwest_client = { git = "https://github.com/huacnlee/zed", rev = "896e7f138b385f745b3f58aba1cb66c647fa1dda" } +gpui = { git = "https://github.com/huacnlee/zed", branch = "gpui-webview-overlay" } +gpui_platform = { git = "https://github.com/huacnlee/zed", branch = "gpui-webview-overlay", features = ["font-kit", "x11", "wayland", "runtime_shaders"] } +gpui_web = { git = "https://github.com/huacnlee/zed", branch = "gpui-webview-overlay" } +gpui_macros = { git = "https://github.com/huacnlee/zed", branch = "gpui-webview-overlay" } +reqwest_client = { git = "https://github.com/huacnlee/zed", branch = "gpui-webview-overlay" } sum-tree = { version = "0.2.0", package = "zed-sum-tree" } # reqwest = { version = "0.12.15-zed", package = "zed-reqwest" } reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662463bda39148ba154100dd44d3fba5873a4", default-features = false, features = [ diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index cb4d167290..a5677aac0a 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -2,7 +2,7 @@ > Research date: 2026-07-30 > Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit -> `896e7f138b385f745b3f58aba1cb66c647fa1dda`. This document records the +> `huacnlee/zed:gpui-webview-overlay` at `41dbc82966`. This document records the > native composition research, the implemented macOS layered-scene spike, and > the remaining Windows and Linux architecture. @@ -704,14 +704,22 @@ blinking caret after the user clicks the WebView, even though subsequent typing belongs to the WebView. The result presents two apparent input targets and makes keyboard ownership ambiguous. -When GPUI receives a mouse-down inside WebView bounds, the WebView element now +When GPUI receives a mouse-down inside WebView bounds, the WebView element treats it as a focus boundary and clears GPUI window focus. This covers the top-plane path where the event dismisses a Popover over the WebView region. -When the top plane is empty, however, AppKit sends the event directly to -`WKWebView`; GPUI does not observe that mouse-down. The production native-slot -API must therefore also report native focus acquisition back to the GPUI -window and blur its focus tree. Returning from WebView to GPUI must perform the -inverse handoff through the normal GPUI focus path. +When the top plane is empty, AppKit sends the event directly to `WKWebView`. +The macOS platform now native-hit-tests mouse-down events before AppKit +dispatch and emits `PlatformInput::NativeViewFocus` when the hit view is an +embedded native descendant rather than the GPUI or overlay surface. That event +uses GPUI's normal input callback and synchronously blurs the logical focus +tree. `makeFirstResponder:` provides the equivalent path for keyboard and +programmatic native focus changes. + +This distinction is subtle: wry inserts `WKWebView` as a descendant of +`GPUIView`, so membership in the GPUI native-view hierarchy is not sufficient +to identify GPUI ownership. Only the GPUI rendering view itself and its +separate overlay view count as GPUI surfaces; embedded descendants are native +focus targets. Returning from WebView to GPUI uses the normal GPUI focus path. This is not example-only polish. Any native-surface-slot API must define: @@ -725,10 +733,21 @@ This is not example-only polish. Any native-surface-slot API must define: Regression validation must first focus the address `Input`, confirm its caret is visible, and then click the WebView both with no overlay and while a Popover -is open. The overlay-dismiss path now clears the GPUI caret; the direct native -path remains an explicit acceptance gate. In both cases the final -implementation must stop the GPUI caret as WebView receives focus. The reverse -transition must restore exactly one GPUI focus target. +is open. Both paths now stop the GPUI caret as WebView receives focus. Runtime +diagnostics verified the active-window native path by observing GPUI focus +change from focused to blurred after a WebView click. The reverse transition +must restore exactly one GPUI focus target. + +On macOS, `Cmd+C`, `Cmd+V`, `Cmd+X`, and `Cmd+A` are AppKit key equivalents +routed through standard Edit-menu selectors and the responder chain. A bare +GPUI example without those menu items can display and focus WKWebView while +copy and paste shortcuts still do nothing. The example therefore installs an +Edit menu whose `MenuItem::os_action` entries map to Cut, Copy, Paste, and +Select All. When WKWebView owns native focus, AppKit routes those selectors to +WebKit; when GPUI owns focus, the same items dispatch the corresponding GPUI +input actions. Native-surface examples and host applications must preserve +this responder-chain integration rather than implementing clipboard shortcuts +as WebView-specific JavaScript. The Notification layer creates a deferred element only when the list is non-empty. This avoids a permanent empty top-plane node and unnecessary scene diff --git a/examples/webview/src/main.rs b/examples/webview/src/main.rs index 5a224b2ea0..9846a6959c 100644 --- a/examples/webview/src/main.rs +++ b/examples/webview/src/main.rs @@ -3,7 +3,7 @@ use gpui_component::{ ActiveTheme as _, Root, WindowExt as _, button::{Button, ButtonVariants as _}, h_flex, - input::{Input, InputEvent, InputState}, + input::{Copy, Cut, Input, InputEvent, InputState, Paste, SelectAll}, menu::DropdownMenu as _, popover::Popover, v_flex, @@ -207,6 +207,12 @@ fn main() { gpui_platform::application().run(move |cx| { // This must be called before using any GPUI Component features. gpui_component::init(cx); + cx.set_menus([Menu::new("Edit").items([ + MenuItem::os_action("Cut", Cut, OsAction::Cut), + MenuItem::os_action("Copy", Copy, OsAction::Copy), + MenuItem::os_action("Paste", Paste, OsAction::Paste), + MenuItem::os_action("Select All", SelectAll, OsAction::SelectAll), + ])]); let window_bounds = WindowBounds::centered(size(px(800.), px(600.)), cx); cx.spawn(async move |cx| { From f958ea989927c4e3e354d0a55459edb17fdde008 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 22:50:45 +0800 Subject: [PATCH 05/14] chore(webview): update overlay branch baseline Co-authored-by: Codex --- Cargo.lock | 54 +++++++++++----------- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 999d9eb706..7f13881a00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.11.0", "log", "prettyplease", "proc-macro2", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "proc-macro2", "quote", @@ -2874,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.62.2", + "windows 0.58.0", ] [[package]] @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "accesskit", "anyhow", @@ -3148,7 +3148,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "accesskit", "accesskit_unix", @@ -3200,7 +3200,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "accesskit", "accesskit_macos", @@ -3249,7 +3249,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3260,7 +3260,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "console_error_panic_hook", "gpui", @@ -3273,7 +3273,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "schemars", "serde", @@ -3283,7 +3283,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "log", @@ -3293,7 +3293,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3316,7 +3316,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "bytemuck", @@ -3346,7 +3346,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "accesskit", "accesskit_windows", @@ -3662,7 +3662,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "async-compression", @@ -3682,7 +3682,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3763,7 +3763,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.58.0", ] [[package]] @@ -4717,7 +4717,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "bindgen", @@ -5723,7 +5723,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "collections", "serde", @@ -6721,7 +6721,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "derive_refineable", ] @@ -6773,7 +6773,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "bytes", @@ -7210,7 +7210,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "async-task", "backtrace", @@ -7831,7 +7831,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "heapless", "log", @@ -9312,7 +9312,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "perf", "quote", @@ -11311,7 +11311,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "anyhow", "chrono", @@ -11328,7 +11328,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" dependencies = [ "tracing", "tracing-subscriber", @@ -11339,7 +11339,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#41dbc8296609fc800ebc832b6fbb31860c96feed" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" [[package]] name = "zune-core" diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index a5677aac0a..d4f2fa4fc3 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -2,7 +2,7 @@ > Research date: 2026-07-30 > Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit -> `huacnlee/zed:gpui-webview-overlay` at `41dbc82966`. This document records the +> `huacnlee/zed:gpui-webview-overlay` at `847a8e30d7`. This document records the > native composition research, the implemented macOS layered-scene spike, and > the remaining Windows and Linux architecture. From cbf63b5f1983a51b1820a82bfbae6827c1885089 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 23:08:08 +0800 Subject: [PATCH 06/14] fix(webview): hand off native focus on macOS Keep WebView focus ownership in gpui-wry so GPUI only needs the scene overlay changes. Document the responder-chain requirements for clipboard shortcuts. Co-authored-by: Codex --- Cargo.lock | 57 +++++++++--------- crates/webview/Cargo.toml | 5 ++ crates/webview/README.md | 26 +++++--- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 38 ++++++------ crates/webview/src/lib.rs | 69 ++++++++++++++++++++++ 5 files changed, 142 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f13881a00..38a524bb92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "proc-macro2", "quote", @@ -2874,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.58.0", + "windows 0.62.2", ] [[package]] @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "accesskit", "anyhow", @@ -3141,14 +3141,17 @@ name = "gpui-wry" version = "0.5.0" dependencies = [ "anyhow", + "block2 0.6.2", "gpui", "lb-wry", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", ] [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "accesskit", "accesskit_unix", @@ -3200,7 +3203,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "accesskit", "accesskit_macos", @@ -3249,7 +3252,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3260,7 +3263,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "console_error_panic_hook", "gpui", @@ -3273,7 +3276,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "schemars", "serde", @@ -3283,7 +3286,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "log", @@ -3293,7 +3296,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3316,7 +3319,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "bytemuck", @@ -3346,7 +3349,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "accesskit", "accesskit_windows", @@ -3662,7 +3665,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "async-compression", @@ -3682,7 +3685,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3763,7 +3766,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.62.2", ] [[package]] @@ -4717,7 +4720,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "bindgen", @@ -5723,7 +5726,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "collections", "serde", @@ -6721,7 +6724,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "derive_refineable", ] @@ -6773,7 +6776,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "bytes", @@ -7210,7 +7213,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "async-task", "backtrace", @@ -7831,7 +7834,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "heapless", "log", @@ -9312,7 +9315,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "perf", "quote", @@ -11311,7 +11314,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "anyhow", "chrono", @@ -11328,7 +11331,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" dependencies = [ "tracing", "tracing-subscriber", @@ -11339,7 +11342,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#847a8e30d761612db1d673385a428030dbee458f" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" [[package]] name = "zune-core" diff --git a/crates/webview/Cargo.toml b/crates/webview/Cargo.toml index 684325a5ff..c6ad21c2f9 100644 --- a/crates/webview/Cargo.toml +++ b/crates/webview/Cargo.toml @@ -21,3 +21,8 @@ doctest = false anyhow.workspace = true gpui.workspace = true wry = { version = "0.53.3", package = "lb-wry" } + +[target.'cfg(target_os = "macos")'.dependencies] +block2 = "0.6" +objc2 = "0.6" +objc2-app-kit = { version = "0.3", features = ["block2", "NSEvent", "NSView", "NSWindow"] } diff --git a/crates/webview/README.md b/crates/webview/README.md index be0c950898..2674cf9068 100644 --- a/crates/webview/README.md +++ b/crates/webview/README.md @@ -1,13 +1,23 @@ # Wry for GPUI -A webview supports for GPUI, based on [Wry](https://github.com/tauri-apps/wry). - -This still a experimental with limited features, please file issues for any bugs or missing features. - -- The WebView will render on top of the GPUI window, any GPUI elements behind the WebView bounds will be covered. -- Only supports macOS and Windows currently. - -So, we recommend using the webview in a separate window or in a Popup layer. +A WebView implementation for GPUI, based on [Wry](https://github.com/tauri-apps/wry). + +This is still experimental with limited features. Please file issues for bugs or missing features. + +- On macOS, GPUI Popovers, Dialogs, Notifications, and Popup Menus can render + above the WebView when using the layered-scene GPUI branch configured by + this repository. +- The WebView owns native keyboard focus after it is clicked. `gpui-wry` + clears GPUI's logical focus at that boundary so an Input does not continue + showing a stale blinking caret. +- On macOS, applications must provide standard Edit-menu actions for Cut, + Copy, Paste, and Select All. AppKit routes their keyboard shortcuts through + the responder chain to either the focused WebView or GPUI. +- Only macOS and Windows are currently supported. Windows overlay composition + remains future work. + +See [`WEBVIEW_OVERLAY_RESEARCH.md`](WEBVIEW_OVERLAY_RESEARCH.md) for the +composition, focus, input, and platform details. ## Run Example diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index d4f2fa4fc3..fc910feffa 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -2,7 +2,7 @@ > Research date: 2026-07-30 > Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit -> `huacnlee/zed:gpui-webview-overlay` at `847a8e30d7`. This document records the +> `huacnlee/zed:gpui-webview-overlay` at `fbe67f26a3`. This document records the > native composition research, the implemented macOS layered-scene spike, and > the remaining Windows and Linux architecture. @@ -708,18 +708,18 @@ When GPUI receives a mouse-down inside WebView bounds, the WebView element treats it as a focus boundary and clears GPUI window focus. This covers the top-plane path where the event dismisses a Popover over the WebView region. When the top plane is empty, AppKit sends the event directly to `WKWebView`. -The macOS platform now native-hit-tests mouse-down events before AppKit -dispatch and emits `PlatformInput::NativeViewFocus` when the hit view is an -embedded native descendant rather than the GPUI or overlay surface. That event -uses GPUI's normal input callback and synchronously blurs the logical focus -tree. `makeFirstResponder:` provides the equivalent path for keyboard and -programmatic native focus changes. - -This distinction is subtle: wry inserts `WKWebView` as a descendant of -`GPUIView`, so membership in the GPUI native-view hierarchy is not sufficient -to identify GPUI ownership. Only the GPUI rendering view itself and its -separate overlay view count as GPUI surfaces; embedded descendants are native -focus targets. Returning from WebView to GPUI uses the normal GPUI focus path. +`gpui-wry` therefore installs a lifecycle-scoped local `NSEvent` monitor for +mouse-down events. The monitor checks the event window, native-hit-tests the +content view, and clears this GPUI window's logical focus only when the hit +view is the managed `WKWebView` or one of its descendants. The monitor token +is removed when the `WebView` is dropped. + +Keeping this handoff in `gpui-wry` is deliberate. It avoids adding a +WebView-specific focus event, AppKit responder override, or native-descendant +classification to GPUI. The GPUI platform patch stays limited to scene +composition, while the component that owns the embedded native view also owns +its focus boundary. Returning from WebView to GPUI uses the normal GPUI focus +path. This is not example-only polish. Any native-surface-slot API must define: @@ -733,10 +733,10 @@ This is not example-only polish. Any native-surface-slot API must define: Regression validation must first focus the address `Input`, confirm its caret is visible, and then click the WebView both with no overlay and while a Popover -is open. Both paths now stop the GPUI caret as WebView receives focus. Runtime -diagnostics verified the active-window native path by observing GPUI focus -change from focused to blurred after a WebView click. The reverse transition -must restore exactly one GPUI focus target. +is open. Both paths stop the GPUI caret as WebView receives focus. Runtime +validation confirmed that the address Input loses its focus indication after +a direct WebView click and that clicking the WebView region dismisses an open +Popover. The reverse transition must restore exactly one GPUI focus target. On macOS, `Cmd+C`, `Cmd+V`, `Cmd+X`, and `Cmd+A` are AppKit key equivalents routed through standard Edit-menu selectors and the responder chain. A bare @@ -747,7 +747,9 @@ Select All. When WKWebView owns native focus, AppKit routes those selectors to WebKit; when GPUI owns focus, the same items dispatch the corresponding GPUI input actions. Native-surface examples and host applications must preserve this responder-chain integration rather than implementing clipboard shortcuts -as WebView-specific JavaScript. +as WebView-specific JavaScript. Runtime validation copied a sentinel from a +GPUI Input into a WebView text field and another sentinel from the WebView back +into the GPUI Input using only `Cmd+C` and `Cmd+V`. The Notification layer creates a deferred element only when the list is non-empty. This avoids a permanent empty top-plane node and unnecessary scene diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index d4f3b20c7c..d48f629429 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -1,10 +1,17 @@ use std::{ops::Deref, rc::Rc}; +#[cfg(target_os = "macos")] +use block2::RcBlock; use wry::{ Rect, dpi::{self, LogicalSize}, }; +#[cfg(target_os = "macos")] +use objc2::{rc::Retained, runtime::AnyObject}; +#[cfg(target_os = "macos")] +use objc2_app_kit::{NSEvent, NSEventMask}; + use gpui::{ App, Bounds, ContentMask, DismissEvent, Element, ElementId, Entity, EventEmitter, FocusHandle, Focusable, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId, MouseDownEvent, @@ -19,10 +26,18 @@ pub struct WebView { webview: Rc, visible: bool, bounds: Bounds, + #[cfg(target_os = "macos")] + event_monitor: Option>, } impl Drop for WebView { fn drop(&mut self) { + #[cfg(target_os = "macos")] + if let Some(event_monitor) = self.event_monitor.take() { + // SAFETY: The token was returned by addLocalMonitor and is removed + // exactly once while the application is still running. + unsafe { NSEvent::removeMonitor(&event_monitor) }; + } self.hide(); } } @@ -37,11 +52,16 @@ impl WebView { .enable_scene_overlay() .expect("macOS WebView requires GPUI layered scene support"); + #[cfg(target_os = "macos")] + let event_monitor = install_focus_monitor(&webview, _window, cx); + Self { focus_handle: cx.focus_handle(), visible: true, bounds: Bounds::default(), webview: Rc::new(webview), + #[cfg(target_os = "macos")] + event_monitor, } } @@ -84,6 +104,55 @@ impl WebView { } } +#[cfg(target_os = "macos")] +fn install_focus_monitor( + webview: &wry::WebView, + window: &Window, + cx: &App, +) -> Option> { + use wry::WebViewExtMacOS as _; + + let native_webview = webview.webview(); + let native_window = webview.ns_window(); + let async_window = window.to_async(cx); + let foreground_executor = cx.foreground_executor().clone(); + let handler = RcBlock::new(move |event: std::ptr::NonNull| { + let event = unsafe { event.as_ref() }; + let clicked_webview = event + .window(objc2::MainThreadMarker::new().expect("NSEvent runs on the main thread")) + .filter(|event_window| std::ptr::eq(&**event_window, &*native_window)) + .and_then(|event_window| event_window.contentView()) + .and_then(|content_view| { + let point = content_view.convertPoint_fromView(event.locationInWindow(), None); + content_view.hitTest(point) + }) + .is_some_and(|hit_view| { + std::ptr::eq(&*hit_view, &***native_webview) + || hit_view.isDescendantOf(&native_webview) + }); + + if clicked_webview { + let mut async_window = async_window.clone(); + foreground_executor + .spawn(async move { + let _ = async_window.update(|window, _| window.blur()); + }) + .detach(); + } + + event as *const NSEvent as *mut NSEvent + }); + + // SAFETY: The block returns the same live NSEvent it receives. The retained + // monitor token is stored on WebView and removed in Drop. + unsafe { + NSEvent::addLocalMonitorForEventsMatchingMask_handler( + NSEventMask::LeftMouseDown | NSEventMask::RightMouseDown | NSEventMask::OtherMouseDown, + &handler, + ) + } +} + impl Deref for WebView { type Target = wry::WebView; From 4e560a95f2c909fdaee5c4be26d3e36a8bb68478 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 23:30:04 +0800 Subject: [PATCH 07/14] feat(webview): host WebView2 in GPUI composition portals Build Windows WebViews with the wry composition controller and synchronize the GPUI native-surface portal bounds. Keep the existing macOS path unchanged. Co-authored-by: Codex --- Cargo.lock | 60 +++++++++++++++---------------- crates/webview/Cargo.toml | 5 ++- crates/webview/src/lib.rs | 68 +++++++++++++++++++++++++++++++++++- examples/webview/Cargo.toml | 2 +- examples/webview/src/main.rs | 21 ++++------- 5 files changed, 109 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38a524bb92..7f087e955e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.11.0", "log", "prettyplease", "proc-macro2", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "proc-macro2", "quote", @@ -2874,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.62.2", + "windows 0.58.0", ] [[package]] @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "accesskit", "anyhow", @@ -3146,12 +3146,13 @@ dependencies = [ "lb-wry", "objc2 0.6.4", "objc2-app-kit 0.3.2", + "windows-core 0.61.2", ] [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "accesskit", "accesskit_unix", @@ -3203,7 +3204,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "accesskit", "accesskit_macos", @@ -3252,7 +3253,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3263,7 +3264,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "console_error_panic_hook", "gpui", @@ -3276,7 +3277,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "schemars", "serde", @@ -3286,7 +3287,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "log", @@ -3296,7 +3297,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3319,7 +3320,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "bytemuck", @@ -3349,7 +3350,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "accesskit", "accesskit_windows", @@ -3665,7 +3666,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "async-compression", @@ -3685,7 +3686,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3766,7 +3767,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.58.0", ] [[package]] @@ -4300,8 +4301,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lb-wry" version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9cfe72bff8acf9af0d6d276569be5b9cb3f313f9882761ada5a50d3044214d4" +source = "git+https://github.com/longbridge/wry?branch=gpui-composition-controller#2d0b3e26f152ab82ca0bae5a7c365a68ca4349fe" dependencies = [ "base64", "block2 0.6.2", @@ -4720,7 +4720,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "bindgen", @@ -5145,7 +5145,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5726,7 +5726,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "collections", "serde", @@ -6724,7 +6724,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "derive_refineable", ] @@ -6776,7 +6776,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "bytes", @@ -7213,7 +7213,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "async-task", "backtrace", @@ -7834,7 +7834,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "heapless", "log", @@ -9315,7 +9315,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "perf", "quote", @@ -11314,7 +11314,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "anyhow", "chrono", @@ -11331,7 +11331,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" dependencies = [ "tracing", "tracing-subscriber", @@ -11342,7 +11342,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#fbe67f26a3db8cb564fd41c29bbc0b97a4aad3ff" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" [[package]] name = "zune-core" diff --git a/crates/webview/Cargo.toml b/crates/webview/Cargo.toml index c6ad21c2f9..b18a67f206 100644 --- a/crates/webview/Cargo.toml +++ b/crates/webview/Cargo.toml @@ -20,9 +20,12 @@ doctest = false [dependencies] anyhow.workspace = true gpui.workspace = true -wry = { version = "0.53.3", package = "lb-wry" } +wry = { git = "https://github.com/longbridge/wry", branch = "gpui-composition-controller", package = "lb-wry" } [target.'cfg(target_os = "macos")'.dependencies] block2 = "0.6" objc2 = "0.6" objc2-app-kit = { version = "0.3", features = ["block2", "NSEvent", "NSView", "NSWindow"] } + +[target.'cfg(target_os = "windows")'.dependencies] +windows-core = "0.61" diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index d48f629429..37411ef6f7 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -28,6 +28,8 @@ pub struct WebView { bounds: Bounds, #[cfg(target_os = "macos")] event_monitor: Option>, + #[cfg(target_os = "windows")] + native_surface: Option>, } impl Drop for WebView { @@ -43,8 +45,41 @@ impl Drop for WebView { } impl WebView { + /// Builds a child WebView using the platform's native-surface integration. + pub fn build_as_child( + builder: wry::WebViewBuilder<'_>, + parent: &impl wry::raw_window_handle::HasWindowHandle, + window: &Window, + cx: &mut App, + ) -> anyhow::Result { + #[cfg(target_os = "windows")] + { + use wry::WebViewBuilderExtWindows as _; + + let native_surface = window.create_native_surface()?; + let platform_handle = native_surface.platform_handle(); + let root_visual = platform_handle + .downcast::() + .map_err(|_| anyhow::anyhow!("GPUI returned an invalid Windows portal handle"))?; + let webview = builder + .with_composition_root_visual(*root_visual) + .build_as_child(parent)?; + return Ok(Self::new_with_native_surface( + webview, + native_surface, + window, + cx, + )); + } + + #[cfg(not(target_os = "windows"))] + { + Ok(Self::new(builder.build_as_child(parent)?, window, cx)) + } + } + /// Create a new WebView from a wry WebView. - pub fn new(webview: wry::WebView, _window: &mut Window, cx: &mut App) -> Self { + pub fn new(webview: wry::WebView, _window: &Window, cx: &mut App) -> Self { let _ = webview.set_bounds(Rect::default()); #[cfg(target_os = "macos")] @@ -62,12 +97,34 @@ impl WebView { webview: Rc::new(webview), #[cfg(target_os = "macos")] event_monitor, + #[cfg(target_os = "windows")] + native_surface: None, + } + } + + #[cfg(target_os = "windows")] + fn new_with_native_surface( + webview: wry::WebView, + native_surface: Rc, + _window: &Window, + cx: &mut App, + ) -> Self { + Self { + focus_handle: cx.focus_handle(), + visible: true, + bounds: Bounds::default(), + webview: Rc::new(webview), + native_surface: Some(native_surface), } } /// Show the webview. pub fn show(&mut self) { let _ = self.webview.set_visible(true); + #[cfg(target_os = "windows")] + if let Some(native_surface) = &self.native_surface { + let _ = native_surface.set_visible(true); + } self.visible = true; } @@ -75,6 +132,10 @@ impl WebView { pub fn hide(&mut self) { _ = self.webview.focus_parent(); _ = self.webview.set_visible(false); + #[cfg(target_os = "windows")] + if let Some(native_surface) = &self.native_surface { + let _ = native_surface.set_visible(false); + } self.visible = false; } @@ -273,6 +334,11 @@ impl Element for WebViewElement { )), }); + #[cfg(target_os = "windows")] + if let Some(native_surface) = &self.parent.read(cx).native_surface { + let _ = native_surface.set_bounds(bounds.to_device_pixels(window.scale_factor())); + } + // Create a hitbox to handle mouse event Some(window.insert_hitbox(bounds, gpui::HitboxBehavior::Normal)) } diff --git a/examples/webview/Cargo.toml b/examples/webview/Cargo.toml index eb792facbb..fc3cf76733 100644 --- a/examples/webview/Cargo.toml +++ b/examples/webview/Cargo.toml @@ -16,7 +16,7 @@ gpui-component = { workspace = true } # WebView dependencies gpui-wry = { path = "../../crates/webview" } -wry = { version = "0.53.3", package = "lb-wry" } +wry = { git = "https://github.com/longbridge/wry", branch = "gpui-composition-controller", package = "lb-wry" } raw-window-handle = { version = "0.6", features = ["std"] } [target."cfg(target_os = \"linux\")".dependencies] diff --git a/examples/webview/src/main.rs b/examples/webview/src/main.rs index 9846a6959c..e08dba2135 100644 --- a/examples/webview/src/main.rs +++ b/examples/webview/src/main.rs @@ -29,7 +29,7 @@ impl Example { target_os = "ios", target_os = "android" )))] - let webview = { + { use gtk::prelude::*; use wry::WebViewBuilderExtUnix; // borrowed from https://github.com/tauri-apps/wry/blob/dev/examples/gtk_multiwebview.rs @@ -37,22 +37,21 @@ impl Example { // TODO: How to initialize this fixed? let fixed = gtk::Fixed::builder().build(); fixed.show_all(); - builder.build_gtk(&fixed).unwrap() - }; + let webview = builder.build_gtk(&fixed).unwrap(); + return WebView::new(webview, window, cx); + } #[cfg(any( target_os = "windows", target_os = "macos", target_os = "ios", target_os = "android" ))] - let webview = { + { use raw_window_handle::HasWindowHandle; let window_handle = window.window_handle().expect("No window handle"); - builder.build_as_child(&window_handle).unwrap() - }; - - WebView::new(webview, window, cx) + WebView::build_as_child(builder, &window_handle, window, cx).unwrap() + } }); let address_input = cx.new(|cx| { @@ -198,12 +197,6 @@ impl Render for Example { } fn main() { - // Required this for Windows to render the WebView. - #[cfg(target_os = "windows")] - unsafe { - std::env::set_var("GPUI_DISABLE_DIRECT_COMPOSITION", "true"); - } - gpui_platform::application().run(move |cx| { // This must be called before using any GPUI Component features. gpui_component::init(cx); From b0fa94356bf94e990f561dcc211c9d851a168a46 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 23:38:11 +0800 Subject: [PATCH 08/14] chore(webview): update GPUI Windows composition revision Co-authored-by: Codex --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f087e955e..4f59d6ec83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "proc-macro2", "quote", @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "anyhow", @@ -3152,7 +3152,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_unix", @@ -3204,7 +3204,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_macos", @@ -3253,7 +3253,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3264,7 +3264,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "console_error_panic_hook", "gpui", @@ -3277,7 +3277,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "schemars", "serde", @@ -3287,7 +3287,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "log", @@ -3297,7 +3297,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3320,7 +3320,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bytemuck", @@ -3350,7 +3350,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_windows", @@ -3666,7 +3666,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "async-compression", @@ -3686,7 +3686,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "rustls", "rustls-platform-verifier", @@ -4720,7 +4720,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bindgen", @@ -5726,7 +5726,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "collections", "serde", @@ -6724,7 +6724,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "derive_refineable", ] @@ -6776,7 +6776,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bytes", @@ -7213,7 +7213,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "async-task", "backtrace", @@ -7834,7 +7834,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "heapless", "log", @@ -9315,7 +9315,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "perf", "quote", @@ -11314,7 +11314,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "chrono", @@ -11331,7 +11331,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "tracing", "tracing-subscriber", @@ -11342,7 +11342,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#deafa650ce388c5ba715aea809f73ccc761b2e72" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" [[package]] name = "zune-core" From 633fcdcedfccaa6912e652e567cb4e3d8059b163 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 23:45:05 +0800 Subject: [PATCH 09/14] docs(webview): defer Linux overlay support Co-authored-by: Codex --- crates/webview/README.md | 8 +++-- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 35 ++++++++++++++++------ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/crates/webview/README.md b/crates/webview/README.md index 2674cf9068..595187ef63 100644 --- a/crates/webview/README.md +++ b/crates/webview/README.md @@ -13,8 +13,12 @@ This is still experimental with limited features. Please file issues for bugs or - On macOS, applications must provide standard Edit-menu actions for Cut, Copy, Paste, and Select All. AppKit routes their keyboard shortcuts through the responder chain to either the focused WebView or GPUI. -- Only macOS and Windows are currently supported. Windows overlay composition - remains future work. +- This overlay work targets macOS and Windows. Windows support uses WebView2 + composition hosting and is still experimental. +- Linux overlay support is intentionally deferred. wry uses different X11 and + Wayland integration paths, and neither provides the compositable native + surface needed to place arbitrary GPUI elements above a live WebView without + substantially reworking GPUI's Linux GTK/GDK window backend. See [`WEBVIEW_OVERLAY_RESEARCH.md`](WEBVIEW_OVERLAY_RESEARCH.md) for the composition, focus, input, and platform details. diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index fc910feffa..c5a2c2e9f1 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -4,7 +4,21 @@ > Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit > `huacnlee/zed:gpui-webview-overlay` at `fbe67f26a3`. This document records the > native composition research, the implemented macOS layered-scene spike, and -> the remaining Windows and Linux architecture. +> the Windows architecture. + +## Platform Scope + +This implementation targets **macOS and Windows**. Linux overlay support is +intentionally deferred and is not a completion requirement for this work. +wry's Linux hosting differs between X11 child windows and Wayland GTK widgets; +neither route exposes a compositable native surface that can be inserted +between GPUI's base and overlay scenes. Supporting the same behavior would +require substantial integration with GPUI's GTK/GDK window backend rather than +a local WebView adapter change. + +The Linux analysis below is retained to explain that boundary and prevent an +unsupported child-window or snapshot fallback from being mistaken for feature +parity. ## Conclusion @@ -23,7 +37,7 @@ The recommended end state is a GPUI **native surface slot**: that their GPU visual is above the WebView visual. Input is routed to the overlay or WebView according to GPUI hit testing. 4. Validate the design on macOS first. Windows must use WebView2 composition - hosting. Linux cannot promise an implementation with the same cost. + hosting. Linux is outside the current implementation scope. GPUI already has a better natural split point than an arbitrary `z-index`. `Window::draw_roots` paints the root, calls `paint_deferred_draws`, and finally @@ -48,7 +62,7 @@ component names as overlays. | --- | --- | --- | --- | | macOS | `WKWebView` as an `NSView` subview | **Promising; validate first** | Put WKWebView and the GPUI Metal views in an explicit sibling view/layer hierarchy; validate transparent overlays, input, and resize | | Windows | WebView2 controller hosted in a separate `WS_CHILD` HWND | **Unreliable; not a final design** | Fork or extend wry to use WebView2 Composition Controller and attach the WebView visual to GPUI's DirectComposition tree | -| Linux | X11 child window or GTK `WebKitWebView` widget | X11 child window: **no**; a unified GTK tree may work | Wayland requires the window and layout to join the GTK widget tree; otherwise only a limited snapshot/offscreen fallback is possible | +| Linux | X11 child window or GTK `WebKitWebView` widget | **Deferred; not supported by this overlay work** | Correct support requires GPUI's Linux window backend to join the GTK/GDK hierarchy; child-window and snapshot fallbacks do not provide feature parity | ## Why the Current Implementation Always Covers GPUI @@ -495,7 +509,7 @@ portal handle guarantees the slot visual's lifetime. The first three stages prove only that WebView can display with an overlay. Interactive, accessible, recoverable product support requires stages 4-8 too. -## Linux: GTK/WebKitGTK and Native Child-Window Constraints +## Linux (Deferred): GTK/WebKitGTK and Native Child-Window Constraints ### Primary-source facts @@ -646,9 +660,11 @@ Windows must explicitly convert unconsumed events to `SendMouseInput` or 3. **Windows composition host:** reuse GPUI's `IDCompositionDevice` and root tree, create a WebView2 composition controller, and complete pointer, drag/drop, IME, and accessibility support. -4. **Linux feasibility spike:** test a GTK-hosted WebKitWebView with a GPUI - overlay widget on X11 and Wayland separately. Promise support only after - live pixels and input both work; snapshots do not pass. + +Linux is not part of this implementation order. A future, separately scoped +feasibility project would need to test a GTK-hosted WebKitWebView with a GPUI +overlay widget on X11 and Wayland independently; snapshots would not qualify +as live WebView support. Re-evaluate the unified native-embedding route if any of these occur: @@ -784,5 +800,6 @@ Unit tests cover empty layers, drawable primitives, and replay. - macOS still needs regression testing for IME, drag/drop, accessibility, fullscreen, scale-factor changes, multiple windows, WebView focus, and live resize. -- Windows CompositionController and Linux GTK/WebKitGTK paths are not - implemented. macOS success does not prove cross-platform completion. +- Windows CompositionController runtime behavior is not yet fully validated. + Linux GTK/WebKitGTK support is intentionally deferred and is not used to + judge macOS/Windows completion. From c4313769b8dec07381c6000515c80c6807a60293 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 30 Jul 2026 23:46:09 +0800 Subject: [PATCH 10/14] docs(webview): clarify deferred Linux integration Co-authored-by: Codex --- crates/webview/README.md | 7 ++++--- crates/webview/WEBVIEW_OVERLAY_RESEARCH.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/webview/README.md b/crates/webview/README.md index 595187ef63..d71c1d1d2c 100644 --- a/crates/webview/README.md +++ b/crates/webview/README.md @@ -16,9 +16,10 @@ This is still experimental with limited features. Please file issues for bugs or - This overlay work targets macOS and Windows. Windows support uses WebView2 composition hosting and is still experimental. - Linux overlay support is intentionally deferred. wry uses different X11 and - Wayland integration paths, and neither provides the compositable native - surface needed to place arbitrary GPUI elements above a live WebView without - substantially reworking GPUI's Linux GTK/GDK window backend. + Wayland integration paths and does not expose a surface that can be inserted + directly into GPUI's existing composition tree. Matching macOS and Windows + would require substantial integration with GPUI's Linux GTK/GDK window + backend. See [`WEBVIEW_OVERLAY_RESEARCH.md`](WEBVIEW_OVERLAY_RESEARCH.md) for the composition, focus, input, and platform details. diff --git a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md index c5a2c2e9f1..2841e31530 100644 --- a/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md +++ b/crates/webview/WEBVIEW_OVERLAY_RESEARCH.md @@ -2,7 +2,7 @@ > Research date: 2026-07-30 > Baseline: `gpui-wry` uses `lb-wry 0.53.3`; GPUI is based on Zed commit -> `huacnlee/zed:gpui-webview-overlay` at `fbe67f26a3`. This document records the +> `huacnlee/zed:gpui-webview-overlay` at `ad82de04a2`. This document records the > native composition research, the implemented macOS layered-scene spike, and > the Windows architecture. From b8a693f11f0e872ba4f1ee5d337b42def93b0fae Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 31 Jul 2026 08:50:00 +0800 Subject: [PATCH 11/14] fix(webview): support Windows composition input and overlays --- Cargo.lock | 26 +--- Cargo.toml | 8 + crates/webview/Cargo.toml | 5 + crates/webview/src/lib.rs | 288 +++++++++++++++++++++++++++++++++-- examples/webview/src/main.rs | 75 ++++++++- 5 files changed, 356 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f59d6ec83..c3c751a71b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1197,7 +1197,6 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1752,6 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "proc-macro2", "quote", @@ -2900,7 +2898,6 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "anyhow", @@ -3146,13 +3143,14 @@ dependencies = [ "lb-wry", "objc2 0.6.4", "objc2-app-kit 0.3.2", + "webview2-com", + "windows 0.61.3", "windows-core 0.61.2", ] [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_unix", @@ -3204,7 +3202,6 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_macos", @@ -3253,7 +3250,6 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3264,7 +3260,6 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "console_error_panic_hook", "gpui", @@ -3277,7 +3272,6 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "schemars", "serde", @@ -3287,7 +3281,6 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "log", @@ -3297,7 +3290,6 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3320,7 +3312,6 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bytemuck", @@ -3350,7 +3341,6 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "accesskit", "accesskit_windows", @@ -3666,7 +3656,6 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "async-compression", @@ -3686,7 +3675,6 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "rustls", "rustls-platform-verifier", @@ -4720,7 +4708,6 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bindgen", @@ -5726,7 +5713,6 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "collections", "serde", @@ -6724,7 +6710,6 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "derive_refineable", ] @@ -6776,7 +6761,6 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "bytes", @@ -7213,7 +7197,6 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "async-task", "backtrace", @@ -7834,7 +7817,6 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "heapless", "log", @@ -9315,7 +9297,6 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "perf", "quote", @@ -11314,7 +11295,6 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "anyhow", "chrono", @@ -11331,7 +11311,6 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" dependencies = [ "tracing", "tracing-subscriber", @@ -11342,7 +11321,6 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ad82de04a27191380368af126f7db870e7063fa5" [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index 19f2dddce1..63484bd4c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,3 +129,11 @@ ignored = ["log", "anyhow", "serde"] [patch.crates-io] # Use stacker's psm version which may have better WASM support psm = { git = "https://github.com/rust-lang/stacker", branch = "master" } + +[patch."https://github.com/huacnlee/zed"] +gpui = { path = "../zed/crates/gpui" } +gpui_macros = { path = "../zed/crates/gpui_macros" } +gpui_platform = { path = "../zed/crates/gpui_platform" } +gpui_web = { path = "../zed/crates/gpui_web" } +gpui_windows = { path = "../zed/crates/gpui_windows" } +reqwest_client = { path = "../zed/crates/reqwest_client" } diff --git a/crates/webview/Cargo.toml b/crates/webview/Cargo.toml index b18a67f206..b8e350e5c1 100644 --- a/crates/webview/Cargo.toml +++ b/crates/webview/Cargo.toml @@ -28,4 +28,9 @@ objc2 = "0.6" objc2-app-kit = { version = "0.3", features = ["block2", "NSEvent", "NSView", "NSWindow"] } [target.'cfg(target_os = "windows")'.dependencies] +webview2-com = "0.38" windows-core = "0.61" + +[target.'cfg(target_os = "windows")'.dependencies.windows] +version = "0.61" +features = ["Win32_Foundation"] diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index 37411ef6f7..c9b12fd293 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -2,6 +2,9 @@ use std::{ops::Deref, rc::Rc}; #[cfg(target_os = "macos")] use block2::RcBlock; +#[cfg(target_os = "windows")] +use std::cell::Cell; +#[cfg(target_os = "windows")] use wry::{ Rect, dpi::{self, LogicalSize}, @@ -11,11 +14,17 @@ use wry::{ use objc2::{rc::Retained, runtime::AnyObject}; #[cfg(target_os = "macos")] use objc2_app_kit::{NSEvent, NSEventMask}; +#[cfg(target_os = "windows")] +use webview2_com::Microsoft::Web::WebView2::Win32::*; +#[cfg(target_os = "windows")] +use windows::Win32::Foundation::POINT; use gpui::{ - App, Bounds, ContentMask, DismissEvent, Element, ElementId, Entity, EventEmitter, FocusHandle, - Focusable, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId, MouseDownEvent, - ParentElement as _, Pixels, Render, Size, Style, Styled as _, Window, canvas, div, + App, Bounds, ContentMask, DismissEvent, DispatchPhase, Element, ElementId, Entity, + EventEmitter, FocusHandle, Focusable, GlobalElementId, Hitbox, InteractiveElement, IntoElement, + LayoutId, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, + ParentElement as _, Pixels, Render, ScrollDelta, ScrollWheelEvent, Size, Style, Styled as _, + Window, canvas, div, }; /// A webview based on wry WebView. @@ -130,7 +139,12 @@ impl WebView { /// Hide the webview. pub fn hide(&mut self) { - _ = self.webview.focus_parent(); + #[cfg(target_os = "windows")] + focus_parent(&self.webview); + #[cfg(not(target_os = "windows"))] + { + _ = self.webview.focus_parent(); + } _ = self.webview.set_visible(false); #[cfg(target_os = "windows")] if let Some(native_surface) = &self.native_surface { @@ -355,18 +369,260 @@ impl Element for WebViewElement { ) { let bounds = hitbox.clone().map(|h| h.bounds).unwrap_or(bounds); window.with_content_mask(Some(ContentMask { bounds }), |window| { - let webview = self.view.clone(); - window.on_mouse_event(move |event: &MouseDownEvent, _, window, _| { - if bounds.contains(&event.position) { - // Native WebView focus is outside GPUI's focus tree. Clear - // GPUI focus so text inputs stop showing a stale caret. - window.blur(); - } else { - // Return native focus to the GPUI parent when clicking - // elsewhere in the GPUI window. - let _ = webview.focus_parent(); - } - }); + #[cfg(target_os = "windows")] + { + let webview = self.view.clone(); + let was_hovered = Rc::new(Cell::new(false)); + window.on_mouse_event(move |event: &MouseMoveEvent, phase, window, _| { + if phase != DispatchPhase::Bubble { + return; + } + if bounds.contains(&event.position) { + was_hovered.set(true); + send_mouse_input(&webview, MouseInput::Move(event), bounds, window); + } else if was_hovered.replace(false) { + send_mouse_leave(&webview); + } + }); + + let webview = self.view.clone(); + let down_hitbox = hitbox.clone(); + window.on_mouse_event(move |event: &MouseDownEvent, phase, window, _| { + // GPUI has updated its hit test before dispatching the + // event. Use it here rather than only checking bounds so + // an overlay control above the WebView remains the real + // target. + let hovered = down_hitbox + .as_ref() + .is_some_and(|hitbox| hitbox.is_hovered(window)); + if phase == DispatchPhase::Capture { + if hovered { + // Move native focus before any bubble listener can + // stop propagation. Composition WebView keyboard + // input is delivered through the controller's + // focused native window, not through GPUI's input + // handler. + window.blur(); + let _ = webview.focus(); + } else { + // Overlay controls may stop propagation during + // bubble, so hand native focus back during capture. + focus_parent(&webview); + } + return; + } + if phase != DispatchPhase::Bubble || !hovered { + return; + } + + { + if let Some(hitbox) = down_hitbox.as_ref() { + window.capture_pointer(hitbox.id); + } + send_mouse_input(&webview, MouseInput::Down(event), bounds, window); + } + }); + + let webview = self.view.clone(); + let up_hitbox = hitbox.clone(); + window.on_mouse_event(move |event: &MouseUpEvent, phase, window, _| { + if phase != DispatchPhase::Bubble { + return; + } + if up_hitbox + .as_ref() + .is_some_and(|hitbox| hitbox.is_hovered(window)) + { + send_mouse_input(&webview, MouseInput::Up(event), bounds, window); + } + }); + + let webview = self.view.clone(); + let wheel_hitbox = hitbox.clone(); + window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, _| { + if phase != DispatchPhase::Bubble { + return; + } + if wheel_hitbox + .as_ref() + .is_some_and(|hitbox| hitbox.should_handle_scroll(window)) + { + send_mouse_input(&webview, MouseInput::Wheel(event), bounds, window); + } + }); + + let webview = self.view.clone(); + window.on_mouse_event(move |_: &MouseExitEvent, phase, _, _| { + if phase != DispatchPhase::Bubble { + return; + } + send_mouse_leave(&webview); + }); + } + + #[cfg(not(target_os = "windows"))] + { + let webview = self.view.clone(); + window.on_mouse_event(move |event: &MouseDownEvent, phase, window, _| { + if phase != DispatchPhase::Bubble { + return; + } + if bounds.contains(&event.position) { + // Native WebView focus is outside GPUI's focus tree. Clear + // GPUI focus so text inputs stop showing a stale caret. + window.blur(); + } else { + // Return native focus to the GPUI parent when clicking + // elsewhere in the GPUI window. + let _ = webview.focus_parent(); + } + }); + } }); } } + +#[cfg(target_os = "windows")] +enum MouseInput<'a> { + Move(&'a MouseMoveEvent), + Down(&'a MouseDownEvent), + Up(&'a MouseUpEvent), + Wheel(&'a ScrollWheelEvent), +} + +#[cfg(target_os = "windows")] +fn composition_controller(webview: &wry::WebView) -> Option { + use wry::WebViewExtWindows as _; + webview.composition_controller() +} + +#[cfg(target_os = "windows")] +fn focus_parent(webview: &wry::WebView) { + let _ = webview.focus_parent(); +} + +#[cfg(target_os = "windows")] +fn send_mouse_leave(webview: &wry::WebView) { + if let Some(controller) = composition_controller(webview) { + let _ = unsafe { + controller.SendMouseInput( + COREWEBVIEW2_MOUSE_EVENT_KIND_LEAVE, + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_NONE, + 0, + POINT { x: 0, y: 0 }, + ) + }; + } +} + +#[cfg(target_os = "windows")] +fn send_mouse_input( + webview: &wry::WebView, + input: MouseInput<'_>, + bounds: Bounds, + window: &Window, +) { + let Some(controller) = composition_controller(webview) else { + return; + }; + + let (position, kind, virtual_keys, mouse_data) = match input { + MouseInput::Move(event) => ( + event.position, + COREWEBVIEW2_MOUSE_EVENT_KIND_MOVE, + virtual_keys(event.modifiers, event.pressed_button), + 0, + ), + MouseInput::Down(event) => ( + event.position, + button_kind(event.button, true, event.click_count), + virtual_keys(event.modifiers, Some(event.button)), + 0, + ), + MouseInput::Up(event) => ( + event.position, + button_kind(event.button, false, event.click_count), + virtual_keys(event.modifiers, None), + 0, + ), + MouseInput::Wheel(event) => { + let (kind, delta) = match event.delta { + ScrollDelta::Pixels(delta) => { + if delta.x.as_f32() != 0. { + ( + COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, + delta.x.as_f32() as i32, + ) + } else { + (COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL, delta.y.as_f32() as i32) + } + } + ScrollDelta::Lines(delta) => { + if delta.x != 0. { + ( + COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, + (delta.x * 120.) as i32, + ) + } else { + (COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL, (delta.y * 120.) as i32) + } + } + }; + ( + event.position, + kind, + virtual_keys(event.modifiers, None), + delta, + ) + } + }; + + let scale_factor = window.scale_factor(); + let point = POINT { + x: ((position.x - bounds.origin.x).as_f32() * scale_factor) as i32, + y: ((position.y - bounds.origin.y).as_f32() * scale_factor) as i32, + }; + let _ = unsafe { controller.SendMouseInput(kind, virtual_keys, mouse_data as u32, point) }; +} + +#[cfg(target_os = "windows")] +fn virtual_keys( + modifiers: gpui::Modifiers, + pressed_button: Option, +) -> COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS { + let mut keys = COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_NONE; + if modifiers.control { + keys = keys | COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_CONTROL; + } + if modifiers.shift { + keys = keys | COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_SHIFT; + } + keys | match pressed_button { + Some(MouseButton::Left) => COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_LEFT_BUTTON, + Some(MouseButton::Right) => COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_RIGHT_BUTTON, + Some(MouseButton::Middle) => COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_MIDDLE_BUTTON, + _ => COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_NONE, + } +} + +#[cfg(target_os = "windows")] +fn button_kind( + button: MouseButton, + down: bool, + click_count: usize, +) -> COREWEBVIEW2_MOUSE_EVENT_KIND { + match (button, down, click_count > 1) { + (MouseButton::Left, true, true) => COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOUBLE_CLICK, + (MouseButton::Left, true, false) => COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOWN, + (MouseButton::Left, false, _) => COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_UP, + (MouseButton::Right, true, true) => COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOUBLE_CLICK, + (MouseButton::Right, true, false) => COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOWN, + (MouseButton::Right, false, _) => COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_UP, + (MouseButton::Middle, true, true) => { + COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOUBLE_CLICK + } + (MouseButton::Middle, true, false) => COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOWN, + (MouseButton::Middle, false, _) => COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_UP, + _ => COREWEBVIEW2_MOUSE_EVENT_KIND_MOVE, + } +} diff --git a/examples/webview/src/main.rs b/examples/webview/src/main.rs index e08dba2135..3602cc143b 100644 --- a/examples/webview/src/main.rs +++ b/examples/webview/src/main.rs @@ -10,6 +10,74 @@ use gpui_component::{ }; use gpui_wry::WebView; +const TEST_HTML: &str = r#" + + +Local WebView input test + +
+

Local WebView input test

+

Click each field and type: abc XYZ 123

+ + + + +
Focus: none
+

Keyboard events

+
Click the page, then press keys...
+
+ +"#; + pub struct Example { focus_handle: FocusHandle, webview: Entity, @@ -19,7 +87,7 @@ pub struct Example { impl Example { pub fn new(window: &mut Window, cx: &mut App) -> Entity { let webview = cx.new(|cx| { - let builder = wry::WebViewBuilder::new(); + let builder = wry::WebViewBuilder::new().with_html(TEST_HTML); #[cfg(any(debug_assertions, feature = "inspector"))] let builder = builder.with_devtools(true); @@ -58,11 +126,6 @@ impl Example { InputState::new(window, cx).default_value("https://longbridge.github.io/gpui-component") }); - let url = address_input.read(cx).value().clone(); - webview.update(cx, |view, _| { - view.load_url(&url); - }); - cx.new(|cx| { let this = Self { focus_handle: cx.focus_handle(), From 5f6e81a0a724673ae7435a4dc759457ee2d7ca70 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 31 Jul 2026 09:04:28 +0800 Subject: [PATCH 12/14] build: use pushed zed gpui dependency --- Cargo.lock | 73 ++++++++++++++++++++++++++++++++---------------------- Cargo.toml | 8 ------ 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3c751a71b..3443a1167b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -846,7 +846,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.117", @@ -1197,6 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "gpui_util", "indexmap", @@ -1752,6 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "proc-macro2", "quote", @@ -2872,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.58.0", + "windows 0.62.2", ] [[package]] @@ -2898,6 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "accesskit", "anyhow", @@ -3151,6 +3154,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "accesskit", "accesskit_unix", @@ -3202,6 +3206,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "accesskit", "accesskit_macos", @@ -3250,6 +3255,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3260,6 +3266,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "console_error_panic_hook", "gpui", @@ -3272,6 +3279,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "schemars", "serde", @@ -3281,6 +3289,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "log", @@ -3290,6 +3299,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3312,6 +3322,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "bytemuck", @@ -3341,6 +3352,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "accesskit", "accesskit_windows", @@ -3656,6 +3668,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "async-compression", @@ -3675,6 +3688,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3755,7 +3769,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.62.2", ] [[package]] @@ -4708,6 +4722,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "bindgen", @@ -5132,7 +5147,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.117", @@ -5557,9 +5572,9 @@ dependencies = [ [[package]] name = "open" -version = "5.3.4" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3bab717c29a857abf75fcef718d441ec7cb2725f937343c734740a985d37fd" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ "is-wsl", "libc", @@ -5580,9 +5595,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "5.3.0" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" dependencies = [ "num-traits", ] @@ -5713,6 +5728,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "collections", "serde", @@ -5984,9 +6000,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plain" @@ -6154,11 +6170,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -6710,6 +6726,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "derive_refineable", ] @@ -6761,6 +6778,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "bytes", @@ -7197,6 +7215,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "async-task", "backtrace", @@ -7817,6 +7836,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "heapless", "log", @@ -8441,15 +8461,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_edit" version = "0.19.15" @@ -8488,14 +8499,14 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime 1.1.1+spec-1.1.0", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", - "winnow 1.0.2", + "winnow 0.7.15", ] [[package]] @@ -9297,6 +9308,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "perf", "quote", @@ -11041,7 +11053,7 @@ version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.117", @@ -11295,6 +11307,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "anyhow", "chrono", @@ -11311,6 +11324,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" dependencies = [ "tracing", "tracing-subscriber", @@ -11321,6 +11335,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" [[package]] name = "zune-core" @@ -11382,7 +11397,7 @@ version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.117", diff --git a/Cargo.toml b/Cargo.toml index 63484bd4c2..19f2dddce1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,11 +129,3 @@ ignored = ["log", "anyhow", "serde"] [patch.crates-io] # Use stacker's psm version which may have better WASM support psm = { git = "https://github.com/rust-lang/stacker", branch = "master" } - -[patch."https://github.com/huacnlee/zed"] -gpui = { path = "../zed/crates/gpui" } -gpui_macros = { path = "../zed/crates/gpui_macros" } -gpui_platform = { path = "../zed/crates/gpui_platform" } -gpui_web = { path = "../zed/crates/gpui_web" } -gpui_windows = { path = "../zed/crates/gpui_windows" } -reqwest_client = { path = "../zed/crates/reqwest_client" } From 44a6761c8df082a380fe0c24177b29a120d1c4d1 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 31 Jul 2026 09:07:28 +0800 Subject: [PATCH 13/14] Update dep to fix keypress in webview on Windows. --- Cargo.lock | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3443a1167b..e33b2b6bc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.11.0", "log", "prettyplease", "proc-macro2", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "proc-macro2", "quote", @@ -2874,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.62.2", + "windows 0.58.0", ] [[package]] @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "accesskit", "anyhow", @@ -3154,7 +3154,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "accesskit", "accesskit_unix", @@ -3206,7 +3206,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "accesskit", "accesskit_macos", @@ -3255,7 +3255,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3266,7 +3266,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "console_error_panic_hook", "gpui", @@ -3279,7 +3279,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "schemars", "serde", @@ -3289,7 +3289,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "log", @@ -3299,7 +3299,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3322,7 +3322,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "bytemuck", @@ -3352,7 +3352,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "accesskit", "accesskit_windows", @@ -3668,7 +3668,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "async-compression", @@ -3688,7 +3688,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3769,7 +3769,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.58.0", ] [[package]] @@ -4722,7 +4722,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "bindgen", @@ -5728,7 +5728,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "collections", "serde", @@ -6726,7 +6726,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "derive_refineable", ] @@ -6778,7 +6778,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "bytes", @@ -7215,7 +7215,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "async-task", "backtrace", @@ -7836,7 +7836,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "heapless", "log", @@ -9308,7 +9308,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "perf", "quote", @@ -11307,7 +11307,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "anyhow", "chrono", @@ -11324,7 +11324,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" dependencies = [ "tracing", "tracing-subscriber", @@ -11335,7 +11335,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#2aca049118adb1a93d148d6db413566eb72ddb08" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" [[package]] name = "zune-core" From 4549adcdc4b3b5746533fdb5e3b88a48fd12010d Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 31 Jul 2026 11:18:38 +0800 Subject: [PATCH 14/14] Update gpui --- Cargo.lock | 54 +++++++++++++++++++-------------------- crates/webview/src/lib.rs | 10 +++++--- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33b2b6bc0..97591af46e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ dependencies = [ "bitflags 2.11.1", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "gpui_util", "indexmap", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "proc-macro2", "quote", @@ -2874,7 +2874,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.58.0", + "windows 0.62.2", ] [[package]] @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "accesskit", "anyhow", @@ -3154,7 +3154,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "accesskit", "accesskit_unix", @@ -3206,7 +3206,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "accesskit", "accesskit_macos", @@ -3255,7 +3255,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3266,7 +3266,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "console_error_panic_hook", "gpui", @@ -3279,7 +3279,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "schemars", "serde", @@ -3289,7 +3289,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "log", @@ -3299,7 +3299,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3322,7 +3322,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "bytemuck", @@ -3352,7 +3352,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "accesskit", "accesskit_windows", @@ -3668,7 +3668,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "async-compression", @@ -3688,7 +3688,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3769,7 +3769,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.62.2", ] [[package]] @@ -4722,7 +4722,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "bindgen", @@ -5728,7 +5728,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "collections", "serde", @@ -6726,7 +6726,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "derive_refineable", ] @@ -6778,7 +6778,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "bytes", @@ -7215,7 +7215,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "async-task", "backtrace", @@ -7836,7 +7836,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "heapless", "log", @@ -9308,7 +9308,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "perf", "quote", @@ -11307,7 +11307,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "anyhow", "chrono", @@ -11324,7 +11324,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" dependencies = [ "tracing", "tracing-subscriber", @@ -11335,7 +11335,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#ce3417edec9b0dfb18fdfa66a47bf6a0ff223c96" +source = "git+https://github.com/huacnlee/zed?branch=gpui-webview-overlay#20a699acac7b5bceea8e8fe6ba257a61ad47fb09" [[package]] name = "zune-core" diff --git a/crates/webview/src/lib.rs b/crates/webview/src/lib.rs index c9b12fd293..4183107f62 100644 --- a/crates/webview/src/lib.rs +++ b/crates/webview/src/lib.rs @@ -4,7 +4,6 @@ use std::{ops::Deref, rc::Rc}; use block2::RcBlock; #[cfg(target_os = "windows")] use std::cell::Cell; -#[cfg(target_os = "windows")] use wry::{ Rect, dpi::{self, LogicalSize}, @@ -22,9 +21,12 @@ use windows::Win32::Foundation::POINT; use gpui::{ App, Bounds, ContentMask, DismissEvent, DispatchPhase, Element, ElementId, Entity, EventEmitter, FocusHandle, Focusable, GlobalElementId, Hitbox, InteractiveElement, IntoElement, - LayoutId, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, - ParentElement as _, Pixels, Render, ScrollDelta, ScrollWheelEvent, Size, Style, Styled as _, - Window, canvas, div, + LayoutId, MouseDownEvent, ParentElement as _, Pixels, Render, Size, Style, Styled as _, Window, + canvas, div, +}; +#[cfg(target_os = "windows")] +use gpui::{ + MouseButton, MouseExitEvent, MouseMoveEvent, MouseUpEvent, ScrollDelta, ScrollWheelEvent, }; /// A webview based on wry WebView.