Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the Windows “VDD mode” flow by unifying display preparation options (VDD + physical) under display_device_prep, adding a new ensure_secondary mode, and introducing a grace-period mechanism to keep VDD alive briefly for same-client reuse. It also updates the web UI + translations accordingly and adds/updates bundled Windows VDD driver assets.
Changes:
- Unify VDD/physical display preparation into
display_device_prep(removevdd_prepandcustom_vdd_screen_modeplumbing). - Add VDD deferred-restore (“grace period”) logic and mapping helpers between unified prep and internal VDD/physical behaviors.
- Update web UI (Setup Wizard + Display Device Options) and i18n strings; add driver catalog/INF assets.
Reviewed changes
Copilot reviewed 32 out of 36 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src_assets/windows/misc/vdd/driver/zakovdd.cat | Adds driver catalog asset for ZakoVDD package. |
| src_assets/windows/misc/vdd/driver/ZakoVDD.inf | Adds driver INF describing UMDF display adapter install. |
| src_assets/common/assets/web/public/assets/locale/zh_TW.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/zh.json | Update display prep strings and VDD reuse description; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/uk.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/tr.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/sv.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/ru.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/pt_BR.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/pt.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/pl.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/ko.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/ja.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/it.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/fr.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/es.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/en_US.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/en_GB.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/en.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/de.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/cs.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/public/assets/locale/bg.json | Update display prep strings; remove legacy VDD layout strings. |
| src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue | Remove VDD-specific UI split; add unified prep + ensure_secondary and dynamic descriptions. |
| src_assets/common/assets/web/composables/useConfig.js | Remove default vdd_prep from web config defaults. |
| src_assets/common/assets/web/components/SetupWizard.vue | Reorder steps and unify display prep selection UI (add ensure_secondary). |
| src/rtsp.h | Remove custom_vdd_screen_mode from launch session struct. |
| src/process.cpp | Remove SUNSHINE_CLIENT_CUSTOM_VDD_SCREEN_MODE env propagation. |
| src/nvhttp.cpp | Remove parsing/export of customVddScreenMode and related env. |
| src/display_device/session.h | Add deferred restore state and new execute_deferred_restore() declaration. |
| src/display_device/session.cpp | Implement grace-period deferred restore + unified prep mapping in restore flow; add shutdown VDD cleanup. |
| src/display_device/parsed_config.h | Add ensure_secondary and mapping helpers declarations. |
| src/display_device/parsed_config.cpp | Implement unified prep → VDD/physical mapping; remove vdd_prep config usage. |
| src/config.h | Remove vdd_prep from video config struct. |
| src/config.cpp | Remove vdd_prep default + parsing from config loader. |
| .gitignore | Remove _dev_notes/ ignore entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // 兜底:退出时如果 VDD 仍存在且 vdd_keep_enabled=false,直接销毁 | ||
| // 不调用完整的 restore_state(),因为析构时 boost::log/timer 可能已被销毁 | ||
| // 仅执行 VDD 销毁(写管道命令,不依赖日志和定时器) | ||
| if (!config::video.vdd_keep_enabled) { | ||
| auto vdd_id = display_device::find_device_by_friendlyname(ZAKO_NAME); | ||
| if (!vdd_id.empty()) { | ||
| vdd_utils::destroy_vdd_monitor(); | ||
| } |
| <div | ||
| id="panelsStayOpen-collapseOne" | ||
| class="accordion-collapse collapse" | ||
| class="accordion-collapse collapse show" | ||
| aria-labelledby="panelsStayOpen-headingOne" | ||
| > |
| @@ -400,7 +400,6 @@ namespace nvhttp { | |||
| launch_session->enable_hdr = util::from_view(get_arg(args, "hdrMode", "0")); | |||
| launch_session->use_vdd = util::from_view(get_arg(args, "useVdd", "0")); | |||
| launch_session->custom_screen_mode = util::from_view(get_arg(args, "customScreenMode", "-1")); | |||
| if (vdd_already_exists) { | ||
| execute_deferred_restore(deferred_restore_reason_); | ||
| } |
| if (!vdd_id.empty() && !is_keep_enabled && is_vdd_mode && has_persistent) { | ||
| BOOST_LOG(info) << "VDD 延迟恢复:启动 grace period,等待可能的同客户端新串流复用 VDD"; | ||
| deferred_restore_ = true; | ||
| deferred_restore_reason_ = reason; | ||
| deferred_client_id_ = current_vdd_client_id; | ||
|
|
||
| timer->setup_timer([this]() { | ||
| // Grace period 到期,没有新的 configure_display 到来,执行真正的 restore | ||
| BOOST_LOG(info) << "VDD grace period 到期,执行延迟恢复"; | ||
| deferred_restore_ = false; | ||
| deferred_client_id_.clear(); | ||
| execute_deferred_restore(deferred_restore_reason_); | ||
| return true; // 一次性执行,不重试 | ||
| }); | ||
| return; |
| @@ -1195,7 +1194,6 @@ namespace config { | |||
| } | |||
| #endif | |||
| @@ -188,7 +188,6 @@ namespace proc { | |||
| _env["SUNSHINE_CLIENT_ENABLE_SOPS"] = launch_session->enable_sops ? "true" : "false"; | |||
| _env["SUNSHINE_CLIENT_ENABLE_MIC"] = launch_session->enable_mic ? "true" : "false"; | |||
| _env["SUNSHINE_CLIENT_CUSTOM_SCREEN_MODE"] = std::to_string(launch_session->custom_screen_mode); | |||
| switch (unified) { | ||
| case device_prep_e::ensure_secondary: | ||
| return device_prep_e::ensure_active; // In physical mode, activate as secondary | ||
| default: | ||
| return unified; // All other values map 1:1 | ||
| } |
| } else if (this.currentStep === 2) { | ||
| return this.selectedDisplay !== null | ||
| } else if (this.currentStep === 3) { | ||
| return this.selectedAdapter !== null |
* feat: add QR code pairing support Backend: - Add preset PIN mechanism to nvhttp (set/get/clear_preset_pin) - Auto-use preset PIN during getservercert pairing phase - Add POST /api/qr-pair endpoint that generates random 4-digit PIN, sets it as preset, and returns moonlight:// URL for QR encoding Frontend: - Add qrcode npm dependency for client-side QR generation - Create useQrPair.js composable (API call, QR generation, countdown) - Add QR code pairing card to Pin.vue with generate/refresh/cancel - Add i18n keys for en and zh locales The QR code encodes a moonlight://pair URL containing host, port, PIN and server name. The preset PIN expires after 120 seconds. * fix: remove non-ASCII filenames that break CPack ZIP packaging CPack ZIP uses CP437 encoding which cannot handle Chinese characters in filenames. These 4 icon files (图标_45.png, 播放_45.png, 暂停_45.png, 锁_45.png) are not referenced by any code and have equivalent English-named counterparts already present in the same directory. * feat: desktop UI 系统 + 子模块更新 - 更新 sunshine-control-panel 子模块 (桌面 UI 完整系统) - confighttp/nvhttp: QR配对相关改动
There was a problem hiding this comment.
Pull request overview
This PR refactors the Windows VDD (virtual display) “prep/layout” flow by consolidating VDD/physical display preparation into a unified display_device_prep path, updating the Web UI (config + setup wizard) and i18n strings accordingly, and removing legacy VDD-specific config/session fields.
Changes:
- Unify display preparation into
display_device_prep(addsensure_secondary) and removevdd_prep/custom_vdd_screen_modeplumbing. - Update Windows display device restore/cleanup logic and setup wizard flow to match the unified preparation model.
- Add/update Windows VDD driver assets and update locale strings across all shipped languages.
Reviewed changes
Copilot reviewed 31 out of 35 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src_assets/windows/misc/vdd/driver/zakovdd.cat | Adds catalog file for the VDD driver package. |
| src_assets/windows/misc/vdd/driver/ZakoVDD.inf | Adds INF for the VDD driver package. |
| src_assets/common/assets/web/public/assets/locale/zh_TW.json | Updates display-prep and wizard strings (adds unified descriptions + ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/zh.json | Updates display-prep and wizard strings; removes old VDD-prep strings. |
| src_assets/common/assets/web/public/assets/locale/uk.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/tr.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/sv.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/ru.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/pt_BR.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/pt.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/pl.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/ko.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/ja.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/it.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/fr.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/es.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/en_US.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/en_GB.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/en.json | Updates unified display-prep labels/descriptions; removes old VDD-prep strings. |
| src_assets/common/assets/web/public/assets/locale/de.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/cs.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/public/assets/locale/bg.json | Updates display-prep and wizard strings (adds ensure_secondary). |
| src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue | Removes VDD-only UI branch; uses unified display prep with per-option descriptions. |
| src_assets/common/assets/web/composables/useConfig.js | Drops vdd_prep default from UI config model. |
| src_assets/common/assets/web/components/SetupWizard.vue | Reorders steps (GPU before display), unifies display-prep strategy selection, updates telemetry fields. |
| src/rtsp.h | Removes custom_vdd_screen_mode from session struct. |
| src/process.cpp | Removes SUNSHINE_CLIENT_CUSTOM_VDD_SCREEN_MODE env export. |
| src/nvhttp.cpp | Removes customVddScreenMode parsing and env export. |
| src/display_device/session.cpp | Adjusts shutdown/restore handling; maps unified prep to VDD/physical behaviors; adds VDD cleanup paths. |
| src/display_device/parsed_config.h | Adds ensure_secondary and mapping helpers for unified prep -> VDD/physical modes. |
| src/display_device/parsed_config.cpp | Implements unified prep mapping, removes client VDD-specific override handling. |
| src/config.h | Removes vdd_prep from config struct. |
| src/config.cpp | Removes vdd_prep parsing/default initialization. |
| .gitignore | Stops ignoring _dev_notes/. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // 兜底:退出时如果 VDD 仍存在且 vdd_keep_enabled=false,直接销毁 | ||
| // 不调用完整的 restore_state(),因为析构时 boost::log/timer 可能已被销毁 | ||
| // 仅执行 VDD 销毁(写管道命令,不依赖日志和定时器) | ||
| if (!config::video.vdd_keep_enabled) { | ||
| auto vdd_id = display_device::find_device_by_friendlyname(ZAKO_NAME); | ||
| if (!vdd_id.empty()) { | ||
| vdd_utils::destroy_vdd_monitor(); | ||
| } |
| parsed_config_t::to_physical_device_prep(device_prep_e unified) { | ||
| switch (unified) { | ||
| case device_prep_e::ensure_secondary: | ||
| return device_prep_e::ensure_active; // In physical mode, activate as secondary |
| <select id="display_device_prep" class="form-select" v-model="config.display_device_prep"> | ||
| <option value="no_operation">{{ $tp('config.display_device_prep_no_operation') }}</option> | ||
| <option value="ensure_active">{{ $tp('config.display_device_prep_ensure_active') }}</option> | ||
| <option value="ensure_primary">{{ $tp('config.display_device_prep_ensure_primary') }}</option> | ||
| <option value="ensure_secondary">{{ $tp('config.display_device_prep_ensure_secondary') }}</option> | ||
| <option value="ensure_only_display"> | ||
| {{ $tp('config.display_device_prep_ensure_only_display') }} | ||
| </option> | ||
| </select> | ||
| </div> | ||
|
|
||
| <!-- VDD mode: Physical display preparation (only shown in VDD mode) --> | ||
| <div class="mb-3" v-if="isVddMode"> | ||
| <label for="vdd_prep" class="form-label"> | ||
| {{ $tp('config.vdd_prep') }} | ||
| </label> | ||
| <select id="vdd_prep" class="form-select" v-model="config.vdd_prep"> | ||
| <option value="no_operation">{{ $tp('config.vdd_prep_no_operation') }}</option> | ||
| <option value="vdd_as_primary">{{ $tp('config.vdd_prep_vdd_as_primary') }}</option> | ||
| <option value="vdd_as_secondary">{{ $tp('config.vdd_prep_vdd_as_secondary') }}</option> | ||
| <option value="display_off">{{ $tp('config.vdd_prep_display_off') }}</option> | ||
| </select> | ||
| <div class="form-text"> | ||
| <p style="white-space: pre-line">{{ $tp('config.vdd_prep_desc') }}</p> | ||
| <div class="form-text" v-if="config.display_device_prep"> | ||
| {{ $tp('config.display_device_prep_' + config.display_device_prep + '_desc') }} | ||
| </div> |
| @@ -1195,7 +1194,6 @@ namespace config { | |||
| } | |||
| #endif | |||
| } else if (this.currentStep === 2) { | ||
| return this.selectedDisplay !== null | ||
| } else if (this.currentStep === 3) { | ||
| return this.selectedAdapter !== null |
| @@ -58,7 +53,7 @@ function addRemapping(type) { | |||
| </h2> | |||
| <div | |||
| id="panelsStayOpen-collapseOne" | |||
| class="accordion-collapse collapse" | |||
| class="accordion-collapse collapse show" | |||
| aria-labelledby="panelsStayOpen-headingOne" | |||
后端 C++(已完成)
src/display_device/parsed_config.hdevice_prep_e枚举新增ensure_secondary(4);新增to_vdd_prep()/to_physical_device_prep()src/display_device/parsed_config.cppdevice_prep_from_view支持新值;make_parsed_config统一映射;移除custom_vdd_screen_modesrc/config.hvideo_t::vdd_prep字段src/config.cppvdd_prep默认值和解析src/display_device/session.hsrc/display_device/session.cpprestore_state_impl直接销毁 VDD 并恢复拓扑;configure_display保持 VDD 存在时的 client_id 检查和 pending_restore 处理;析构函数使用destroy_vdd_monitor_nolog()兜底清理src/display_device/vdd_utils.hdestroy_vdd_monitor_nolog()声明src/display_device/vdd_utils.cppdestroy_vdd_monitor_nolog()实现(shutdown-safe,纯 Win32 API)src/rtsp.hcustom_vdd_screen_mode字段src/nvhttp.cppcustomVddScreenMode解析和环境变量src/process.cppSUNSHINE_CLIENT_CUSTOM_VDD_SCREEN_MODE环境变量前端(已完成)
DisplayDeviceOptions.vue<select>5 选项,移除 VDD/物理分支SetupWizard.vuevddPrep,统一保存useConfig.jsvdd_prep默认值vdd_prep_*,新增ensure_secondary,统一文案关键设计决策
Q1:为什么不区分 VDD/物理模式的选项?
用户不需要理解 VDD 是什么。"主屏串流"在物理模式下是"设该显示器为主屏",在 VDD 模式下是"VDD 作为主屏 + 物理扩展",语义一致。后端自动处理差异。
Q2:为什么新增
ensure_secondary而不是复用ensure_active?ensure_active的原始语义是"仅激活,不修改拓扑"。在 VDD 模式下等效于no_operation。ensure_secondary的语义是"副屏串流",在 VDD 模式下映射到vdd_as_secondary(物理主屏 + VDD 副屏)。两者在 VDD 模式下行为不同,不能合并。
Q3:
vdd_prep需要迁移吗?不需要。
vdd_prep尚未正式上线发布,无线上用户配置需要迁移。直接废弃即可。Q4:
custom_screen_mode客户端 override 如何支持?custom_screen_mode扩展支持新增的整数值(4 对应ensure_secondary)。原
custom_vdd_screen_mode直接移除(未上线,无需兼容)。