1use crate::traits::ToJson;
24use anyhow::Result;
25use serde::{Deserialize, Serialize};
26use std::{env, fs, path::Path, process::Command};
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct SessionInfo {
31 pub desktop: Option<String>,
33
34 pub desktop_ver: Option<String>,
36
37 pub window_manager: Option<String>,
39}
40
41impl ToJson for SessionInfo {}
42
43impl SessionInfo {
44 pub fn new() -> Result<Self> {
45 let desktop = Self::get_desktop();
46 let desktop_ver = match &desktop {
47 Some(de) => Self::get_desktop_version(de),
48 _ => None,
49 };
50
51 Ok(Self {
52 desktop: if let Some(ref de) = desktop {
53 Some(Self::format_desktop_name(de))
54 } else {
55 desktop
56 },
57 desktop_ver,
58 window_manager: None,
59 })
60 }
61
62 pub fn get_desktop() -> Option<String> {
63 if let Ok(session) = env::var("DESKTOP_SESSION") {
64 if &session == "regolith" {
65 return Some("Regolith".to_string());
66 }
67 }
68
69 if let Some(de) = Self::get_de_from_env() {
70 return Some(de);
71 }
72 if let Some(de) = Self::get_de_from_xprop()
73 && env::var("DISPLAY").is_ok()
74 {
75 return Some(de);
76 }
77 None
78 }
79
80 fn get_de_from_env() -> Option<String> {
81 if let Ok(xdg) = env::var("XDG_CURRENT_DESKTOP") {
82 let mut de = xdg.replace("X-", "");
83 de = de.replace("Budgie:GNOME", "Budgie");
84 de = de.replace(":Unity7:ubuntu", "");
85 return Some(de);
86 }
87
88 if let Ok(session) = env::var("DESKTOP_SESSION") {
89 let de = Path::new(&session)
90 .file_name()
91 .and_then(|n| n.to_str())
92 .unwrap_or(&session)
93 .to_string();
94 return Some(de);
95 }
96
97 if env::var("GNOME_DESKTOP_SESSION_ID").is_ok() {
98 return Some("GNOME".to_string());
99 }
100 if env::var("MATE_DESKTOP_SESSION_ID").is_ok() {
101 return Some("MATE".to_string());
102 }
103 if env::var("TDE_FULL_SESSION").is_ok() {
104 return Some("Trinity Desktop".to_string());
105 }
106 None
107 }
108
109 fn get_de_from_xprop() -> Option<String> {
110 let out = Command::new("xprop").arg("-root").output().ok()?;
111 let stdout = String::from_utf8_lossy(&out.stdout);
112
113 for line in stdout.lines() {
114 if line.contains("KDE_SESSION_VERSION")
115 || line.contains("_MUFFIN")
116 || line.contains("xfce")
117 {
118 return Some(line.to_string());
119 }
120 }
121 None
122 }
123
124 fn format_desktop_name(de: &str) -> String {
125 let de = de.to_string();
126
127 if de.starts_with("KDE_SESSION_VERSION") {
128 if let Some(pos) = de.find(" = ") {
129 return format!("KDE{}", &de[pos + 3..]);
130 }
131 }
132
133 if de.contains("xfce4") {
134 return "Xfce4".to_string();
135 }
136 if de.contains("xfce5") {
137 return "Xfce5".to_string();
138 }
139 if de.contains("xfce") {
140 return "Xfce".to_string();
141 }
142 if de.contains("mate") {
143 return "MATE".to_string();
144 }
145 if de.contains("GNOME") {
146 return "GNOME".to_string();
147 }
148 if de.contains("MUFFIN") {
149 return "Cinnamon".to_string();
150 }
151 de
152 }
153
154 pub fn get_desktop_version(de: &str) -> Option<String> {
155 let cmd = if de.starts_with("Plasma") {
156 Some("plasmashell")
157 } else if de.starts_with("MATE") {
158 Some("mate-session")
159 } else if de.starts_with("Xfce") {
160 Some("xfce4-session")
161 } else if de.starts_with("GNOME") {
162 Some("gnome-shell")
163 } else if de.starts_with("Cinnamom") {
164 Some("cinnamon")
165 } else if de.starts_with("Budgie") {
166 Some("budgie-desktop")
167 } else if de.starts_with("LXQt") {
168 Some("lxqt-session")
169 } else if de.starts_with("Lumina") {
170 Some("lumina-desktop")
171 } else if de.starts_with("Trinity") {
172 Some("tde-config")
173 } else if de.starts_with("Unity") {
174 Some("unity")
175 } else if de.starts_with("Deepin") {
176 if let Ok(contents) = fs::read_to_string("/etc/deepin-version") {
178 for line in contents.lines() {
179 if line.starts_with("Version=") {
180 return Some(line[8..].to_string());
181 }
182 }
183 }
184 None
185 } else {
186 None
187 };
188
189 if let Some(cmd) = cmd {
190 let out = Command::new(cmd).arg("--version").output().ok()?;
191
192 let mut version = String::from_utf8_lossy(&out.stdout).to_string();
193 if version.is_empty() {
194 version = String::from_utf8_lossy(&out.stderr).to_string();
195 }
196
197 version = version
198 .replace("TDE:", "")
199 .replace("tde-config", "")
200 .replace("liblxqt", "")
201 .replace("Copyright", "")
202 .replace(")", "");
203
204 if let Some(last) = version.split_whitespace().last() {
205 return Some(last.trim_matches('"').to_string());
206 }
207 }
208 None
209 }
210}