From e7910c8e3866b01098c37c6eb961190ef5b6d937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B3=A1=E8=8A=99?= Date: Mon, 24 Aug 2026 00:14:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(rdp):=20=E7=8B=AC=E7=AB=8B=E5=85=A8?= =?UTF-8?q?=E5=B1=8F=E7=AA=97=E5=8F=A3=E9=BB=98=E8=AE=A4=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E5=91=88=E7=8E=B0=EF=BC=8C=E5=8F=8C=E5=87=BB=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E6=89=93=E5=BC=80=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/remote_desktop_view/src/view.rs | 10 +++++-- .../src/view/render_contract_tests.rs | 28 +++++++++++++++++++ main/src/home/home_strategy.rs | 22 ++++++--------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/crates/remote_desktop_view/src/view.rs b/crates/remote_desktop_view/src/view.rs index 5f938e97..fb10bea4 100644 --- a/crates/remote_desktop_view/src/view.rs +++ b/crates/remote_desktop_view/src/view.rs @@ -877,6 +877,12 @@ impl RemoteDesktopView { cx: &mut Context, ) -> Self { let manage_native_cursor = config.options.protocol == RemoteDesktopProtocol::Rdp; + // Standalone windows (tab_index: None, e.g. the fullscreen RDP popup) + // have no tab container to drive TabContent::on_activate, so they must + // start as the active presentation and request native focus directly. + // Otherwise the native overlay stays hidden and the window renders + // only the GPUI background. + let standalone_window = config.tab_index.is_none(); let presentation_initialization = if config.options.protocol == RemoteDesktopProtocol::Vnc { presentation::RemoteDesktopPresentationInitialization::Canvas { fallback_reason: None, @@ -1104,7 +1110,7 @@ impl RemoteDesktopView { _presentation_task: None, _presentation_pacing_task: None, presentation_initialization, - tab_active: false, + tab_active: standalone_window, #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] windows_native: None, #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] @@ -1126,7 +1132,7 @@ impl RemoteDesktopView { #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] windows_native_lifecycle_dirty: false, #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] - windows_native_focus_requested: false, + windows_native_focus_requested: standalone_window, #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] windows_native_close_requested: false, #[cfg(all(feature = "windows-native-rdp", target_os = "windows"))] diff --git a/crates/remote_desktop_view/src/view/render_contract_tests.rs b/crates/remote_desktop_view/src/view/render_contract_tests.rs index 1f2b5ce2..569ecabd 100644 --- a/crates/remote_desktop_view/src/view/render_contract_tests.rs +++ b/crates/remote_desktop_view/src/view/render_contract_tests.rs @@ -1443,6 +1443,34 @@ fn windows_native_tab_lifecycle_defers_focus_only_while_active() { } } +#[test] +fn standalone_window_starts_active_with_native_focus_requested() { + let view = include_str!("../view.rs").replace("\r\n", "\n"); + let new_body = function_body( + &view, + "pub fn new(", + "fn cancel_presentation_pacing", + ); + + let standalone = new_body + .find("let standalone_window = config.tab_index.is_none();") + .expect("standalone window detection"); + let tab_active = new_body + .find("tab_active: standalone_window,") + .expect("standalone windows start active"); + let focus_requested = new_body + .find("windows_native_focus_requested: standalone_window,") + .expect("standalone windows request native focus"); + assert!( + standalone < tab_active && tab_active < focus_requested, + "standalone detection must precede both activation intents" + ); + assert!( + !new_body[standalone..tab_active].contains("tab_active: false"), + "initialization must never hard-code the inactive tab state" + ); +} + #[test] fn local_pointer_move_makes_the_canvas_cursor_paintable_before_hiding_native_cursor() { let input = include_str!("input.rs"); diff --git a/main/src/home/home_strategy.rs b/main/src/home/home_strategy.rs index f04c5872..d2254435 100644 --- a/main/src/home/home_strategy.rs +++ b/main/src/home/home_strategy.rs @@ -271,13 +271,8 @@ impl ConnectionOpenStrategy for RemoteDesktopOpenStrategy { connection, protocol, } = *self; - if protocol == RemoteDesktopProtocol::Rdp && remote_desktop::windows_native_rdp_compiled() { - // Windows 原生 RDP 与 gpui-rdp-smoke 一致:在独立全屏窗口中 - // 承载原生 ActiveX child(覆盖整个客户区),避免在主窗口 tab - // 内嵌时被 DirectComposition visual 盖住而白屏。 - home.open_remote_desktop_fullscreen_window(&connection, window, cx); - return; - } + // 双击等常规打开一律走 tab;独立全屏窗口仅保留在连接的右键菜单里 + // (Connection.open_in_fullscreen_window)。 extension_runtime::remote_desktop_provider_install::open_remote_desktop_connection_with_provider_guard( home, connection, protocol, mode, window, cx, ); @@ -301,7 +296,7 @@ mod tests { use one_core::storage::{MongoDBParams, MongoDriverVariant, StoredConnection}; #[test] - fn native_rdp_opens_in_an_independent_window_like_gpui_rdp_smoke() { + fn remote_desktop_double_click_opens_in_a_tab() { let source = include_str!("home_strategy.rs").replace("\r\n", "\n"); let start = source .find("impl ConnectionOpenStrategy for RemoteDesktopOpenStrategy") @@ -312,13 +307,14 @@ mod tests { .expect("next strategy"); let strategy = &source[start..end]; - assert!(strategy.contains("protocol == RemoteDesktopProtocol::Rdp")); - assert!(strategy.contains("remote_desktop::windows_native_rdp_compiled()")); assert!( - strategy - .contains("home.open_remote_desktop_fullscreen_window(&connection, window, cx)") + strategy.contains("open_remote_desktop_connection_with_provider_guard("), + "double-click must open the remote desktop in a tab" + ); + assert!( + !strategy.contains("open_remote_desktop_fullscreen_window"), + "the fullscreen window must stay behind the context-menu action" ); - assert!(strategy.contains("open_remote_desktop_connection_with_provider_guard(")); } #[test]