2f4f1c64d2
- Replace .map().unwrap_or(false) with .is_some_and()/.is_ok_and()
- Use path.display() instead of {:?} for user-facing messages
- Replace Option<Option<Vec<String>>> with GamescopeUpdate enum
- Replace manual parent-walking loops with .ancestors() iterators
- Simplify kill()/kill_all() signatures to return () instead of Result
- Use tokio::task::spawn_blocking instead of hand-rolled thread+oneshot
- Read /proc/self/status for UID instead of spawning id subprocess
- Build Exec= line directly in render_desktop instead of string-replace
- Bump PKGBUILD pkgrel to 6
60 lines
2.1 KiB
Rust
60 lines
2.1 KiB
Rust
/// Run a blocking closure on the tokio blocking thread pool and await its result.
|
|
/// Used to offload blocking work (HTTP, disk, process spawning) without
|
|
/// stalling the iced event loop.
|
|
pub async fn async_blocking<T, F>(f: F) -> T
|
|
where
|
|
T: Send + 'static,
|
|
F: FnOnce() -> T + Send + 'static,
|
|
{
|
|
tokio::task::spawn_blocking(f)
|
|
.await
|
|
.expect("blocking task panicked")
|
|
}
|
|
|
|
/// Open a native folder picker dialog and return the chosen path, or None if
|
|
/// the user cancelled. Tries zenity (GNOME/GTK) then kdialog (KDE) in order.
|
|
pub fn pick_folder(title: &str) -> Option<String> {
|
|
for (cmd, args) in [
|
|
("zenity", vec!["--file-selection", "--directory", "--title", title]),
|
|
("kdialog", vec!["--getexistingdirectory", "/home", "--title", title]),
|
|
] {
|
|
let Ok(out) = std::process::Command::new(cmd).args(&args).output() else {
|
|
continue;
|
|
};
|
|
if out.status.success() {
|
|
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
|
|
if !s.is_empty() {
|
|
return Some(s);
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Open a native file picker dialog starting in `start_dir`, or None if
|
|
/// the user cancelled. Tries zenity then kdialog.
|
|
pub fn pick_file(title: &str, start_dir: &str) -> Option<String> {
|
|
// zenity uses --filename with a trailing slash to open a directory
|
|
let start_slash = format!("{}/", start_dir.trim_end_matches('/'));
|
|
let zenity_args = vec![
|
|
"--file-selection",
|
|
"--title",
|
|
title,
|
|
"--filename",
|
|
&start_slash,
|
|
];
|
|
let kdialog_args = vec!["--getopenfilename", start_dir, "--title", title];
|
|
for (cmd, args) in [("zenity", zenity_args.as_slice()), ("kdialog", kdialog_args.as_slice())] {
|
|
let Ok(out) = std::process::Command::new(cmd).args(args).output() else {
|
|
continue;
|
|
};
|
|
if out.status.success() {
|
|
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
|
|
if !s.is_empty() {
|
|
return Some(s);
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|