leenfetch_core/modules/linux/desktop/
de.rs1use std::env;
2use std::process::Command;
3
4pub fn get_de(show_version: bool, wm: Option<&str>) -> Option<String> {
5 let mut de = detect_de_env().or_else(detect_de_fallback)?;
6
7 if let Some(wm_name) = wm && de.eq_ignore_ascii_case(wm_name) {
9 return None;
10 }
11
12 normalize_de_name(&mut de);
13
14 if show_version && let Some(ver) = get_de_version(&de) {
16 de = format!("{} {}", de, ver);
17 }
18
19 if env::var_os("WAYLAND_DISPLAY").is_some() {
21 de.push_str(" (Wayland)");
22 }
23
24 Some(de)
25}
26
27fn detect_de_env() -> Option<String> {
29 if let Some(val) = env::var_os("DESKTOP_SESSION") {
30 let val_str = val.to_string_lossy();
31 return Some(if val_str.contains("regolith") {
32 "Regolith".into()
33 } else {
34 val_str.into()
35 });
36 }
37
38 if let Some(val) = env::var_os("XDG_CURRENT_DESKTOP") {
39 let val_str = val
40 .to_string_lossy()
41 .replace("X-", "")
42 .replace("Budgie:GNOME", "Budgie");
43 return Some(val_str);
44 }
45
46 None
47}
48
49fn detect_de_fallback() -> Option<String> {
51 if env::var_os("GNOME_DESKTOP_SESSION_ID").is_some() {
52 return Some("GNOME".into());
53 }
54 if env::var_os("MATE_DESKTOP_SESSION_ID").is_some() {
55 return Some("MATE".into());
56 }
57 if env::var_os("TDE_FULL_SESSION").is_some() {
58 return Some("Trinity".into());
59 }
60
61 if env::var_os("DISPLAY").is_some() && is_installed("xprop") {
63 let output = run_command("xprop", &["-root"])?;
64 if output.contains("KDE_SESSION_VERSION") {
65 return Some("KDE".into());
66 }
67 if output.contains("_MUFFIN") {
68 return Some("Cinnamon".into());
69 }
70 if output.contains("xfce") {
71 return Some("Xfce".into());
72 }
73 }
74
75 None
76}
77
78fn normalize_de_name(de: &mut String) {
80 let lower = de.to_lowercase();
81 *de = match lower.as_str() {
82 s if s.contains("xfce4") => "Xfce4",
83 s if s.contains("xfce5") => "Xfce5",
84 s if s.contains("xfce") => "Xfce",
85 s if s.contains("mate") => "MATE",
86 s if s.contains("gnome") => "GNOME",
87 s if s.contains("muffin") => "Cinnamon",
88 s if s.contains("budgie") => "Budgie",
89 s if s.contains("lxqt") => "LXQt",
90 s if s.contains("plasma") || s.contains("kde") => "Plasma",
91 s if s.contains("unity") => "Unity",
92 _ => de.as_str(),
93 }
94 .to_string();
95}
96
97fn is_installed(cmd: &str) -> bool {
98 if let Ok(path) = std::env::var("PATH") {
100 for dir in path.split(':') {
101 let cmd_path = std::path::Path::new(dir).join(cmd);
102 if cmd_path.exists() {
103 return true;
104 }
105 }
106 }
107 false
108}
109
110fn run_command(cmd: &str, args: &[&str]) -> Option<String> {
111 Command::new(cmd)
112 .args(args)
113 .output()
114 .ok()
115 .filter(|o| o.status.success())
116 .map(|o| String::from_utf8_lossy(&o.stdout).to_string())
117}
118
119fn get_de_version(de: &str) -> Option<String> {
120 match de {
121 "Plasma" => parse_version("plasmashell", &["--version"]),
122 "MATE" => parse_version("mate-session", &["--version"]),
123 "Xfce" | "Xfce4" => parse_version("xfce4-session", &["--version"]),
124 "GNOME" => parse_version("gnome-shell", &["--version"]),
125 "Cinnamon" => parse_version("cinnamon", &["--version"]),
126 "Budgie" => parse_version("budgie-desktop", &["--version"]),
127 "LXQt" => parse_version("lxqt-session", &["--version"]),
128 "Lumina" => parse_version("lumina-desktop", &["--version"]),
129 "Trinity" => parse_version("tde-config", &["--version"]),
130 "Unity" => parse_version("unity", &["--version"]),
131 _ => None,
132 }
133}
134
135fn parse_version(cmd: &str, args: &[&str]) -> Option<String> {
136 run_command(cmd, args).and_then(|out| {
137 out.lines().rev().find_map(|line| {
138 line.split_whitespace()
139 .find(|s| {
140 s.chars()
141 .next()
142 .map(|c| c.is_ascii_digit())
143 .unwrap_or(false)
144 })
145 .map(|s| s.to_string())
146 })
147 })
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use crate::test_utils::EnvLock;
154
155 fn clear_env() -> EnvLock {
156 let vars = [
157 "DESKTOP_SESSION",
158 "XDG_CURRENT_DESKTOP",
159 "GNOME_DESKTOP_SESSION_ID",
160 "MATE_DESKTOP_SESSION_ID",
161 "TDE_FULL_SESSION",
162 "WAYLAND_DISPLAY",
163 "DISPLAY",
164 ];
165 let env_lock = EnvLock::acquire(&vars);
166 for var in vars {
167 env_lock.remove_var(var);
168 }
169 env_lock
170 }
171
172 #[test]
221 fn excludes_wm_that_matches_de() {
222 let env_lock = clear_env();
223 env_lock.set_var("DESKTOP_SESSION", "sway");
224 let result = get_de(false, Some("sway"));
225 assert_eq!(result, None);
226 drop(env_lock);
227 }
228
229 #[test]
239 fn normalize_de_variants() {
240 let mut de = "xfce".to_string();
241 normalize_de_name(&mut de);
242 assert_eq!(de, "Xfce");
243
244 let mut de = "Xfce4".to_string();
245 normalize_de_name(&mut de);
246 assert_eq!(de, "Xfce4");
247
248 let mut de = "mate".to_string();
249 normalize_de_name(&mut de);
250 assert_eq!(de, "MATE");
251
252 let mut de = "gnome".to_string();
253 normalize_de_name(&mut de);
254 assert_eq!(de, "GNOME");
255
256 let mut de = "lxqt".to_string();
257 normalize_de_name(&mut de);
258 assert_eq!(de, "LXQt");
259
260 let mut de = "plasma-kde".to_string();
261 normalize_de_name(&mut de);
262 assert_eq!(de, "Plasma");
263 }
264}