pub const SYSTEM_THEME_NAME: &str = "System";
pub const SYSTEM_DARK_INDEX: usize = 0; pub const SYSTEM_LIGHT_INDEX: usize = 1;
pub fn is_system_name(name: &str) -> bool {
name.eq_ignore_ascii_case(SYSTEM_THEME_NAME)
}
pub fn system_theme_index(dark: bool) -> usize {
if dark {
SYSTEM_DARK_INDEX
} else {
SYSTEM_LIGHT_INDEX
}
}
pub fn parse_macos(out: &str) -> bool {
out.trim().eq_ignore_ascii_case("dark")
}
pub fn parse_gsettings(out: &str) -> Option<bool> {
let v = out.trim().trim_matches('\'');
match v {
"prefer-dark" => Some(true),
"prefer-light" | "default" => Some(false),
_ => None,
}
}
pub fn parse_windows(out: &str) -> Option<bool> {
let v = out.split_whitespace().last()?;
match v {
"0x0" => Some(true),
"0x1" => Some(false),
_ => None,
}
}
#[allow(dead_code)]
fn run(cmd: &str, args: &[&str]) -> Option<String> {
let o = std::process::Command::new(cmd).args(args).output().ok()?;
Some(String::from_utf8_lossy(&o.stdout).into_owned())
}
pub fn detect_system_dark() -> Option<bool> {
#[cfg(target_os = "macos")]
{
Some(parse_macos(
&run("defaults", &["read", "-g", "AppleInterfaceStyle"]).unwrap_or_default(),
))
}
#[cfg(target_os = "windows")]
{
parse_windows(&run(
"reg",
&[
"query",
r"HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
"/v",
"AppsUseLightTheme",
],
)?)
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
if let Some(d) = run(
"gsettings",
&["get", "org.gnome.desktop.interface", "color-scheme"],
)
.and_then(|o| parse_gsettings(&o))
{
return Some(d);
}
std::env::var("GTK_THEME")
.ok()
.map(|t| t.to_ascii_lowercase().contains("dark"))
}
}
pub fn current_system_theme_index() -> usize {
system_theme_index(detect_system_dark().unwrap_or(true))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn system_name_is_case_insensitive_and_not_a_preset() {
assert!(is_system_name("System") && is_system_name("system"));
assert!(!is_system_name("Nord"));
assert!(!super::super::THEME_NAMES.iter().any(|n| is_system_name(n)));
}
#[test]
fn dark_and_light_map_to_matching_presets() {
assert!(super::super::theme_by_index(system_theme_index(true)).is_dark);
assert!(!super::super::theme_by_index(system_theme_index(false)).is_dark);
}
#[test]
fn parsers() {
assert!(parse_macos("Dark\n"));
assert!(!parse_macos(""));
assert_eq!(parse_gsettings("'prefer-dark'\n"), Some(true));
assert_eq!(parse_gsettings("'default'"), Some(false));
assert_eq!(parse_gsettings("garbage"), None);
assert_eq!(
parse_windows(" AppsUseLightTheme REG_DWORD 0x0\r\n"),
Some(true)
);
assert_eq!(
parse_windows("AppsUseLightTheme REG_DWORD 0x1"),
Some(false)
);
assert_eq!(parse_windows(""), None);
}
}