mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-06 22:19:11 +08:00
[feat] add configurable video pause on minimize, refs #143
This commit is contained in:
@@ -154,6 +154,8 @@ int ConfigCenter::Load() {
|
||||
ini_->GetBoolValue(section_, "trusted_devices_only", true));
|
||||
save_remote_previews_.store(
|
||||
ini_->GetBoolValue(section_, "save_remote_previews", true));
|
||||
pause_video_when_minimized_.store(
|
||||
ini_->GetBoolValue(section_, "pause_video_when_minimized", true));
|
||||
portable_service_prompt_suppressed_ =
|
||||
ini_->GetBoolValue(section_, "portable_service_prompt_suppressed",
|
||||
portable_service_prompt_suppressed_);
|
||||
@@ -253,6 +255,8 @@ int ConfigCenter::Save() {
|
||||
ini_->SetBoolValue(section_, "trusted_devices_only", trusted_devices_only_.load());
|
||||
ini_->SetBoolValue(section_, "save_remote_previews",
|
||||
save_remote_previews_.load());
|
||||
ini_->SetBoolValue(section_, "pause_video_when_minimized",
|
||||
pause_video_when_minimized_.load());
|
||||
ini_->SetBoolValue(section_, "portable_service_prompt_suppressed",
|
||||
portable_service_prompt_suppressed_);
|
||||
ini_->SetValue(section_, "sponsorship_prompt_dismissed_version",
|
||||
@@ -467,6 +471,18 @@ bool ConfigCenter::IsSaveRemotePreviews() const {
|
||||
return save_remote_previews_.load();
|
||||
}
|
||||
|
||||
int ConfigCenter::SetPauseVideoWhenMinimized(bool enabled) {
|
||||
if (StoreValues({{"pause_video_when_minimized", enabled ? "true" : "false"}}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
pause_video_when_minimized_.store(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ConfigCenter::IsPauseVideoWhenMinimized() const {
|
||||
return pause_video_when_minimized_.load();
|
||||
}
|
||||
|
||||
int ConfigCenter::SetPortableServicePromptSuppressed(bool suppressed) {
|
||||
portable_service_prompt_suppressed_ = suppressed;
|
||||
ini_->SetBoolValue(section_, "portable_service_prompt_suppressed",
|
||||
|
||||
@@ -57,6 +57,7 @@ class ConfigCenter {
|
||||
int SetLockOnDisconnect(bool enabled);
|
||||
int SetTrustedDevicesOnly(bool enabled);
|
||||
int SetSaveRemotePreviews(bool enabled);
|
||||
int SetPauseVideoWhenMinimized(bool enabled);
|
||||
int SetPortableServicePromptSuppressed(bool suppressed);
|
||||
int SetSponsorshipPromptDismissedVersion(const std::string& version);
|
||||
int SetFileTransferSavePath(const std::string& path);
|
||||
@@ -83,6 +84,7 @@ class ConfigCenter {
|
||||
bool IsLockOnDisconnect() const;
|
||||
bool IsTrustedDevicesOnly() const;
|
||||
bool IsSaveRemotePreviews() const;
|
||||
bool IsPauseVideoWhenMinimized() const;
|
||||
bool IsPortableServicePromptSuppressed() const;
|
||||
std::string GetSponsorshipPromptDismissedVersion() const;
|
||||
std::string GetFileTransferSavePath() const;
|
||||
@@ -117,6 +119,7 @@ class ConfigCenter {
|
||||
std::atomic<bool> lock_on_disconnect_{true};
|
||||
std::atomic<bool> trusted_devices_only_{false};
|
||||
std::atomic<bool> save_remote_previews_{true};
|
||||
std::atomic<bool> pause_video_when_minimized_{true};
|
||||
bool portable_service_prompt_suppressed_ = false;
|
||||
std::string sponsorship_prompt_dismissed_version_;
|
||||
std::string file_transfer_save_path_ = "";
|
||||
|
||||
@@ -1575,6 +1575,7 @@ void GuiApplication::ResetSettingsUi(bool gallery_window) {
|
||||
#endif
|
||||
main->set_daemon_enabled(enable_daemon_);
|
||||
main->set_save_remote_previews(config_center_->IsSaveRemotePreviews());
|
||||
main->set_pause_video_when_minimized(config_center_->IsPauseVideoWhenMinimized());
|
||||
main->set_privacy_on_connect_enabled(
|
||||
config_center_->IsEnablePrivacyScreen());
|
||||
main->set_privacy_local_unlock_allowed(config_center_->IsPrivacyLocalUnlockAllowed());
|
||||
@@ -4868,6 +4869,13 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) {
|
||||
localization::Literal("无法保存隐私屏解锁设置,请重试。", localization_language_index_)));
|
||||
return false;
|
||||
}
|
||||
if (config_center_->SetPauseVideoWhenMinimized(main->get_pause_video_when_minimized()) != 0) {
|
||||
if (wall_changed && !ui_->gallery.Save(ui_->gallery_path))
|
||||
LOG_ERROR("Failed to restore DeskHub settings after video pause preference save failure");
|
||||
main->set_settings_save_error(UiText(
|
||||
localization::Literal("保存失败,请重试", localization_language_index_)));
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const bool listen_all = main->get_lan_listen_all_draft();
|
||||
if (LanAvailable() && main->get_ip_direct_enabled_draft()) {
|
||||
@@ -4978,6 +4986,7 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) {
|
||||
ApplySettingsFromConfig(previous_server !=
|
||||
GetSignalServerSettings(*config_center_));
|
||||
ResetSettingsUi(gallery_window);
|
||||
ui_->gallery_synced = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6701,6 +6710,8 @@ void GuiApplication::SyncGallery() {
|
||||
const bool stream_window_visible = ui_->stream &&
|
||||
(*ui_->stream)->window().is_visible() &&
|
||||
!(*ui_->stream)->window().is_minimized();
|
||||
const bool stream_window_receiving = ui_->stream &&
|
||||
(stream_window_visible || !config_center_->IsPauseVideoWhenMinimized());
|
||||
const auto stream_viewport = stream_window_visible
|
||||
? gallery::PreviewResolution::Viewport(
|
||||
(*ui_->stream)->get_video_area_width(),
|
||||
@@ -6743,6 +6754,12 @@ void GuiApplication::SyncGallery() {
|
||||
const bool needs_sync = props->preview_needs_sync_.exchange(false);
|
||||
const bool stream_visible = stream_window_visible &&
|
||||
props->tab_opened_ && id == focused_remote_id_;
|
||||
// Ordinary tabs keep receiving while their window is visible. DeskHub
|
||||
// sessions also account for their visible previews below. A minimized
|
||||
// window can keep receiving when the user disables automatic pausing.
|
||||
const bool stream_needs_video = stream_window_receiving &&
|
||||
props->tab_opened_ &&
|
||||
(!props->wall_managed_ || id == focused_remote_id_);
|
||||
if (props->preview_resolution_supported_) {
|
||||
const auto wall_viewport = !preview_ids.count(id)
|
||||
? gallery::PreviewResolution{}
|
||||
@@ -6757,7 +6774,7 @@ void GuiApplication::SyncGallery() {
|
||||
demand.width = resolution.width;
|
||||
demand.height = resolution.height;
|
||||
}
|
||||
if (props->wall_managed_ && !preview_ids.count(id) && !stream_visible)
|
||||
if (!preview_ids.count(id) && !stream_needs_video)
|
||||
demand.fps = 0;
|
||||
gallery::PreviewBandwidthDemand bandwidth;
|
||||
if (props->preview_bandwidth_supported_) {
|
||||
|
||||
@@ -525,6 +525,8 @@ inline constexpr TranslationRow kTranslationRows[] = {
|
||||
{"发送到本机", {"发送到本机", "Send to local", "Отправить на этот ПК", "傳送到本機", "この端末へ送信", "이 기기로 보내기", "An diesen PC senden", "Envoyer à ce PC", "Enviar a este equipo", "Enviar a este computador"}},
|
||||
{"清除已完成", {"清除已完成", "Clear completed", "Убрать завершённые", "清除已完成", "完了済みをクリア", "완료 항목 지우기", "Abgeschlossene entfernen", "Effacer les tâches terminées", "Limpiar completadas", "Limpar concluídas"}},
|
||||
{"打开目录", {"打开目录", "Open folder", "Открыть папку", "開啟目錄", "フォルダーを開く", "폴더 열기", "Ordner öffnen", "Ouvrir le dossier", "Abrir carpeta", "Abrir pasta"}},
|
||||
{"最小化时暂停视频", {"最小化时暂停视频", "Pause video when minimized", "Приостанавливать видео при сворачивании", "最小化時暫停視訊", "最小化時に映像を一時停止", "최소화 시 영상 일시 중지", "Video beim Minimieren pausieren", "Mettre la vidéo en pause à la réduction", "Pausar el vídeo al minimizar", "Pausar vídeo ao minimizar"}},
|
||||
{"控制窗口最小化时暂停接收视频,降低本机解码资源占用。", {"控制窗口最小化时暂停接收视频,降低本机解码资源占用。", "Pause video reception when the control window is minimized to reduce local decoding resource usage.", "При сворачивании окна управления приём видео приостанавливается, снижая нагрузку от декодирования на этом устройстве.", "控制視窗最小化時暫停接收視訊,降低本機解碼資源占用。", "操作ウィンドウの最小化時に映像の受信を一時停止し、この端末のデコード処理による負荷を軽減します。", "제어 창을 최소화하면 영상 수신을 일시 중지하여 이 기기의 디코딩 리소스 사용량을 줄입니다.", "Pausiert den Videoempfang, wenn das Steuerungsfenster minimiert ist, und reduziert so den lokalen Ressourcenverbrauch beim Dekodieren.", "Met en pause la réception vidéo lorsque la fenêtre de contrôle est réduite afin de diminuer les ressources de décodage utilisées sur cet appareil.", "Pausa la recepción de vídeo al minimizar la ventana de control para reducir el uso de recursos de decodificación en este dispositivo.", "Pausa a recepção de vídeo ao minimizar a janela de controle para reduzir o uso de recursos de decodificação neste dispositivo."}},
|
||||
};
|
||||
|
||||
struct NamedTranslation { const char* name; const char* literal; };
|
||||
@@ -813,6 +815,8 @@ inline constexpr NamedTranslation kNamedTranslations[] = {
|
||||
{"privacy_screen_unlock_hint", "按下快捷键,解除隐私屏"},
|
||||
{"exit_program", "退出"},
|
||||
{"shutdown_reason", "远程控制连接中,保留连接以确认或取消关机。"},
|
||||
{"pause_video_when_minimized", "最小化时暂停视频"},
|
||||
{"pause_video_when_minimized_hint", "控制窗口最小化时暂停接收视频,降低本机解码资源占用。"},
|
||||
};
|
||||
inline constexpr const char* kSlintLiterals[] = {
|
||||
"此端口已被占用,",
|
||||
@@ -1023,6 +1027,8 @@ inline constexpr const char* kSlintLiterals[] = {
|
||||
"确认执行",
|
||||
"监听所有 IP 接口",
|
||||
"所有接口共用一个端口,包括 VPN。分享时请选择实际 IP;关闭后恢复各 IP 的独立端口。",
|
||||
"最小化时暂停视频",
|
||||
"控制窗口最小化时暂停接收视频,降低本机解码资源占用。",
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -1310,7 +1316,9 @@ inline constexpr const char* kSlintLiterals[] = {
|
||||
X(privacy_unlock_lock) \
|
||||
X(privacy_screen_unlock_hint) \
|
||||
X(exit_program) \
|
||||
X(shutdown_reason)
|
||||
X(shutdown_reason) \
|
||||
X(pause_video_when_minimized) \
|
||||
X(pause_video_when_minimized_hint)
|
||||
|
||||
} // namespace localization
|
||||
} // namespace crossdesk
|
||||
|
||||
@@ -76,6 +76,8 @@ export global UiStrings {
|
||||
in-out property <string> capture-method: "Capture method";
|
||||
in-out property <string> capture-method-auto: "Auto";
|
||||
in-out property <string> codec: "Video codec";
|
||||
in-out property <string> pause-video-when-minimized: "Pause video when minimized";
|
||||
in-out property <string> pause-video-when-minimized-hint: "Pause video reception when the control window is minimized to reduce local decoding resource usage.";
|
||||
in-out property <string> force-relay: "Force relay";
|
||||
in-out property <string> self-hosted: "Self-hosted server";
|
||||
in-out property <string> autostart: "Start with system";
|
||||
@@ -658,6 +660,7 @@ export component MainWindow inherits Window {
|
||||
changed autostart-guide-open => { if root.autostart-guide-open { root.dialog-focus-pending = true; } }
|
||||
in-out property <bool> daemon-enabled: false;
|
||||
in-out property <bool> save-remote-previews: true;
|
||||
in-out property <bool> pause-video-when-minimized: true;
|
||||
// Show the preference on every platform; only adapted hosts can change it.
|
||||
in property <bool> privacy-setting-available: false;
|
||||
in-out property <bool> privacy-on-connect-enabled: true;
|
||||
@@ -726,6 +729,11 @@ export component MainWindow inherits Window {
|
||||
in-out property <bool> settings-open: false;
|
||||
in-out property <int> settings-tab: 0;
|
||||
private property <length> settings-scroll-y: 0px;
|
||||
private property <bool> pause-video-hint-visible: false;
|
||||
private property <length> pause-video-hint-x: 0px;
|
||||
private property <length> pause-video-hint-y: 0px;
|
||||
changed settings-tab => { root.pause-video-hint-visible = false; }
|
||||
changed settings-scroll-y => { root.pause-video-hint-visible = false; }
|
||||
in-out property <bool> self-host-settings-open: false;
|
||||
changed self-host-settings-open => {
|
||||
if !root.self-host-settings-open { root.self-host-settings-error = ""; }
|
||||
@@ -826,6 +834,7 @@ export component MainWindow inherits Window {
|
||||
changed connection-dialog-open => { if root.connection-dialog-open { root.gallery-action("release", ""); } }
|
||||
changed permission-dialog-open => { if root.permission-dialog-open { root.gallery-action("release", ""); } }
|
||||
changed settings-open => {
|
||||
root.pause-video-hint-visible = false;
|
||||
if root.settings-open {
|
||||
root.settings-tab = 0;
|
||||
root.settings-scroll-y = 0px;
|
||||
@@ -2730,15 +2739,30 @@ export component MainWindow inherits Window {
|
||||
}
|
||||
SettingsGroup {
|
||||
title: GalleryStrings.texts[115];
|
||||
rows: root.capture-method-visible ? 2 : 1;
|
||||
rows: root.capture-method-visible ? 3 : 2;
|
||||
if root.capture-method-visible: SettingsRow {
|
||||
label: UiStrings.capture-method; enabled: !root.settings-session-active;
|
||||
SettingsSelect { x: parent.width - 116px; y: 4px; width: 104px; enabled: !root.settings-session-active; model: [UiStrings.capture-method-auto, "DXGI", "WGC", "GDI"]; current-index <=> root.capture-method-index; }
|
||||
}
|
||||
SettingsRow {
|
||||
label: UiStrings.codec; enabled: !root.settings-session-active; divider: false;
|
||||
label: UiStrings.codec; enabled: !root.settings-session-active;
|
||||
SettingsSelect { x: parent.width - 116px; y: 4px; width: 104px; enabled: !root.settings-session-active; model: [UiStrings.codec-h264, UiStrings.codec-av1]; current-index <=> root.codec-index; }
|
||||
}
|
||||
pause-video-hover := TouchArea {
|
||||
height: 36px;
|
||||
function update-hint() {
|
||||
root.pause-video-hint-visible = self.has-hover;
|
||||
root.pause-video-hint-x = self.absolute-position.x + self.mouse-x;
|
||||
root.pause-video-hint-y = self.absolute-position.y + self.mouse-y;
|
||||
}
|
||||
changed has-hover => { self.update-hint(); }
|
||||
pointer-event(event) => { self.update-hint(); }
|
||||
SettingsToggleRow {
|
||||
width: parent.width;
|
||||
label: UiStrings.pause-video-when-minimized;
|
||||
checked <=> root.pause-video-when-minimized; divider: false;
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingsGroup {
|
||||
title: GalleryStrings.texts[116]; rows: 4;
|
||||
@@ -2843,6 +2867,25 @@ export component MainWindow inherits Window {
|
||||
clicked => { if root.save-settings() { root.settings-open = false; root.self-host-settings-open = false; } }
|
||||
}
|
||||
}
|
||||
if root.window-active && root.settings-tab == 0 && root.pause-video-hint-visible: Rectangle {
|
||||
// Keep the immediate hint outside ScrollView's clipping area.
|
||||
width: min(260px, parent.width - 16px);
|
||||
height: max(28px, pause-video-hint-text.preferred-height + 12px);
|
||||
x: clamp(root.pause-video-hint-x - settings-dialog.absolute-position.x,
|
||||
8px, parent.width - self.width - 8px);
|
||||
private property <length> pointer-y: root.pause-video-hint-y - settings-dialog.absolute-position.y;
|
||||
y: self.pointer-y + 8px + self.height <= parent.height - 8px
|
||||
? self.pointer-y + 8px : self.pointer-y - self.height - 8px;
|
||||
background: #24324a;
|
||||
border-radius: UiRadius.control; z: 20;
|
||||
pause-video-hint-text := Text {
|
||||
x: 10px; y: 6px;
|
||||
width: parent.width - 20px; height: parent.height - 12px;
|
||||
text: UiStrings.pause-video-when-minimized-hint;
|
||||
font-size: 12px; font-weight: 400; color: white; wrap: word-wrap;
|
||||
horizontal-alignment: left; vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,6 +130,10 @@ 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_pause_video_when_minimized(
|
||||
Text(localization::pause_video_when_minimized[language]));
|
||||
strings.set_pause_video_when_minimized_hint(
|
||||
Text(localization::pause_video_when_minimized_hint[language]));
|
||||
strings.set_force_relay(Text(localization::force_relay[language]));
|
||||
strings.set_self_hosted(
|
||||
Text(localization::self_hosted_server_config[language]));
|
||||
|
||||
@@ -10643,6 +10643,30 @@
|
||||
"fr": "Ouvrir le dossier",
|
||||
"es": "Abrir carpeta",
|
||||
"pt-BR": "Abrir pasta"
|
||||
},
|
||||
"最小化时暂停视频": {
|
||||
"zh-Hans": "最小化时暂停视频",
|
||||
"en": "Pause video when minimized",
|
||||
"ru": "Приостанавливать видео при сворачивании",
|
||||
"zh-Hant": "最小化時暫停視訊",
|
||||
"ja": "最小化時に映像を一時停止",
|
||||
"ko": "최소화 시 영상 일시 중지",
|
||||
"de": "Video beim Minimieren pausieren",
|
||||
"fr": "Mettre la vidéo en pause à la réduction",
|
||||
"es": "Pausar el vídeo al minimizar",
|
||||
"pt-BR": "Pausar vídeo ao minimizar"
|
||||
},
|
||||
"控制窗口最小化时暂停接收视频,降低本机解码资源占用。": {
|
||||
"zh-Hans": "控制窗口最小化时暂停接收视频,降低本机解码资源占用。",
|
||||
"en": "Pause video reception when the control window is minimized to reduce local decoding resource usage.",
|
||||
"ru": "При сворачивании окна управления приём видео приостанавливается, снижая нагрузку от декодирования на этом устройстве.",
|
||||
"zh-Hant": "控制視窗最小化時暫停接收視訊,降低本機解碼資源占用。",
|
||||
"ja": "操作ウィンドウの最小化時に映像の受信を一時停止し、この端末のデコード処理による負荷を軽減します。",
|
||||
"ko": "제어 창을 최소화하면 영상 수신을 일시 중지하여 이 기기의 디코딩 리소스 사용량을 줄입니다.",
|
||||
"de": "Pausiert den Videoempfang, wenn das Steuerungsfenster minimiert ist, und reduziert so den lokalen Ressourcenverbrauch beim Dekodieren.",
|
||||
"fr": "Met en pause la réception vidéo lorsque la fenêtre de contrôle est réduite afin de diminuer les ressources de décodage utilisées sur cet appareil.",
|
||||
"es": "Pausa la recepción de vídeo al minimizar la ventana de control para reducir el uso de recursos de decodificación en este dispositivo.",
|
||||
"pt-BR": "Pausa a recepção de vídeo ao minimizar a janela de controle para reduzir o uso de recursos de decodificação neste dispositivo."
|
||||
}
|
||||
},
|
||||
"desktop": {
|
||||
@@ -10929,7 +10953,9 @@
|
||||
"privacy_unlock_lock": "锁定",
|
||||
"privacy_screen_unlock_hint": "按下快捷键,解除隐私屏",
|
||||
"exit_program": "退出",
|
||||
"shutdown_reason": "远程控制连接中,保留连接以确认或取消关机。"
|
||||
"shutdown_reason": "远程控制连接中,保留连接以确认或取消关机。",
|
||||
"pause_video_when_minimized": "最小化时暂停视频",
|
||||
"pause_video_when_minimized_hint": "控制窗口最小化时暂停接收视频,降低本机解码资源占用。"
|
||||
},
|
||||
"slint": [
|
||||
"此端口已被占用,",
|
||||
@@ -11139,7 +11165,9 @@
|
||||
"确认断开",
|
||||
"确认执行",
|
||||
"监听所有 IP 接口",
|
||||
"所有接口共用一个端口,包括 VPN。分享时请选择实际 IP;关闭后恢复各 IP 的独立端口。"
|
||||
"所有接口共用一个端口,包括 VPN。分享时请选择实际 IP;关闭后恢复各 IP 的独立端口。",
|
||||
"最小化时暂停视频",
|
||||
"控制窗口最小化时暂停接收视频,降低本机解码资源占用。"
|
||||
],
|
||||
"platforms": {
|
||||
"desktop": [
|
||||
@@ -11654,7 +11682,9 @@
|
||||
"发送到远端",
|
||||
"发送到本机",
|
||||
"清除已完成",
|
||||
"打开目录"
|
||||
"打开目录",
|
||||
"最小化时暂停视频",
|
||||
"控制窗口最小化时暂停接收视频,降低本机解码资源占用。"
|
||||
],
|
||||
"android": [
|
||||
" · 已完成",
|
||||
|
||||
Reference in New Issue
Block a user