1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use std::collections::HashMap;
use std::path::PathBuf;

use cssparser::Color;

use super::parse::{from_file, DefineColor};

#[cfg(all(unix, not(target_os = "macos")))]
/**
 * Get the current color variables applied by GTK
 *
 * Currently only supports Freedesktop platforms.
 */
pub fn current() -> (HashMap<String, Color>, Vec<Error>) {
    use std::env;

    let (mut map, mut error) = if let Ok(name) = std::env::var("GTK_THEME") {
        get_theme(&name)
    } else {
        (HashMap::new(), vec![])
    };

    get_theme_on_folder(
        &PathBuf::from(env::var("HOME").unwrap()).join(".config/gtk-4.0"),
        &mut map,
        &mut error,
    );
    (map, error)
}

pub fn get_theme(name: &str) -> (HashMap<String, Color>, Vec<Error>) {
    let mut themes = HashMap::new();
    let mut errors = vec![];

    for path in ["/usr/share/themes/", "~/.local/share/themes/", "~/.themes/"] {
        let path = PathBuf::from(path).join(name).join("gtk-4.0");

        get_theme_on_folder(&path, &mut themes, &mut errors);
    }

    (themes, errors)
}

fn push(theme: &PathBuf, themes: &mut HashMap<String, Color>, errors: &mut Vec<Error>) {
    if theme.exists() {
        match from_file(theme) {
            Ok(theme) => {
                for DefineColor {
                    ident,
                    color,
                    loc: _,
                } in theme
                {
                    themes.insert(ident, color);
                }
            }
            Err(error) => errors.push(Error::ParsingError(error)),
        };
    }
}

fn get_theme_on_folder(
    path: &PathBuf,
    themes: &mut HashMap<String, Color>,
    errors: &mut Vec<Error>,
) {
    if path.exists() {
        let normal = path.join("gtk.css");

        if normal.exists() {
            push(&normal, themes, errors);
        }

        if dark_light::detect() == dark_light::Mode::Dark {
            let dark = PathBuf::from(path).join("gtk-dark.css");

            if dark.exists() {
                push(&dark, themes, errors);
            }
        }
    }
}

#[derive(Debug)]
pub enum Error {
    ParsingError(super::parse::Error),
}