use super::Desktop;
use std::error::Error;
use std::io::BufRead;
use std::path::PathBuf;
use std::process::Command;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DesktopEnvt {
GNOME,
Cinnamon,
MATE,
XFCE,
Deepin,
KDE,
BSPWM,
I3,
}
impl Desktop for DesktopEnvt {
fn new() -> Result<Self, Box<dyn Error>> {
let desktop = std::env::var("XDG_CURRENT_DESKTOP")?;
if is_gnome_compliant(&desktop) {
Ok(DesktopEnvt::GNOME)
} else {
Ok(match &desktop[..] {
"X-Cinnamon" => DesktopEnvt::Cinnamon,
"MATE" => DesktopEnvt::MATE,
"XFCE" => DesktopEnvt::XFCE,
"Deepin" => DesktopEnvt::Deepin,
"KDE" => DesktopEnvt::KDE,
"bspwm" => DesktopEnvt::BSPWM,
"i3" => DesktopEnvt::I3,
_ => panic!("Unsupported Desktop Environment"),
})
}
}
fn set_wallpaper(&self, path: &str) -> Result<(), Box<dyn Error>> {
let path = enquote::enquote('"', &format!("{}", path));
match self {
DesktopEnvt::GNOME => {
Command::new("gsettings")
.args(&["set", "org.gnome.desktop.background", "picture-uri", &path])
.output()?;
}
DesktopEnvt::Cinnamon => {
Command::new("dconf")
.args(&[
"write",
"/org/cinnamon/desktop/background/picture-uri",
&path,
])
.output()?;
}
DesktopEnvt::MATE => {
let mate_path = path.replace("file://", "");
Command::new("dconf")
.args(&[
"write",
"/org/mate/desktop/background/picture-filename",
&mate_path,
])
.output()?;
}
DesktopEnvt::XFCE => {
let path_unquoted = enquote::unquote(&path).unwrap();
let xfce_path = path_unquoted
.strip_prefix("file://")
.unwrap();
let values_raw = Command::new("xfconf-query")
.args(&[
"-c",
"xfce4-desktop",
"-p",
"/backdrop/screen0",
"-lv",
])
.output()
.unwrap()
.stdout;
let values_str = match std::str::from_utf8(&values_raw) {
Ok(v) => v.to_string(),
Err(_) => "/backdrop/screen0/monitor0/workspace0/last-image".to_string(),
};
let values_vec: Vec<&str> = values_str
.split_whitespace()
.step_by(2)
.filter(|v| v.contains("last-image"))
.collect();
for v in values_vec {
Command::new("xfconf-query")
.args(&[
"-c",
"xfce4-desktop",
"-p",
v,
"-s",
&xfce_path,
])
.output()?;
}
}
DesktopEnvt::Deepin => {
Command::new("dconf")
.args(&[
"write",
"/com/deepin/wrap/gnome/desktop/background/picture-uri",
&path,
])
.output()?;
}
DesktopEnvt::KDE => {
let kde_set_arg = format!(
r#"
const monitors = desktops()
for (var i = 0; i < monitors.length; i++) {{
monitors[i].wallpaperPlugin = "org.kde.image"
monitors[i].currentConfigGroup = ["Wallpaper"]
monitors[i].writeConfig("Image", {})
}}"#,
&path
);
Command::new("qdbus")
.args(&[
"org.kde.plasmashell",
"/PlasmaShell",
"org.kde.PlasmaShell.evaluateScript",
&kde_set_arg,
])
.output()?;
}
DesktopEnvt::BSPWM | DesktopEnvt::I3 => {
Command::new("feh")
.args(&["--bg-fill", &path.replace("\"", "")])
.output()?;
}
}
Ok(())
}
fn get_wallpaper(&self) -> Result<PathBuf, Box<dyn Error>> {
let output = match self {
DesktopEnvt::GNOME => Command::new("gsettings")
.args(&["get", "org.gnome.desktop.background", "picture-uri"])
.output()?,
DesktopEnvt::Cinnamon => Command::new("dconf")
.arg("read")
.arg("/org/cinnamon/desktop/background/picture-uri")
.output()?,
DesktopEnvt::MATE => Command::new("dconf")
.args(&["read", "/org/mate/desktop/background/picture-filename"])
.output()?,
DesktopEnvt::XFCE => Command::new("xfconf-query")
.args(&[
"-c",
"xfce4-desktop",
"-p",
"/backdrop/screen0/monitor0/workspace0/last-image",
])
.output()?,
DesktopEnvt::Deepin => Command::new("dconf")
.args(&[
"read",
"/com/deepin/wrap/gnome/desktop/background/picture-uri",
])
.output()?,
DesktopEnvt::KDE => return Ok(kde_get_wallpaper()?),
DesktopEnvt::BSPWM | DesktopEnvt::I3 => Command::new("sed")
.args(&[
"-n",
"'s/feh.*\\('.*'\\)/\\1/gp'",
&format!("/home/{}/.fehbg", std::env::var("USER")?.trim()),
])
.output()?,
};
let output = enquote::unquote(String::from_utf8(output.stdout)?.trim().into())?;
Ok(PathBuf::from(output))
}
}
fn is_gnome_compliant(desktop: &str) -> bool {
desktop.contains("GNOME") || desktop == "Unity" || desktop == "Pantheon"
}
fn kde_get_wallpaper() -> Result<PathBuf, Box<dyn Error>> {
let mut path = dirs_next::config_dir().ok_or("Could not determine config directory")?;
path.push("plasma-org.kde.plasma.desktop-appletsrc");
let file = std::fs::File::open(path)?;
let reader = std::io::BufReader::new(file);
for line in reader.lines() {
let line = line?;
if line.starts_with("Image=") {
let mut line = line[6..].trim();
if line.starts_with("file://") {
line = &line[7..];
}
return Ok(PathBuf::from(line));
}
}
Err("KDE Image not found".into())
}