f170171895
GUI dashboard (gui.rs): - Add detect, diagnose, settings panel, per-launcher games management - Async Kill with optimistic UI state and rollback on error - Settings: pick_list for Proton version, browse button for compat dir, validation, per-launcher version badge - Detect Installed button with scan results in footer - Diagnose card with ✓/✗ checklist per launcher Issue #1 — Use System Proton (proton.rs): - Extend list_installed() to scan ~/.steam/root/compatibilitytools.d, ~/.local/share/Steam/compatibilitytools.d, and /usr/share/steam/compatibilitytools.d in addition to the configured compat dir; deduplicates by name so the same version never appears twice Issue #4 — Remove Systemd Service (service.rs): - Replace systemd unit management with XDG autostart: install() writes ~/.config/autostart/umutray.desktop instead of a systemd unit and never calls systemctl; uninstall() removes that file; status() checks whether the autostart entry exists - Update GUI service_is_installed() to check the XDG autostart path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
123 lines
4.0 KiB
Rust
123 lines
4.0 KiB
Rust
use anyhow::{Context, Result};
|
|
use owo_colors::OwoColorize;
|
|
use std::path::PathBuf;
|
|
|
|
const DESKTOP_NAME: &str = "umutray.desktop";
|
|
|
|
fn home() -> Result<PathBuf> {
|
|
dirs::home_dir().context("Cannot determine home directory")
|
|
}
|
|
|
|
fn autostart_path() -> Result<PathBuf> {
|
|
Ok(home()?.join(".config/autostart").join(DESKTOP_NAME))
|
|
}
|
|
|
|
fn desktop_path() -> Result<PathBuf> {
|
|
Ok(home()?.join(".local/share/applications").join(DESKTOP_NAME))
|
|
}
|
|
|
|
fn render_desktop(exe: &std::path::Path, autostart: bool) -> String {
|
|
let mut s = format!(
|
|
"[Desktop Entry]\n\
|
|
Name=umutray\n\
|
|
Comment=Wine launcher manager for Windows game launchers\n\
|
|
Exec={exe}\n\
|
|
Icon=applications-games\n\
|
|
Type=Application\n\
|
|
Categories=Game;\n\
|
|
Keywords=wine;proton;gaming;launcher;\n\
|
|
StartupNotify=false\n",
|
|
exe = exe.display(),
|
|
);
|
|
if autostart {
|
|
s.push_str("X-GNOME-Autostart-enabled=true\n");
|
|
s.push_str("Hidden=false\n");
|
|
} else {
|
|
// App-menu entry launches the GUI
|
|
s = s.replace(
|
|
&format!("Exec={}", exe.display()),
|
|
&format!("Exec={} gui", exe.display()),
|
|
);
|
|
s.push_str("StartupNotify=true\n");
|
|
}
|
|
s
|
|
}
|
|
|
|
/// Install only the .desktop file so umutray appears in the app menu.
|
|
/// Called automatically on first `umutray gui` run.
|
|
pub fn install_desktop() -> Result<()> {
|
|
let exe = std::env::current_exe().context("Cannot determine path to own executable")?;
|
|
let desktop = desktop_path()?;
|
|
if let Some(p) = desktop.parent() {
|
|
std::fs::create_dir_all(p).with_context(|| format!("Failed to create {p:?}"))?;
|
|
}
|
|
std::fs::write(&desktop, render_desktop(&exe, false))
|
|
.with_context(|| format!("Failed to write desktop file {desktop:?}"))?;
|
|
println!("{} App menu entry written: {}", "✓".green().bold(), desktop.display());
|
|
Ok(())
|
|
}
|
|
|
|
/// Remove the .desktop file.
|
|
pub fn uninstall_desktop() -> Result<()> {
|
|
let desktop = desktop_path()?;
|
|
if desktop.exists() {
|
|
std::fs::remove_file(&desktop)
|
|
.with_context(|| format!("Failed to remove {desktop:?}"))?;
|
|
println!("Removed {}", desktop.display());
|
|
} else {
|
|
println!("No desktop file at {}", desktop.display());
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Write an XDG autostart entry and the app-menu .desktop file.
|
|
pub fn install() -> Result<()> {
|
|
let exe = std::env::current_exe().context("Cannot determine path to own executable")?;
|
|
|
|
// XDG autostart
|
|
let autostart = autostart_path()?;
|
|
if let Some(p) = autostart.parent() {
|
|
std::fs::create_dir_all(p).with_context(|| format!("Failed to create {p:?}"))?;
|
|
}
|
|
std::fs::write(&autostart, render_desktop(&exe, true))
|
|
.with_context(|| format!("Failed to write autostart file {autostart:?}"))?;
|
|
println!("Wrote autostart: {}", autostart.display());
|
|
|
|
// App-menu entry
|
|
install_desktop()?;
|
|
|
|
println!();
|
|
println!("{} Autostart installed.", "✓".green().bold());
|
|
println!(" umutray will start with your next graphical session.");
|
|
println!(" To start now: {}", exe.display());
|
|
Ok(())
|
|
}
|
|
|
|
/// Remove the XDG autostart entry and the app-menu .desktop file.
|
|
pub fn uninstall() -> Result<()> {
|
|
let autostart = autostart_path()?;
|
|
if autostart.exists() {
|
|
std::fs::remove_file(&autostart)
|
|
.with_context(|| format!("Failed to remove {autostart:?}"))?;
|
|
println!("Removed {}", autostart.display());
|
|
} else {
|
|
println!("No autostart file at {}", autostart.display());
|
|
}
|
|
|
|
uninstall_desktop()?;
|
|
|
|
println!("{} Autostart removed.", "✓".green().bold());
|
|
Ok(())
|
|
}
|
|
|
|
/// Show whether the XDG autostart entry is present.
|
|
pub fn status() -> Result<()> {
|
|
let autostart = autostart_path()?;
|
|
if autostart.exists() {
|
|
println!("{} Autostart enabled: {}", "✓".green().bold(), autostart.display());
|
|
} else {
|
|
println!("{} Autostart not installed ({})", "✗".red().bold(), autostart.display());
|
|
}
|
|
Ok(())
|
|
}
|