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