win,linux remove desktop wallpaper

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-10-11 19:03:34 +08:00
parent 1be5f2d647
commit d3ce8203be
45 changed files with 453 additions and 45 deletions

23
Cargo.lock generated
View File

@ -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"

View File

@ -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" }

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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"),
("Filter by intersection", "")
("Filter by intersection", ""),
("Remove wallpaper during incoming sessions", ""),
("Test", ""),
].iter().cloned().collect();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -555,6 +555,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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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<String>, // ubuntu 22.04 light/dark theme have different uri
}
impl WallPaperRemover {
pub fn new() -> ResultType<Self> {
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())));
}
}
}

View File

@ -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<License> {
}
Some(lic)
}
fn get_sid_of_user(username: &str) -> ResultType<String> {
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<Self> {
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<String> {
// 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<String>) -> 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())));
}
}

View File

@ -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::<Mutex<HashMap<String, (i32, i32, i32)>>> = Default::default();
static ref SESSIONS: Arc::<Mutex<HashMap<String, Session>>> = Default::default();
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType)>>> = Default::default();
static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
lazy_static::lazy_static! {
static ref WALLPAPER_REMOVER: Arc<Mutex<Option<WallPaperRemover>>> = 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<StartCmIpcPara>,
auto_disconnect_timer: Option<(Instant, u64)>,
authed_conn_id: Option<self::raii::AuthedConnID>,
}
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;
}
}
}
}
}

View File

@ -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()

View File

@ -217,6 +217,7 @@ class Enhancements: Reactor.Component {
{has_hwcodec ? <li #enable-hwcodec><span>{svg_checkmark}</span>{translate("Hardware Codec")} (beta)</li> : ""}
<li #enable-abr><span>{svg_checkmark}</span>{translate("Adaptive bitrate")} (beta)</li>
<li #screen-recording>{translate("Recording")}</li>
{is_osx ? "" : <li #allow-remove-wallpaper><span>{svg_checkmark}</span>{translate("Remove wallpaper during incoming sessions")}</li>}
</menu>
</li>;
}
@ -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();