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