system_theme/platform/
windows.rs1use windows::{
2 core::HSTRING,
3 Foundation::Metadata::ApiInformation,
4 UI::{
5 Color,
6 ViewManagement::{AccessibilitySettings, UIColorType, UISettings},
7 },
8};
9
10use crate::{error::Error, ThemeColor, ThemeContrast, ThemeKind, ThemeScheme};
11
12impl From<Color> for ThemeColor {
13 fn from(color: Color) -> Self {
14 ThemeColor {
15 red: color.R as f32 / 255.0,
16 green: color.G as f32 / 255.0,
17 blue: color.B as f32 / 255.0,
18 }
19 }
20}
21
22fn check_color_supported() -> Result<bool, Error> {
24 const GET_COLOR_VALUE_TYPE: &str = "Windows.UI.ViewManagement.UISettings";
25 const GET_COLOR_VALUE_METHOD: &str = "GetColorValue";
26
27 ApiInformation::IsMethodPresent(
28 &HSTRING::from(GET_COLOR_VALUE_TYPE),
29 &HSTRING::from(GET_COLOR_VALUE_METHOD),
30 )
31 .map_err(Error::from_platform)
32}
33
34fn check_high_contrast_supported() -> Result<bool, Error> {
36 const GET_HIGH_CONTRAST_TYPE: &str = "Windows.UI.ViewManagement.AccessibilitySettings";
37 const GET_HIGH_CONTRAST_VALUE_METHOD: &str = "HighContrast";
38
39 ApiInformation::IsPropertyPresent(
40 &HSTRING::from(GET_HIGH_CONTRAST_TYPE),
41 &HSTRING::from(GET_HIGH_CONTRAST_VALUE_METHOD),
42 )
43 .map_err(Error::from_platform)
44}
45
46pub struct Platform {
47 ui_settings: Option<UISettings>,
48 a11y_settings: Option<AccessibilitySettings>,
49}
50
51impl Platform {
52 pub fn new() -> Result<Self, Error> {
53 let ui_settings = if check_color_supported()? {
55 Some(UISettings::new().map_err(Error::from_platform)?)
56 } else {
57 None
58 };
59
60 let a11y_settings = if check_high_contrast_supported()? {
62 Some(AccessibilitySettings::new().map_err(Error::from_platform)?)
63 } else {
64 None
65 };
66
67 Ok(Platform {
68 ui_settings,
69 a11y_settings,
70 })
71 }
72
73 pub fn theme_kind(&self) -> Result<ThemeKind, Error> {
74 Ok(ThemeKind::Windows)
75 }
76
77 pub fn theme_scheme(&self) -> Result<ThemeScheme, Error> {
78 let background = self.get_ui_color(UIColorType::Background)?;
80 Ok(if ThemeColor::from(background).is_dark() {
81 ThemeScheme::Dark
82 } else {
83 ThemeScheme::Light
84 })
85 }
86
87 pub fn theme_contrast(&self) -> Result<ThemeContrast, Error> {
88 self.a11y_settings
90 .as_ref()
91 .map(|settings| {
92 settings
93 .HighContrast()
94 .map(|high_contrast| {
95 if high_contrast {
96 ThemeContrast::High
97 } else {
98 ThemeContrast::Normal
99 }
100 })
101 .map_err(Error::from_platform)
102 })
103 .unwrap_or(Err(Error::Unsupported))
104 }
105
106 pub fn theme_accent(&self) -> Result<ThemeColor, Error> {
107 self.get_ui_color(UIColorType::Accent)
109 .map(|color| color.into())
110 }
111
112 fn get_ui_color(&self, color_type: UIColorType) -> Result<Color, Error> {
113 self.ui_settings
115 .as_ref()
116 .map(|settings| {
117 settings
118 .GetColorValue(color_type)
119 .map_err(Error::from_platform)
120 })
121 .unwrap_or(Err(Error::Unsupported))
122 }
123}