diff --git a/apps/desktop/src/config_center/config_center.cpp b/apps/desktop/src/config_center/config_center.cpp index d39ce1e3..2041036f 100644 --- a/apps/desktop/src/config_center/config_center.cpp +++ b/apps/desktop/src/config_center/config_center.cpp @@ -58,6 +58,14 @@ int ConfigCenter::Load() { video_frame_rate_ = static_cast(ini_.GetLongValue( section_, "video_frame_rate", static_cast(video_frame_rate_))); + const long screen_capture_method_value = ini_.GetLongValue( + section_, "screen_capture_method", + static_cast(ScreenCaptureMethod::Auto)); + screen_capture_method_ = IsValidScreenCaptureMethod(screen_capture_method_value) + ? static_cast( + screen_capture_method_value) + : ScreenCaptureMethod::Auto; + const long video_adaptation_policy_value = ini_.GetLongValue( section_, "video_adaptation_policy", static_cast(video_adaptation_policy_)); @@ -147,6 +155,8 @@ int ConfigCenter::Save() { static_cast(video_quality_)); ini_.SetLongValue(section_, "video_frame_rate", static_cast(video_frame_rate_)); + ini_.SetLongValue(section_, "screen_capture_method", + static_cast(screen_capture_method_)); ini_.SetLongValue(section_, "video_adaptation_policy", static_cast(video_adaptation_policy_)); ini_.SetLongValue(section_, "video_encode_format", @@ -217,6 +227,20 @@ int ConfigCenter::SetVideoFrameRate(VIDEO_FRAME_RATE video_frame_rate) { return 0; } +int ConfigCenter::SetScreenCaptureMethod(ScreenCaptureMethod method) { + if (!IsValidScreenCaptureMethod(static_cast(method))) { + return -1; + } + ini_.SetLongValue(section_, "screen_capture_method", static_cast(method)); + if (ini_.SaveFile(config_path_.c_str()) < 0) { + ini_.SetLongValue(section_, "screen_capture_method", + static_cast(screen_capture_method_)); + return -1; + } + screen_capture_method_ = method; + return 0; +} + int ConfigCenter::SetVideoAdaptationPolicy( VIDEO_ADAPTATION_POLICY policy) { video_adaptation_policy_ = policy; @@ -413,6 +437,10 @@ ConfigCenter::VIDEO_FRAME_RATE ConfigCenter::GetVideoFrameRate() const { return video_frame_rate_; } +ScreenCaptureMethod ConfigCenter::GetScreenCaptureMethod() const { + return screen_capture_method_; +} + ConfigCenter::VIDEO_ADAPTATION_POLICY ConfigCenter::GetVideoAdaptationPolicy() const { return video_adaptation_policy_; diff --git a/apps/desktop/src/config_center/config_center.h b/apps/desktop/src/config_center/config_center.h index 5f8430e0..c7365d27 100644 --- a/apps/desktop/src/config_center/config_center.h +++ b/apps/desktop/src/config_center/config_center.h @@ -11,6 +11,7 @@ #include #include "SimpleIni.h" +#include "screen_capturer/screen_capture_method.h" namespace crossdesk { @@ -40,6 +41,7 @@ class ConfigCenter { int SetLanguage(LANGUAGE language); int SetVideoQuality(VIDEO_QUALITY video_quality); int SetVideoFrameRate(VIDEO_FRAME_RATE video_frame_rate); + int SetScreenCaptureMethod(ScreenCaptureMethod method); int SetVideoAdaptationPolicy(VIDEO_ADAPTATION_POLICY policy); int SetVideoEncodeFormat(VIDEO_ENCODE_FORMAT video_encode_format); int SetHardwareVideoCodec(bool hardware_video_codec); @@ -60,6 +62,7 @@ class ConfigCenter { LANGUAGE GetLanguage() const; VIDEO_QUALITY GetVideoQuality() const; VIDEO_FRAME_RATE GetVideoFrameRate() const; + ScreenCaptureMethod GetScreenCaptureMethod() const; VIDEO_ADAPTATION_POLICY GetVideoAdaptationPolicy() const; VIDEO_ENCODE_FORMAT GetVideoEncodeFormat() const; bool IsHardwareVideoCodec() const; @@ -88,6 +91,7 @@ class ConfigCenter { LANGUAGE language_ = LANGUAGE::CHINESE; VIDEO_QUALITY video_quality_ = VIDEO_QUALITY::HIGH; VIDEO_FRAME_RATE video_frame_rate_ = VIDEO_FRAME_RATE::FPS_60; + ScreenCaptureMethod screen_capture_method_ = ScreenCaptureMethod::Auto; VIDEO_ADAPTATION_POLICY video_adaptation_policy_ = VIDEO_ADAPTATION_POLICY::QUALITY_PRIORITY; VIDEO_ENCODE_FORMAT video_encode_format_ = VIDEO_ENCODE_FORMAT::H264; diff --git a/apps/desktop/src/gui/application/gui_application.cpp b/apps/desktop/src/gui/application/gui_application.cpp index 7dc64a78..4f7f8767 100644 --- a/apps/desktop/src/gui/application/gui_application.cpp +++ b/apps/desktop/src/gui/application/gui_application.cpp @@ -1231,6 +1231,9 @@ void GuiApplication::ResetSettingsUi() { ui_->main->set_autostart_enabled(enable_autostart_); ui_->main->set_daemon_enabled(enable_daemon_); #ifdef _WIN32 + ui_->main->set_capture_method_visible(true); + ui_->main->set_capture_method_index( + static_cast(config_center_->GetScreenCaptureMethod())); ui_->main->set_privacy_setting_visible(true); ui_->main->set_privacy_on_connect_enabled( config_center_->IsEnablePrivacyScreen()); @@ -3008,6 +3011,15 @@ void GuiApplication::SaveSettingsFromUi() { config_center_->SetAutostart(enable_autostart_); config_center_->SetDaemon(enable_daemon_); #ifdef _WIN32 + if (!HasActiveSession()) { + const auto capture_method = static_cast( + std::clamp(main->get_capture_method_index(), 0, 3)); + if (config_center_->SetScreenCaptureMethod(capture_method) != 0) { + LOG_ERROR("Failed to save screen capture method"); + } + } + main->set_capture_method_index( + static_cast(config_center_->GetScreenCaptureMethod())); if (config_center_->SetPrivacyScreen(main->get_privacy_on_connect_enabled()) != 0) { main->set_privacy_on_connect_enabled( diff --git a/apps/desktop/src/gui/assets/localization/localization_data.h b/apps/desktop/src/gui/assets/localization/localization_data.h index 648d256c..ec206d86 100644 --- a/apps/desktop/src/gui/assets/localization/localization_data.h +++ b/apps/desktop/src/gui/assets/localization/localization_data.h @@ -127,6 +127,9 @@ struct TranslationRow { u8"стола") \ X(settings, u8"设置", "Settings", u8"Настройки") \ X(language, u8"语言:", "Language:", u8"Язык:") \ + X(screen_capture_method, u8"采集方式:", "Capture Method:", \ + u8"Способ захвата:") \ + X(screen_capture_method_auto, u8"自动", "Auto", u8"Авто") \ X(video_quality, u8"画面质量:", "Video Quality:", u8"Качество видео:") \ X(video_frame_rate, u8"画面采集帧率:", \ "Video Capture Frame Rate:", u8"Частота захвата видео:") \ diff --git a/apps/desktop/src/gui/features/devices/session_device_manager.cpp b/apps/desktop/src/gui/features/devices/session_device_manager.cpp index 0139ca76..8d506627 100644 --- a/apps/desktop/src/gui/features/devices/session_device_manager.cpp +++ b/apps/desktop/src/gui/features/devices/session_device_manager.cpp @@ -78,11 +78,13 @@ int SessionDeviceManager::InitializeScreenCapturer() { if (!screen_capturer_) { screen_capturer_ = static_cast(screen_capturer_factory_->Create()); -#ifdef _WIN32 - if (auto windows = dynamic_cast(screen_capturer_)) - windows->SetPrivacyController(&owner_.privacy_); -#endif } +#ifdef _WIN32 + if (auto windows = dynamic_cast(screen_capturer_)) { + windows->SetPrivacyController(&owner_.privacy_); + windows->SetCaptureMethod(owner_.config_center_->GetScreenCaptureMethod()); + } +#endif last_frame_time_ = {}; next_frame_deadline_ = {}; diff --git a/apps/desktop/src/gui/ui/main_window.slint b/apps/desktop/src/gui/ui/main_window.slint index fc1ce2f8..4942dced 100644 --- a/apps/desktop/src/gui/ui/main_window.slint +++ b/apps/desktop/src/gui/ui/main_window.slint @@ -39,6 +39,8 @@ export global UiStrings { in-out property language: "Language"; in-out property video-quality: "Video quality"; in-out property frame-rate: "Frame rate"; + in-out property capture-method: "Capture method"; + in-out property capture-method-auto: "Auto"; in-out property adaptation-policy: "Video preference"; in-out property priority-frame-rate: "Frame rate"; in-out property priority-quality: "Quality"; @@ -239,6 +241,8 @@ export component MainWindow inherits Window { in-out property language-index: 0; in-out property video-quality-index: 2; in-out property frame-rate-index: 1; + in property capture-method-visible: false; + in-out property capture-method-index: 0; in-out property adaptation-policy-index: 1; in-out property codec-index: 0; in-out property hardware-codec-enabled: true; @@ -1448,6 +1452,11 @@ export component MainWindow inherits Window { Text { x: 8px; y: 3px; width: root.compact-language ? 94px : 162px; height: 24px; text: UiStrings.language; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; } CompactComboBox { x: root.compact-language ? 106px : 174px; y: 2px; model: ["中文", "English", "Русский"]; current-index <=> root.language-index; } } + if root.capture-method-visible: Rectangle { + height: 30px; + Text { x: 8px; y: 3px; width: root.compact-language ? 94px : 162px; height: 24px; text: UiStrings.capture-method; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; } + CompactComboBox { x: root.compact-language ? 106px : 174px; y: 2px; enabled: !root.settings-session-active; model: [UiStrings.capture-method-auto, "DXGI", "WGC", "GDI"]; current-index <=> root.capture-method-index; } + } if root.privacy-setting-visible: Rectangle { height: 30px; Text { x: 8px; y: 3px; width: root.compact-language ? 145px : 212px; height: 24px; text: UiStrings.privacy-on-connect; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; } diff --git a/apps/desktop/src/gui/ui/ui_localization.h b/apps/desktop/src/gui/ui/ui_localization.h index db92fc5c..1e2ecab0 100644 --- a/apps/desktop/src/gui/ui/ui_localization.h +++ b/apps/desktop/src/gui/ui/ui_localization.h @@ -54,6 +54,9 @@ inline int ApplyMainWindowStrings( strings.set_language(Text(localization::language[language])); strings.set_video_quality(Text(localization::video_quality[language])); strings.set_frame_rate(Text(localization::video_frame_rate[language])); + strings.set_capture_method(Text(localization::screen_capture_method[language])); + strings.set_capture_method_auto( + Text(localization::screen_capture_method_auto[language])); strings.set_adaptation_policy( Text(localization::video_adaptation_policy[language])); strings.set_priority_frame_rate( diff --git a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp index 9d1eb44c..b6639612 100644 --- a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp +++ b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp @@ -439,9 +439,12 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) { return true; }; // Short-circuiting also keeps the unused WGC plugin unloaded. - if (try_init(std::make_unique()) || - try_init(WgcPluginCapturer::Create()) || - try_init(std::make_unique())) { + if ((IsBackendEnabled(ScreenCaptureMethod::Dxgi) && + try_init(std::make_unique())) || + (IsBackendEnabled(ScreenCaptureMethod::Wgc) && + try_init(WgcPluginCapturer::Create())) || + (IsBackendEnabled(ScreenCaptureMethod::Gdi) && + try_init(std::make_unique()))) { LOG_INFO("Windows capturer: using {}", CaptureBackendName(impl_.get())); BuildCanonicalFromImpl(); monitor_index_.store(0, std::memory_order_relaxed); @@ -449,7 +452,8 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) { return 0; } - LOG_ERROR("Windows capturer: all implementations failed, ret={}", ret); + LOG_ERROR("Windows capturer: selected capture method {} failed, ret={}", + static_cast(capture_method_), ret); return -1; } @@ -576,6 +580,11 @@ int ScreenCapturerWin::Start(bool show_cursor) { } } if (ret != 0) { + if (capture_method_ != ScreenCaptureMethod::Auto) { + LOG_ERROR("Windows capturer: selected backend {} failed to start (ret={})", + CaptureBackendName(impl_.get()), ret); + return ret; + } LOG_WARN("Windows capturer: refresh/start failed (ret={}), trying fallback", ret); @@ -799,10 +808,12 @@ bool ScreenCapturerWin::RestartCaptureBackendAfterSecureDesktop() { return true; } - if (TryStartBackend(std::make_unique(), - current_monitor) || - TryStartBackend(WgcPluginCapturer::Create(), current_monitor) || - TryStartBackend(std::make_unique(), current_monitor)) { + if ((IsBackendEnabled(ScreenCaptureMethod::Dxgi) && + TryStartBackend(std::make_unique(), current_monitor)) || + (IsBackendEnabled(ScreenCaptureMethod::Wgc) && + TryStartBackend(WgcPluginCapturer::Create(), current_monitor)) || + (IsBackendEnabled(ScreenCaptureMethod::Gdi) && + TryStartBackend(std::make_unique(), current_monitor))) { return true; } diff --git a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.h b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.h index 6bdb00af..9d7226bd 100644 --- a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.h +++ b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.h @@ -20,6 +20,7 @@ #include #include "screen_capturer.h" +#include "screen_capture_method.h" #include "privacy_controller.h" namespace crossdesk { @@ -45,9 +46,16 @@ class ScreenCapturerWin : public ScreenCapturer { std::vector GetDisplayInfoList() override; void SetPrivacyController(PrivacyController* privacy) { privacy_ = privacy; } + // Set before Init(), while capture is stopped. + void SetCaptureMethod(ScreenCaptureMethod method) { capture_method_ = method; } private: std::unique_ptr impl_; + ScreenCaptureMethod capture_method_ = ScreenCaptureMethod::Auto; + bool IsBackendEnabled(ScreenCaptureMethod method) const { + return capture_method_ == ScreenCaptureMethod::Auto || + capture_method_ == method; + } PrivacyController* privacy_ = nullptr; void NotifyPrivacyCapture(bool running); int fps_ = 60; diff --git a/apps/desktop/src/screen_capturer/screen_capture_method.h b/apps/desktop/src/screen_capturer/screen_capture_method.h new file mode 100644 index 00000000..61d4533d --- /dev/null +++ b/apps/desktop/src/screen_capturer/screen_capture_method.h @@ -0,0 +1,22 @@ +/* + * @Author: DI JUNKUN + * @Date: 2026-09-11 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _SCREEN_CAPTURE_METHOD_H_ +#define _SCREEN_CAPTURE_METHOD_H_ + +namespace crossdesk { + +// Persisted values; keep these in the same order as the settings choices. +enum class ScreenCaptureMethod { Auto = 0, Dxgi = 1, Wgc = 2, Gdi = 3 }; + +inline bool IsValidScreenCaptureMethod(long value) { + return value >= static_cast(ScreenCaptureMethod::Auto) && + value <= static_cast(ScreenCaptureMethod::Gdi); +} + +} // namespace crossdesk + +#endif \ No newline at end of file diff --git a/apps/desktop/xmake/targets.lua b/apps/desktop/xmake/targets.lua index 34126d8e..9c282a8d 100644 --- a/apps/desktop/xmake/targets.lua +++ b/apps/desktop/xmake/targets.lua @@ -298,7 +298,8 @@ function setup_targets() set_kind("object") add_deps("rd_log", "autostart") add_files("apps/desktop/src/config_center/*.cpp") - add_includedirs("apps/desktop/src/config_center", {public = true}) + add_includedirs("apps/desktop/src", "apps/desktop/src/config_center", + {public = true}) target("assets") set_kind("headeronly")