diff --git a/Cargo.lock b/Cargo.lock index 3a8adbda2..24a4a399c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1819,6 +1819,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "enquote" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c36cb11dbde389f4096111698d8b567c0720e3452fd5ac3e6b4e47e1939932" +dependencies = [ + "thiserror", +] + [[package]] name = "enum-iterator" version = "1.4.1" @@ -5214,6 +5223,7 @@ dependencies = [ "users 0.11.0", "uuid", "virtual_display", + "wallpaper", "whoami", "winapi 0.3.9", "windows-service", @@ -6589,6 +6599,19 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wallpaper" +version = "3.2.0" +source = "git+https://github.com/21pages/wallpaper.rs#2bbb70acd93be179c69cb96cb8c3dda487e6f5fd" +dependencies = [ + "dirs 5.0.1", + "enquote", + "rust-ini", + "thiserror", + "winapi 0.3.9", + "winreg 0.11.0", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 9e8224fc1..d24e7a061 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ clipboard = { path = "libs/clipboard" } ctrlc = "3.2" arboard = "3.2" system_shutdown = "4.0" +shutdown_hooks = "0.1" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi"] } @@ -96,7 +97,6 @@ windows-service = "0.6" virtual_display = { path = "libs/virtual_display", optional = true } impersonate_system = { git = "https://github.com/21pages/impersonate-system" } shared_memory = "0.12" -shutdown_hooks = "0.1" tauri-winrt-notification = "0.1.2" [target.'cfg(target_os = "macos")'.dependencies] @@ -118,6 +118,9 @@ image = "0.24" [target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies] keepawake = { git = "https://github.com/rustdesk-org/keepawake-rs" } +[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies] +wallpaper = { git = "https://github.com/21pages/wallpaper.rs" } + [target.'cfg(target_os = "linux")'.dependencies] psimple = { package = "libpulse-simple-binding", version = "2.27" } pulse = { package = "libpulse-binding", version = "2.27" } diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 7324d3a72..a105f2135 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -322,6 +323,24 @@ class _GeneralState extends State<_General> { 'enable-confirm-closing-tabs', isServer: false), _OptionCheckBox(context, 'Adaptive bitrate', 'enable-abr'), + if (Platform.isWindows || Platform.isLinux) + Row( + children: [ + Flexible( + child: _OptionCheckBox( + context, + 'Remove wallpaper during incoming sessions', + 'allow-remove-wallpaper'), + ), + _CountDownButton( + text: 'Test', + second: 5, + onPressed: () { + bind.mainTestWallpaper(second: 5); + }, + ) + ], + ), _OptionCheckBox( context, 'Open connection in new tab', @@ -1873,6 +1892,69 @@ class _ComboBox extends StatelessWidget { } } +class _CountDownButton extends StatefulWidget { + _CountDownButton({ + Key? key, + required this.text, + required this.second, + required this.onPressed, + }) : super(key: key); + final String text; + final VoidCallback? onPressed; + final int second; + + @override + State<_CountDownButton> createState() => _CountDownButtonState(); +} + +class _CountDownButtonState extends State<_CountDownButton> { + bool _isButtonDisabled = false; + + late int _countdownSeconds = widget.second; + + Timer? _timer; + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + void _startCountdownTimer() { + _timer = Timer.periodic(Duration(seconds: 1), (timer) { + if (_countdownSeconds <= 0) { + setState(() { + _isButtonDisabled = false; + }); + timer.cancel(); + } else { + setState(() { + _countdownSeconds--; + }); + } + }); + } + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: _isButtonDisabled + ? null + : () { + widget.onPressed?.call(); + setState(() { + _isButtonDisabled = true; + _countdownSeconds = widget.second; + }); + _startCountdownTimer(); + }, + child: Text( + _isButtonDisabled ? '$_countdownSeconds s' : translate(widget.text), + ), + ); + } +} + //#endregion //#region dialogs diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index c931d8926..b4ae89bc9 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1613,6 +1613,18 @@ pub fn main_start_ipc_url_server() { std::thread::spawn(move || crate::server::start_ipc_url_server()); } +pub fn main_test_wallpaper(_second: u64) { + #[cfg(any(target_os = "windows", target_os = "linux"))] + std::thread::spawn(move || match crate::platform::WallPaperRemover::new() { + Ok(_remover) => { + std::thread::sleep(std::time::Duration::from_secs(_second)); + } + Err(e) => { + log::info!("create wallpaper remover failed:{:?}", e); + } + }); +} + /// Send a url scheme throught the ipc. /// /// * macOS only diff --git a/src/lang/ar.rs b/src/lang/ar.rs index a7f24540e..7921dbde4 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index e7180abf3..61cbef359 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index d1cff492b..ea8f4ee4e 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "启动时检查软件更新"), ("upgrade_rustdesk_server_pro_to_{}_tip", "请升级专业版服务器到{}或更高版本!"), ("pull_group_failed_tip", "获取组信息失败"), - ("Filter by intersection", "按交集过滤") + ("Filter by intersection", "按交集过滤"), + ("Remove wallpaper during incoming sessions", "接受会话时移除桌面壁纸"), + ("Test", "测试"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 9267e1f75..ff0b87502 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Kontrola aktualizace softwaru při spuštění"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Aktualizujte prosím RustDesk Server Pro na verzi {} nebo novější!"), ("pull_group_failed_tip", "Nepodařilo se obnovit skupinu"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 1ad6f36b5..6b577e5b8 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 661437085..aac437388 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Beim Start auf Softwareaktualisierung prüfen"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Bitte aktualisieren Sie RustDesk Server Pro auf die Version {} oder neuer!"), ("pull_group_failed_tip", "Aktualisierung der Gruppe fehlgeschlagen"), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ("Filter by intersection", "Nach Schnittpunkt filtern") ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index a984411a2..169ee2359 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 51e97c68a..59c4db9fe 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 350505a34..c8abc4e1b 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Comprobar actualización al iniciar"), ("upgrade_rustdesk_server_pro_to_{}_tip", "¡Por favor, actualiza RustDesk Server Pro a la versión {} o superior"), ("pull_group_failed_tip", "No se ha podido refrescar el grupo"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0e0009a6c..e5b20d39c 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 50b03299a..075167af1 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Vérifier la disponibilité des mises à jour au démarrage"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Veuillez mettre à jour RustDesk Server Pro avec la version {} ou une version plus récente !"), ("pull_group_failed_tip", "Échec de l'actualisation du groupe"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index f9f7051ae..3c3e50205 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 6a8f47b85..d162971b9 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Periksa pembaruan aplikasi saat sistem dinyalakan."), ("upgrade_rustdesk_server_pro_to_{}_tip", "Silahkan perbarui RustDesk Server Pro ke versi {} atau yang lebih baru!"), ("pull_group_failed_tip", "Gagal memperbarui grup"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 854b4a9c0..d21870c26 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -556,6 +556,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "All'avvio verifica presenza aggiornamenti programma"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Aggiorna RustDesk Server Pro alla versione {} o successiva!"), ("pull_group_failed_tip", "Impossibile aggiornare il gruppo"), - ("Filter by intersection", "Filtra per incrocio") + ("Filter by intersection", "Filtra per incrocio"), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 48b4f28ae..61dafdb34 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 00a4012e8..f4c9076ca 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index d7481eaff..20efc25c4 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 9e63f6160..c360d3ecb 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 684f9393a..9d72e407a 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Startējot pārbaudīt, vai nav programmatūras atjauninājumu"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Lūdzu, jauniniet RustDesk Server Pro uz versiju {} vai jaunāku!"), ("pull_group_failed_tip", "Neizdevās atsvaidzināt grupu"), - ("Filter by intersection", "Filtrēt pēc krustpunkta") + ("Filter by intersection", "Filtrēt pēc krustpunkta"), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 93967ebad..3b30015c3 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Checken voor updates bij opstarten"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Upgrade RustDesk Server Pro naar versie {} of nieuwer!"), ("pull_group_failed_tip", "Vernieuwen van groep mislukt"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index d6c4f5b84..77b3204b8 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Sprawdź aktualizacje przy starcie programu"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Proszę zaktualizować RustDesk Server Pro do wersji {} lub nowszej!"), ("pull_group_failed_tip", "Błąd odświeżania grup"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 8712ac615..93d20600b 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index f2810f76c..62e2ef812 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 73ff3bb22..6d755a802 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 1d7c8cfca..22e920b8e 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Проверять обновления программы при запуске"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Обновите RustDesk Server Pro до версии {} или новее!"), ("pull_group_failed_tip", "Невозможно обновить группу"), - ("Filter by intersection", "Фильтровать по пересечению") + ("Filter by intersection", "Фильтровать по пересечению"), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 95b808fa7..3f0ad7bb3 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 88c4c35e6..4d05f7e1b 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index e63dadfe0..ce69547d3 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index a51e36526..d1e5cd206 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index e0fd1086b..7deaac905 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index dfd4b9651..f3187966e 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 4ed4dd76c..2b2f63d34 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "ตรวจสอบการอัปเดตโปรแกรมเมื่อเริ่มต้นใช้งาน"), ("upgrade_rustdesk_server_pro_to_{}_tip", "กรุณาอัปเดต Rustdesk Server Pro ไปยังเวอร์ชัน {} หรือใหม่กว่า!"), ("pull_group_failed_tip", "การเรียกใช้งานกลุ่มล้มเหลว"), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6ce86e6f3..69de33892 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index a9fc78e99..15c404937 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 4e4c29e0c..d3b3b9181 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 88d42cd08..e29da9ae0 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -555,6 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", ""), ("upgrade_rustdesk_server_pro_to_{}_tip", ""), ("pull_group_failed_tip", ""), - ("Filter by intersection", "") + ("Filter by intersection", ""), + ("Remove wallpaper during incoming sessions", ""), + ("Test", ""), ].iter().cloned().collect(); } diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 0f926c469..a4975d3aa 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -5,7 +5,9 @@ use desktop::Desktop; use hbb_common::config::CONFIG_OPTION_ALLOW_LINUX_HEADLESS; pub use hbb_common::platform::linux::*; use hbb_common::{ - allow_err, bail, + allow_err, + anyhow::anyhow, + bail, config::Config, libc::{c_char, c_int, c_long, c_void}, log, @@ -26,6 +28,7 @@ use std::{ time::{Duration, Instant}, }; use users::{get_user_by_name, os::unix::UserExt}; +use wallpaper; type Xdo = *const c_void; @@ -1311,3 +1314,41 @@ NoDisplay=false } Ok(()) } + +pub struct WallPaperRemover { + old_path: String, + old_path_dark: Option, // ubuntu 22.04 light/dark theme have different uri +} + +impl WallPaperRemover { + pub fn new() -> ResultType { + let start = std::time::Instant::now(); + let old_path = wallpaper::get().map_err(|e| anyhow!(e.to_string()))?; + let old_path_dark = wallpaper::get_dark().ok(); + if old_path.is_empty() && old_path_dark.clone().unwrap_or_default().is_empty() { + bail!("already solid color"); + } + wallpaper::set_from_path("").map_err(|e| anyhow!(e.to_string()))?; + wallpaper::set_dark_from_path("").ok(); + log::info!( + "created wallpaper remover, old_path:{:?}, old_path_dark:{:?}, elapsed:{:?}", + old_path, + old_path_dark, + start.elapsed(), + ); + Ok(Self { + old_path, + old_path_dark, + }) + } +} + +impl Drop for WallPaperRemover { + fn drop(&mut self) { + allow_err!(wallpaper::set_from_path(&self.old_path).map_err(|e| anyhow!(e.to_string()))); + if let Some(old_path_dark) = &self.old_path_dark { + allow_err!(wallpaper::set_dark_from_path(old_path_dark.as_str()) + .map_err(|e| anyhow!(e.to_string()))); + } + } +} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index a74cbf896..9cc4fd39f 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -14,6 +14,7 @@ use hbb_common::{ message_proto::Resolution, sleep, timeout, tokio, }; +use std::process::{Command, Stdio}; use std::{ collections::HashMap, ffi::OsString, @@ -26,6 +27,7 @@ use std::{ sync::{atomic::Ordering, Arc, Mutex}, time::{Duration, Instant}, }; +use wallpaper; use winapi::{ ctypes::c_void, shared::{minwindef::*, ntdef::NULL, windef::*, winerror::*}, @@ -2335,3 +2337,98 @@ fn get_license() -> Option { } Some(lic) } + +fn get_sid_of_user(username: &str) -> ResultType { + let mut output = Command::new("wmic") + .args(&[ + "useraccount", + "where", + &format!("name='{}'", username), + "get", + "sid", + "/value", + ]) + .creation_flags(CREATE_NO_WINDOW) + .stdout(Stdio::piped()) + .spawn()? + .stdout + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to open stdout"))?; + let mut result = String::new(); + output.read_to_string(&mut result)?; + let sid_start_index = result + .find('=') + .map(|i| i + 1) + .ok_or(anyhow!("bad output format"))?; + if sid_start_index > 0 && sid_start_index < result.len() + 1 { + Ok(result[sid_start_index..].trim().to_string()) + } else { + bail!("bad output format"); + } +} + +pub struct WallPaperRemover { + old_path: String, +} + +impl WallPaperRemover { + pub fn new() -> ResultType { + let start = std::time::Instant::now(); + if !Self::need_remove() { + bail!("already solid color"); + } + let old_path = match Self::get_recent_wallpaper() { + Ok(old_path) => old_path, + Err(e) => { + log::info!("Failed to get recent wallpaper:{:?}, use fallback", e); + wallpaper::get().map_err(|e| anyhow!(e.to_string()))? + } + }; + Self::set_wallpaper(None)?; + log::info!( + "created wallpaper remover, old_path:{:?}, elapsed:{:?}", + old_path, + start.elapsed(), + ); + Ok(Self { old_path }) + } + + fn get_recent_wallpaper() -> ResultType { + // SystemParametersInfoW may return %appdata%\Microsoft\Windows\Themes\TranscodedWallpaper, not real path and may not real cache + // https://www.makeuseof.com/find-desktop-wallpapers-file-location-windows-11/ + // https://superuser.com/questions/1218413/write-to-current-users-registry-through-a-different-admin-account + let (hkcu, sid) = if is_root() { + let username = get_active_username(); + let sid = get_sid_of_user(&username)?; + log::info!("username:{username}, sid:{sid}"); + (RegKey::predef(HKEY_USERS), format!("{}\\", sid)) + } else { + (RegKey::predef(HKEY_CURRENT_USER), "".to_string()) + }; + let explorer_key = hkcu.open_subkey_with_flags( + &format!( + "{}Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Wallpapers", + sid + ), + KEY_READ, + )?; + Ok(explorer_key.get_value("BackgroundHistoryPath0")?) + } + + fn need_remove() -> bool { + if let Ok(wallpaper) = wallpaper::get() { + return !wallpaper.is_empty(); + } + false + } + + fn set_wallpaper(path: Option) -> ResultType<()> { + wallpaper::set_from_path(&path.unwrap_or_default()).map_err(|e| anyhow!(e.to_string())) + } +} + +impl Drop for WallPaperRemover { + fn drop(&mut self) { + // If the old background is a slideshow, it will be converted into an image. AnyDesk does the same. + allow_err!(Self::set_wallpaper(Some(self.old_path.clone()))); + } +} diff --git a/src/server/connection.rs b/src/server/connection.rs index 8e08fa5a8..fa2b8261b 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -6,6 +6,8 @@ use crate::common::update_clipboard; #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] use crate::platform::linux_desktop_manager; +#[cfg(any(target_os = "windows", target_os = "linux"))] +use crate::platform::WallPaperRemover; #[cfg(windows)] use crate::portable_service::client as portable_client; use crate::{ @@ -60,8 +62,14 @@ lazy_static::lazy_static! { static ref LOGIN_FAILURES: Arc::>> = Default::default(); static ref SESSIONS: Arc::>> = Default::default(); static ref ALIVE_CONNS: Arc::>> = Default::default(); + static ref AUTHED_CONNS: Arc::>> = Default::default(); static ref SWITCH_SIDES_UUID: Arc::>> = Default::default(); } + +#[cfg(any(target_os = "windows", target_os = "linux"))] +lazy_static::lazy_static! { + static ref WALLPAPER_REMOVER: Arc>> = Default::default(); +} pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0); #[cfg(not(any(target_os = "android", target_os = "ios")))] pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0); @@ -143,6 +151,13 @@ struct StartCmIpcPara { tx_cm_stream_ready: mpsc::Sender<()>, } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum AuthConnType { + Remote, + FileTransfer, + PortForward, +} + pub struct Connection { inner: ConnInner, stream: super::Stream, @@ -205,6 +220,7 @@ pub struct Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] start_cm_ipc_para: Option, auto_disconnect_timer: Option<(Instant, u64)>, + authed_conn_id: Option, } impl ConnInner { @@ -345,6 +361,7 @@ impl Connection { tx_cm_stream_ready, }), auto_disconnect_timer: None, + authed_conn_id: None, }; let addr = hbb_common::try_into_v4(addr); if !conn.on_open(addr).await { @@ -976,13 +993,17 @@ impl Connection { if self.authorized { return; } - let conn_type = if self.file_transfer.is_some() { - 1 + let (conn_type, auth_conn_type) = if self.file_transfer.is_some() { + (1, AuthConnType::FileTransfer) } else if self.port_forward_socket.is_some() { - 2 + (2, AuthConnType::PortForward) } else { - 0 + (0, AuthConnType::Remote) }; + self.authed_conn_id = Some(self::raii::AuthedConnID::new( + self.inner.id(), + auth_conn_type, + )); self.post_conn_audit( json!({"peer": ((&self.lr.my_id, &self.lr.my_name)), "type": conn_type}), ); @@ -1117,6 +1138,7 @@ impl Connection { *super::video_service::LAST_SYNC_DISPLAYS.write().unwrap() = displays; } } + Self::on_remote_authorized(); } let mut msg_out = Message::new(); msg_out.set_login_response(res); @@ -1155,6 +1177,29 @@ impl Connection { } } + fn on_remote_authorized() { + use std::sync::Once; + static ONCE: Once = Once::new(); + #[cfg(any(target_os = "windows", target_os = "linux"))] + if !Config::get_option("allow-remove-wallpaper").is_empty() { + // multi connections set once + let mut wallpaper = WALLPAPER_REMOVER.lock().unwrap(); + if wallpaper.is_none() { + match crate::platform::WallPaperRemover::new() { + Ok(remover) => { + *wallpaper = Some(remover); + ONCE.call_once(|| { + shutdown_hooks::add_shutdown_hook(shutdown_hook); + }); + } + Err(e) => { + log::info!("create wallpaper remover failed:{:?}", e); + } + } + } + } + } + fn peer_keyboard_enabled(&self) -> bool { self.keyboard && !self.disable_keyboard } @@ -2734,6 +2779,11 @@ impl LinuxHeadlessHandle { } } +#[cfg(any(target_os = "windows", target_os = "linux"))] +extern "C" fn shutdown_hook() { + *WALLPAPER_REMOVER.lock().unwrap() = None; +} + mod raii { use super::*; pub struct ConnectionID(i32); @@ -2767,4 +2817,26 @@ mod raii { .on_connection_close(self.0); } } + + pub struct AuthedConnID(i32); + + impl AuthedConnID { + pub fn new(id: i32, conn_type: AuthConnType) -> Self { + AUTHED_CONNS.lock().unwrap().push((id, conn_type)); + Self(id) + } + } + + impl Drop for AuthedConnID { + fn drop(&mut self) { + let mut lock = AUTHED_CONNS.lock().unwrap(); + lock.retain(|&c| c.0 != self.0); + if lock.iter().filter(|c| c.1 == AuthConnType::Remote).count() == 0 { + #[cfg(any(target_os = "windows", target_os = "linux"))] + { + *WALLPAPER_REMOVER.lock().unwrap() = None; + } + } + } + } } diff --git a/src/tray.rs b/src/tray.rs index fc124e6c4..7b05be101 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -65,14 +65,14 @@ pub fn make_tray() -> hbb_common::ResultType<()> { ) } }; - let tray_icon = Some( + let _tray_icon = Some( TrayIconBuilder::new() .with_menu(Box::new(tray_menu)) .with_tooltip(tooltip(0)) .with_icon(icon) .build()?, ); - let tray_icon = Arc::new(Mutex::new(tray_icon)); + let _tray_icon = Arc::new(Mutex::new(_tray_icon)); let menu_channel = MenuEvent::receiver(); let tray_channel = TrayEvent::receiver(); @@ -149,7 +149,7 @@ pub fn make_tray() -> hbb_common::ResultType<()> { if let Ok(data) = ipc_receiver.try_recv() { match data { Data::ControlledSessionCount(count) => { - tray_icon + _tray_icon .lock() .unwrap() .as_mut() diff --git a/src/ui/index.tis b/src/ui/index.tis index 9d09dd7a7..67deed7d7 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -217,6 +217,7 @@ class Enhancements: Reactor.Component { {has_hwcodec ?
  • {svg_checkmark}{translate("Hardware Codec")} (beta)
  • : ""}
  • {svg_checkmark}{translate("Adaptive bitrate")} (beta)
  • {translate("Recording")}
  • + {is_osx ? "" :
  • {svg_checkmark}{translate("Remove wallpaper during incoming sessions")}
  • } ; } @@ -226,6 +227,9 @@ class Enhancements: Reactor.Component { if (el.id && el.id.indexOf("enable-") == 0) { var enabled = handler.get_option(el.id) != "N"; el.attributes.toggleClass("selected", enabled); + } else if (el.id && el.id.indexOf("allow-") == 0) { + var enabled = handler.get_option(el.id) == "Y"; + el.attributes.toggleClass("selected", enabled); } } @@ -235,6 +239,8 @@ class Enhancements: Reactor.Component { var v = me.id; if (v.indexOf("enable-") == 0) { handler.set_option(v, handler.get_option(v) != 'N' ? 'N' : ''); + } else if (v.indexOf("allow-") == 0) { + handler.set_option(v, handler.get_option(v) == 'Y' ? '' : 'Y'); } else if (v == 'screen-recording') { var dir = handler.get_option("video-save-directory"); if (!dir) dir = handler.default_video_save_directory();