1#![forbid(unsafe_code)]
14
15use freedesktop_entry_parser::parse_entry;
16use ini::Ini;
17use std::{env, ffi::OsString, process::Command, str};
18
19pub fn get_icon_theme() -> Option<String> {
33 get_icon_theme_order(&[
34 Check::KDEGlobals,
35 Check::GSettings,
36 Check::GTK3,
37 Check::GTK2,
38 Check::ThemeConf,
39 ])
40}
41
42pub fn get_icon_theme_order(order: &[Check]) -> Option<String> {
46 let home_path = env::var_os("HOME")?;
47 for check in order {
48 match check {
49 Check::KDEGlobals => {
50 if let Some(s) = kde(home_path.clone()) {
51 return Some(s);
52 }
53 }
54 Check::GSettings => {
55 if let Some(s) = gsettings() {
56 return Some(s);
57 }
58 }
59 Check::GTK3 => {
60 if let Some(s) = gtk3(home_path.clone()) {
61 return Some(s);
62 }
63 }
64 Check::GTK2 => {
65 if let Some(s) = gtk2(home_path.clone()) {
66 return Some(s);
67 }
68 }
69 Check::ThemeConf => {
70 if let Some(s) = theme_conf(home_path.clone()) {
71 return Some(s);
72 }
73 }
74 }
75 }
76 None
77}
78
79pub enum Check {
81 KDEGlobals,
83 GSettings,
85 GTK3,
87 GTK2,
89 ThemeConf,
91}
92
93fn kde(home_path: OsString) -> Option<String> {
94 let mut path = conf_dir(home_path)?;
95 path.push("/kdeglobals");
96 let file = parse_entry(path).ok()?;
97 file.section("Icons").attr("Theme").map(|s| s.to_owned())
98}
99
100fn gtk2(mut home_path: OsString) -> Option<String> {
101 home_path.push("/.gtkrc-2.0");
102 let file = Ini::load_from_file(home_path).ok()?;
103 file.get_from::<String>(None, "gtk-icon-theme-name")
104 .map(|s| s.to_owned())
105}
106
107fn gtk3(home_path: OsString) -> Option<String> {
108 let mut path = conf_dir(home_path)?;
109 path.push("/gtk-3.0/settings.ini");
110 let file = Ini::load_from_file(path).ok()?;
111 file.get_from(Some("Settings"), "gtk-icon-theme-name")
112 .map(|s| s.to_owned())
113}
114
115fn gsettings() -> Option<String> {
116 let output = Command::new("gsettings")
117 .args(&["get", "org.gnome.desktop.interface", "icon-theme"])
118 .output()
119 .ok()?
120 .stdout;
121 let s = str::from_utf8(&output).ok()?;
122 let s = match s.strip_suffix('\n') {
124 Some(s) => s,
125 None => s,
126 };
127 let s = match s.strip_prefix('\'') {
128 Some(s) => s,
129 None => s,
130 };
131 let s = match s.strip_suffix('\'') {
132 Some(s) => s,
133 None => s,
134 };
135 Some(s.to_owned())
136}
137
138fn theme_conf(home_path: OsString) -> Option<String> {
139 let mut path = conf_dir(home_path)?;
140 path.push("/theme.conf");
141 let file = Ini::load_from_file(path).ok()?;
142 file.get_from(Some("Settings"), "icon-theme-name")
143 .map(|s| s.to_owned())
144}
145
146fn conf_dir(mut home_path: OsString) -> Option<OsString> {
147 match env::var_os("XDG_CONFIG_HOME") {
148 Some(s) => Some(s),
149 None => {
150 home_path.push("/.config");
151 Some(home_path)
152 }
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn kde_test() {
162 let home_path = env::var_os("HOME").unwrap();
163 let target_name = env::var("TEST_THEME").unwrap();
164 assert_eq!(kde(home_path), Some(target_name));
165 }
166
167 #[test]
168 fn gtk3_test() {
169 let home_path = env::var_os("HOME").unwrap();
170 let target_name = env::var("TEST_THEME").unwrap();
171 assert_eq!(gtk3(home_path), Some(target_name));
172 }
173
174 #[test]
175 fn gtk2_test() {
176 let home_path = env::var_os("HOME").unwrap();
177 let target_name = env::var("TEST_THEME").unwrap();
178 assert_eq!(gtk2(home_path), Some(target_name));
179 }
180
181 #[test]
182 fn gsettings_test() {
183 let target_name = env::var("TEST_THEME").unwrap();
184 assert_eq!(gsettings(), Some(target_name));
185 }
186
187 #[test]
188 fn theme_conf_test() {
189 let home_path = env::var_os("HOME").unwrap();
190 let target_name = env::var("TEST_THEME").unwrap();
191 assert_eq!(theme_conf(home_path), Some(target_name));
192 }
193}