hyprshell_core_lib/
theme_icon_cache.rs

1// https://github.com/H3rmt/hyprshell/discussions/137#discussioncomment-12078216
2use std::collections::BTreeSet;
3use std::fs::read_dir;
4use std::path::{Path, PathBuf};
5use std::sync::{Mutex, OnceLock};
6use tracing::debug;
7
8fn get_icon_map() -> &'static Mutex<BTreeSet<Box<str>>> {
9    static MAP_LOCK: OnceLock<Mutex<BTreeSet<Box<str>>>> = OnceLock::new();
10    MAP_LOCK.get_or_init(|| Mutex::new(BTreeSet::new()))
11}
12
13pub fn init_icon_map(icon_names: Vec<String>, search_path: Option<Vec<PathBuf>>) {
14    let mut map = get_icon_map().lock().expect("Failed to lock icon map");
15
16    debug!("found {} icons from theme", icon_names.len());
17    for icon in icon_names {
18        map.insert(icon.into_boxed_str());
19    }
20
21    if let Some(search_path) = search_path {
22        // gtk4 only reports 500 icons for candy-theme, scan through the filesystem
23        for path in search_path {
24            if path.exists() {
25                let paths = collect_files_recursive(&path);
26                debug!("found {} icons from filesystem in {path:?}", paths.len());
27                for icon in paths {
28                    map.insert(icon);
29                }
30                return;
31            }
32        }
33    }
34}
35
36pub fn theme_has_icon_name(name: &str) -> bool {
37    let map = get_icon_map().lock().expect("Failed to lock icon map");
38    map.contains(&Box::from(name))
39}
40fn collect_files_recursive(dir: &Path) -> Vec<Box<str>> {
41    let mut files = Vec::new();
42    let mut dirs_to_visit = vec![dir.to_path_buf()];
43
44    while let Some(current_dir) = dirs_to_visit.pop() {
45        if current_dir.is_dir() {
46            if let Ok(entries) = read_dir(&current_dir) {
47                for entry in entries.flatten() {
48                    let path = entry.path();
49                    if path.is_dir() {
50                        dirs_to_visit.push(path);
51                    } else {
52                        files.push(
53                            path.file_stem()
54                                .unwrap_or_default()
55                                .to_string_lossy()
56                                .into_owned()
57                                .into_boxed_str(),
58                        );
59                    }
60                }
61            }
62        }
63    }
64
65    files
66}