diff --git a/apps/desktop/src/config_center/config_center.cpp b/apps/desktop/src/config_center/config_center.cpp index 6860fd3f..67e135bf 100644 --- a/apps/desktop/src/config_center/config_center.cpp +++ b/apps/desktop/src/config_center/config_center.cpp @@ -319,10 +319,7 @@ int ConfigCenter::SetTurnMode(TURN_MODE mode) { return 0; } -int ConfigCenter::SetTurn(bool enable_turn, bool force_relay) { - if (!enable_turn) { - return SetTurnMode(TURN_MODE::DISABLED); - } +int ConfigCenter::SetForceRelay(bool force_relay) { if (!force_relay) { return SetTurnMode(TURN_MODE::AUTO_UDP_TCP); } @@ -479,10 +476,6 @@ ConfigCenter::TURN_MODE ConfigCenter::GetTurnMode() const { return turn_mode_; } -bool ConfigCenter::IsEnableTurn() const { - return turn_mode_ != TURN_MODE::DISABLED; -} - bool ConfigCenter::IsForceRelay() const { return turn_mode_ == TURN_MODE::FORCE_UDP || turn_mode_ == TURN_MODE::FORCE_TCP; } diff --git a/apps/desktop/src/config_center/config_center.h b/apps/desktop/src/config_center/config_center.h index 68915f67..e2d74cde 100644 --- a/apps/desktop/src/config_center/config_center.h +++ b/apps/desktop/src/config_center/config_center.h @@ -41,7 +41,7 @@ class ConfigCenter { int SetScreenCaptureMethod(ScreenCaptureMethod method); int SetVideoEncodeFormat(VIDEO_ENCODE_FORMAT video_encode_format); int SetTurnMode(TURN_MODE turn_mode); - int SetTurn(bool enable_turn, bool force_relay); + int SetForceRelay(bool force_relay); int SetServerHost(const std::string& signal_server_host); int SetServerPort(int signal_server_port); int SetServerEndpoint(const std::string& address, int port); @@ -63,7 +63,6 @@ class ConfigCenter { ScreenCaptureMethod GetScreenCaptureMethod() const; VIDEO_ENCODE_FORMAT GetVideoEncodeFormat() const; TURN_MODE GetTurnMode() const; - bool IsEnableTurn() const; bool IsForceRelay() const; bool IsEnableSrtp() const; std::string GetSignalServerHost() const; diff --git a/apps/desktop/src/gui/application/gui_application.cpp b/apps/desktop/src/gui/application/gui_application.cpp index fcc97f6b..8a433b95 100644 --- a/apps/desktop/src/gui/application/gui_application.cpp +++ b/apps/desktop/src/gui/application/gui_application.cpp @@ -1488,7 +1488,6 @@ void GuiApplication::ResetSettingsUi(bool gallery_window) { auto& main = ui_->Window(gallery_window); main->set_language_index(language_button_value_); main->set_codec_index(video_encode_format_button_value_); - main->set_turn_enabled(enable_turn_); main->set_ip_direct_enabled_draft(config_center_->IsIpDirectEnabled()); main->set_settings_save_error(""); main->set_force_relay_enabled(config_center_->IsForceRelay()); @@ -4559,7 +4558,6 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { language_button_value_ = localization::detail::ClampLanguageIndex(main->get_language_index()); video_encode_format_button_value_ = std::clamp(main->get_codec_index(), 0, 1); - enable_turn_ = main->get_turn_enabled(); enable_self_hosted_ = main->get_self_hosted_enabled(); #if !defined(__OHOS__) enable_autostart_ = main->get_autostart_enabled(); @@ -4575,7 +4573,7 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { config_center_->SetVideoEncodeFormat( static_cast( video_encode_format_button_value_)); - config_center_->SetTurn(enable_turn_, main->get_force_relay_enabled()); + config_center_->SetForceRelay(main->get_force_relay_enabled()); main->set_force_relay_enabled(config_center_->IsForceRelay()); #if !defined(__OHOS__) config_center_->SetAutostart(enable_autostart_); @@ -4641,7 +4639,6 @@ void GuiApplication::ApplySettingsFromConfig(bool reconnect) { localization_language_index_ = localization::detail::ClampLanguageIndex(language_button_value_); localization_language_ = config_center_->GetLanguage(); video_encode_format_button_value_ = static_cast(config_center_->GetVideoEncodeFormat()); - enable_turn_ = config_center_->IsEnableTurn(); enable_self_hosted_ = config_center_->IsSelfHosted(); enable_autostart_ = config_center_->IsEnableAutostart(); enable_daemon_ = config_center_->IsEnableDaemon(); @@ -4655,7 +4652,6 @@ void GuiApplication::ApplySettingsFromConfig(bool reconnect) { std::snprintf(signal_server_port_self_, sizeof(signal_server_port_self_), "%s", port_text.c_str()); language_button_value_last_ = language_button_value_; video_encode_format_button_value_last_ = video_encode_format_button_value_; - enable_turn_last_ = enable_turn_; enable_self_hosted_last_ = enable_self_hosted_; enable_autostart_last_ = enable_autostart_; enable_daemon_last_ = enable_daemon_; diff --git a/apps/desktop/src/gui/assets/localization/localization_data.h b/apps/desktop/src/gui/assets/localization/localization_data.h index 7ba4ec0e..6951aaf9 100644 --- a/apps/desktop/src/gui/assets/localization/localization_data.h +++ b/apps/desktop/src/gui/assets/localization/localization_data.h @@ -237,8 +237,6 @@ struct TranslationRow { "Video Encode Format:", u8"Формат кодека видео:") \ X(av1, u8"AV1", "AV1", "AV1") \ X(h264, u8"H.264", "H.264", "H.264") \ - X(enable_turn, u8"启用中继服务:", \ - "Enable TURN Service:", u8"Включить TURN-сервис:") \ X(force_relay, u8"强制中继连接:", "Force Relay:", u8"Только через реле:") \ X(self_hosted_server_config, u8"自托管配置", "Self-Hosted Config", \ u8"Конфигурация self-hosted") \ diff --git a/apps/desktop/src/gui/features/settings/settings_manager.cpp b/apps/desktop/src/gui/features/settings/settings_manager.cpp index 37b5b6f0..a569d6a0 100644 --- a/apps/desktop/src/gui/features/settings/settings_manager.cpp +++ b/apps/desktop/src/gui/features/settings/settings_manager.cpp @@ -465,7 +465,6 @@ int SettingsManager::Load() { static_cast(owner_.config_center_->GetLanguage())); owner_.video_encode_format_button_value_ = static_cast(owner_.config_center_->GetVideoEncodeFormat()); - owner_.enable_turn_ = owner_.config_center_->IsEnableTurn(); owner_.enable_self_hosted_ = owner_.config_center_->IsSelfHosted(); owner_.enable_autostart_ = owner_.config_center_->IsEnableAutostart(); owner_.enable_daemon_ = owner_.config_center_->IsEnableDaemon(); @@ -484,7 +483,6 @@ int SettingsManager::Load() { owner_.language_button_value_last_ = owner_.language_button_value_; owner_.video_encode_format_button_value_last_ = owner_.video_encode_format_button_value_; - owner_.enable_turn_last_ = owner_.enable_turn_; owner_.enable_self_hosted_last_ = owner_.enable_self_hosted_; owner_.enable_autostart_last_ = owner_.enable_autostart_; diff --git a/apps/desktop/src/gui/runtime/runtime_state.h b/apps/desktop/src/gui/runtime/runtime_state.h index 80e41f0b..5abc1da3 100644 --- a/apps/desktop/src/gui/runtime/runtime_state.h +++ b/apps/desktop/src/gui/runtime/runtime_state.h @@ -150,13 +150,11 @@ struct UserSettingsState { char connection_login_identity_[17] = ""; int language_button_value_ = 0; int video_encode_format_button_value_ = 0; - bool enable_turn_ = true; char signal_server_ip_[256] = "api.crossdesk.cn"; char signal_server_port_[6] = "9099"; bool enable_self_hosted_ = false; int language_button_value_last_ = 0; int video_encode_format_button_value_last_ = 0; - bool enable_turn_last_ = true; bool enable_self_hosted_last_ = false; bool enable_autostart_ = false; bool enable_autostart_last_ = false; diff --git a/apps/desktop/src/gui/ui/main_window.slint b/apps/desktop/src/gui/ui/main_window.slint index 65dc844d..c93f6d07 100644 --- a/apps/desktop/src/gui/ui/main_window.slint +++ b/apps/desktop/src/gui/ui/main_window.slint @@ -72,7 +72,6 @@ export global UiStrings { in-out property capture-method: "Capture method"; in-out property capture-method-auto: "Auto"; in-out property codec: "Video codec"; - in-out property turn-relay: "TURN relay"; in-out property force-relay: "Force relay"; in-out property self-hosted: "Self-hosted server"; in-out property autostart: "Start with system"; @@ -625,13 +624,9 @@ export component MainWindow inherits Window { in property capture-method-visible: false; in-out property capture-method-index: 0; in-out property codec-index: 0; - in-out property turn-enabled: true; in-out property ip-direct-enabled-draft: true; in property settings-save-error; in-out property force-relay-enabled: false; - changed turn-enabled => { - if !root.turn-enabled { root.force-relay-enabled = false; } - } in-out property self-hosted-enabled: false; in-out property autostart-enabled: false; in property autostart-system-managed: false; @@ -2672,13 +2667,12 @@ export component MainWindow inherits Window { } } SettingsGroup { - title: GalleryStrings.tr("网络连接", "Network", "Сеть"); rows: 4; + title: GalleryStrings.tr("网络连接", "Network", "Сеть"); rows: 3; SettingsToggleRow { label: GalleryStrings.tr("启用 IP 直连", "Enable direct IP", "Прямое IP-подключение"); checked <=> root.ip-direct-enabled-draft; } - SettingsToggleRow { label: UiStrings.turn-relay; checked <=> root.turn-enabled; enabled: !root.settings-session-active; } - SettingsToggleRow { label: UiStrings.force-relay; checked <=> root.force-relay-enabled; enabled: root.turn-enabled && !root.settings-session-active; } + SettingsToggleRow { label: UiStrings.force-relay; checked <=> root.force-relay-enabled; enabled: !root.settings-session-active; } SettingsToggleRow { checked <=> root.self-hosted-enabled; enabled: !root.settings-session-active; divider: false; SettingsButton { x: 0px; y: 2px; width: parent.width - 60px; height: 32px; quiet: true; align-left: true; text: UiStrings.self-hosted; enabled: !root.settings-session-active; clicked => { root.self-host-settings-open = true; } } diff --git a/apps/desktop/src/gui/ui/ui_localization.h b/apps/desktop/src/gui/ui/ui_localization.h index b9bec49e..e8bcd3e9 100644 --- a/apps/desktop/src/gui/ui/ui_localization.h +++ b/apps/desktop/src/gui/ui/ui_localization.h @@ -93,7 +93,6 @@ inline int ApplyMainWindowStrings( strings.set_capture_method_auto( Text(localization::screen_capture_method_auto[language])); strings.set_codec(Text(localization::video_encode_format[language])); - strings.set_turn_relay(Text(localization::enable_turn[language])); strings.set_force_relay(Text(localization::force_relay[language])); strings.set_self_hosted( Text(localization::self_hosted_server_config[language])); diff --git a/docs/FAQ.md b/docs/FAQ.md index ba731e60..941dad7f 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -12,7 +12,7 @@ ## 对等连接失败 -在 **☰ → 设置** 中勾选 **启用中继服务**,点击“确认”后重新连接。自托管用户还需检查 Coturn 是否正常运行,以及中继端口 TCP/UDP、媒体端口范围 UDP 是否放通。 +默认连接策略已允许 TURN 中继回退。可在 **☰ → 设置** 中开启 **强制中继连接**,保存后重新连接以排查直连问题。自托管用户还需检查 Coturn 是否正常运行,以及中继端口 TCP/UDP、媒体端口范围 UDP 是否放通。 公共服务的兼容性变更也会影响旧客户端;请核对 [Release 说明](https://github.com/kunkundi/crossdesk/releases),尽量让两端使用兼容的近期版本。 @@ -85,7 +85,7 @@ Windows 安装包和便携包内置了 Amyuni 的 `usbmmidd_v2` 虚拟显示器 | --- | --- | | Server disconnected / TLS error | Network access, signaling endpoint, certificate dates, hostname, and system trust. See [self-hosting](SELF_HOSTING_EN.md). | | Remote device offline | Keep the host running, connect both sides to the same signaling server, and copy its current ID again. | -| P2P connection failed | Enable TURN relay in Settings and reconnect. For self-hosting, check Coturn and relay/media firewall ports. Review [release compatibility notes](https://github.com/kunkundi/crossdesk/releases). | +| P2P connection failed | The default connection policy already allows TURN relay fallback. Enable Force Relay in Settings, save, and reconnect to troubleshoot direct connections. For self-hosting, check Coturn and relay/media firewall ports. Review [release compatibility notes](https://github.com/kunkundi/crossdesk/releases). | | Black screen / no input on macOS | Grant Screen Recording and Accessibility, then reopen the app. A changed app path or signature may require fresh permission grants. | | No capture on Linux Wayland | Check the Wayland build option, host PipeWire 0.3, and desktop portal permission. Compare with an X11 session. See [Linux build instructions](BUILD_EN.md#linux). | | Linux host has no monitor or graphical session | Start CrossDesk normally to automatically discover and select your existing desktop, preserving its Dock and apps; no display number is needed. A bare Xvfb shows only CrossDesk on a black background; use an existing session or install Xfce and specify `--headless-session startxfce4`. See [Linux headless operation](HEADLESS_EN.md). | diff --git a/docs/SELF_HOSTING.md b/docs/SELF_HOSTING.md index 0d0bb746..512c4cc5 100644 --- a/docs/SELF_HOSTING.md +++ b/docs/SELF_HOSTING.md @@ -95,7 +95,7 @@ sudo security add-trusted-cert -d -r trustRoot \ - **未连接服务器 / TLS 错误:** 先检查地址、信令端口、证书有效期、证书主机名及根证书信任。 - **已连服务器但设备离线:** 确认两端连接同一服务、被控端仍在运行,并重新复制当前 ID。 -- **P2P 连接失败:** 检查“启用中继服务”、Coturn 状态、TURN 端口和媒体端口范围,并核对客户端与服务端版本兼容性。 +- **P2P 连接失败:** 默认已允许中继回退;可开启“强制中继连接”排查直连问题。检查 Coturn 状态、TURN 端口和媒体端口范围,并核对客户端与服务端版本兼容性。 - **配置修改未生效:** 在配置目录重新执行 `sudo docker compose up -d`;单纯重启容器不会应用修改过的环境变量。 日志、备份和迁移操作请参考 [服务端维护说明](https://github.com/kunkundi/crossdesk-server)。 diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index b11a1542..22a5943d 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -149,8 +149,7 @@ sudo apt install "./crossdesk-virtual-desktop-xfce-linux-amd64-.deb" | 采集方式(Windows) | 自动 / DXGI / WGC / GDI;无显示器主机使用“自动”启用自动适配 | | 视频编码格式 | H.264 / AV1;H.264 自动优先使用硬件编解码,不可用或初始化失败时回退到软件;桌面端 AV1 使用软件编解码 | | 启用 IP 直连 | 默认开启;保存后即时启停 IP 直连。关闭会断开 IP 会话、停止监听并隐藏主窗口模式按钮,重启后保持 | -| 启用中继服务 | 允许借助 TURN 中继建立连接;P2P 连接失败时先检查此项 | -| 强制中继连接 | 启用中继服务后可勾选,让连接通过中继建立;关闭中继服务会同时关闭此项 | +| 强制中继连接 | 关闭时自动选择连接方式,允许 P2P 和 TURN 中继回退;开启时仅通过中继连接 | | 保存远程画面预览 | 默认开启,保存远程画面预览;关闭后缩略图区域显示被控端平台,并清除已有预览,保留连接记录和密码 | | 被连接时开启隐私屏 | 设置本机被远程连接时是否自动启用隐私屏;会话中可从控制端工具栏切换 | | 自托管配置 | 填写服务器地址和信令服务端口,并勾选启用 | diff --git a/docs/USER_GUIDE_EN.md b/docs/USER_GUIDE_EN.md index 34be4c8e..bf9f4fad 100644 --- a/docs/USER_GUIDE_EN.md +++ b/docs/USER_GUIDE_EN.md @@ -149,8 +149,7 @@ Open **☰ → Settings** in the top-right corner, choose **General / DeskHub**, | Capture Method (Windows) | Auto / DXGI / WGC / GDI; choose Auto for automatic headless adaptation | | Video Encode Format | H.264 / AV1; H.264 automatically prefers hardware codecs, with software fallback when unavailable or initialization fails; desktop AV1 uses software codecs | | Enable direct IP | Enabled by default; saving starts or stops direct IP immediately. Disabling disconnects IP sessions, stops listeners, and hides the mode button; the choice persists across restarts | -| Enable TURN Service | Allow relay-assisted connections; check this setting if P2P fails | -| Force Relay | Require relay connections when TURN is enabled; turning TURN off also disables this option | +| Force Relay | When off, automatically select a connection path with P2P and TURN relay fallback; when on, use relay connections only | | Save remote screen previews | On by default. When disabled, the thumbnail area shows the remote device’s platform and existing previews are cleared; connection records and passwords are preserved | | Privacy screen on connect | Automatically enable privacy when this computer is controlled remotely; the controller can toggle it from the session toolbar | | Self-Hosted Config | Set the server address and signaling port, then enable the checkbox | diff --git a/docs/images/README.md b/docs/images/README.md index e3899c94..33fb56f2 100644 --- a/docs/images/README.md +++ b/docs/images/README.md @@ -4,6 +4,7 @@ ## 来源 / Sources +- **2026-10-25** 删除“启用中继服务”开关后,从当前工作区组件重新生成 `desktop-settings-*` 和 `desktop-settings-network-*` 共 4 张中英文截图,展示可独立操作的“强制中继连接”。 - **2026-10-25** 从 `ae6f81e8` 的实际 Slint 组件重新生成 16 张中英文截图:更新主窗口、常规设置、桌面墙设置、自托管及关于共 10 张,新增 IP 直连主界面、记住密码弹窗和网络设置共 6 张。使用 Slint 1.17.1、macOS arm64 和 2× 软件渲染。 - 捕获程序在**工程外临时目录**中复用现有 [`slint_ui_smoke_test`](../../apps/desktop/tests/slint_ui_smoke_test.cpp) 的截图辅助函数,并注入演示界面状态;没有启动应用运行时、打开监听端口或建立远控会话。没有修改产品组件或工程内测试,临时源码、可执行程序与 PPM 均位于工程外。 - 主窗口展示 ID / IP 模式切换、桌面墙入口和各自的近期设备;IP 模式展示地址编辑、六位密码和默认端口 52888,网络设置展示“启用 IP 直连”及关闭说明。IP 近期设备的 `LAN` 标记表示记录类型,不代表在线探测结果。 @@ -13,7 +14,7 @@ - 缩略图沿用既有公开页面截图:`fixtures/source.png` 来自 [CrossDesk Xmake 源码页](https://github.com/kunkundi/crossdesk/blob/ios-support/xmake.lua),`fixtures/website.png` 来自 [CrossDesk 官网](https://www.crossdesk.cn/),两者采集于 2026-09-07。它们只用于展示预览效果,不代表这些页面正在对应设备上运行,页面中的版本信息也不代表最新发布。 - `web-client.png` 保留 **2026-09-25** 从 [Web 客户端](https://web.crossdesk.cn/) 采集的 1280 × 720 连接首页,页面版本为 `2026.09.24.2`,ID 与密码为空。本次未重新采集 Web 页面;桌面设备预览继续复用这张图片。 -On **2026-10-25**, 16 images were rendered from the actual Slint components at `ae6f81e8`: ten refreshed images (main window, General settings, DeskHub settings, self-hosting, and About) and six additions (Direct IP mode, its password dialog, and Network settings), in Chinese and English. The capture-only program reused the existing helper functions in an external temporary directory, using Slint 1.17.1 on macOS arm64 at 2× scale. No product components or repository tests were changed, and no listeners or remote sessions were opened. IDs, IPs, passwords, device records, connection states, and update results are illustrative; `LAN` labels indicate record type, not an online check. The checked Remember password box is a demonstration choice. The other six desktop screenshots remain from 2026-10-19, public-page fixtures from 2026-09-07, and the Web image from 2026-09-25. Native mobile screenshots are not included. +On **2026-10-25**, 16 images were rendered from the actual Slint components at `ae6f81e8`: ten refreshed images (main window, General settings, DeskHub settings, self-hosting, and About) and six additions (Direct IP mode, its password dialog, and Network settings), in Chinese and English. Later that day, the four General and Network settings images were refreshed from the working tree after removing Enable TURN Service, showing the independent Force Relay switch. The capture-only program reused the existing helper functions in an external temporary directory, using Slint 1.17.1 on macOS arm64 at 2× scale. Capture did not modify product components or repository tests, and no listeners or remote sessions were opened. IDs, IPs, passwords, device records, connection states, and update results are illustrative; `LAN` labels indicate record type, not an online check. The checked Remember password box is a demonstration choice. The other six desktop screenshots remain from 2026-10-19, public-page fixtures from 2026-09-07, and the Web image from 2026-09-25. Native mobile screenshots are not included. ## 文件 / Files @@ -112,7 +113,6 @@ int main() { !RegisterFontAwesome(server->window())) return 2; window->set_local_id("123 456 789"); window->set_local_password("Ab12Cd"); - window->set_turn_enabled(true); window->window().set_size(slint::LogicalSize({640.0f, 472.0f})); return RunCaptureMode(options, window, stream, server); } diff --git a/docs/images/desktop-settings-en.png b/docs/images/desktop-settings-en.png index 37b1be1c..887070a2 100644 Binary files a/docs/images/desktop-settings-en.png and b/docs/images/desktop-settings-en.png differ diff --git a/docs/images/desktop-settings-network-en.png b/docs/images/desktop-settings-network-en.png index b9695e0d..50eb518b 100644 Binary files a/docs/images/desktop-settings-network-en.png and b/docs/images/desktop-settings-network-en.png differ diff --git a/docs/images/desktop-settings-network-zh.png b/docs/images/desktop-settings-network-zh.png index 2e1a5b94..e9b277d8 100644 Binary files a/docs/images/desktop-settings-network-zh.png and b/docs/images/desktop-settings-network-zh.png differ diff --git a/docs/images/desktop-settings-zh.png b/docs/images/desktop-settings-zh.png index 99d7cb9b..e978dfbd 100644 Binary files a/docs/images/desktop-settings-zh.png and b/docs/images/desktop-settings-zh.png differ