teksilo_platform/
accessibility_prefs.rs1#[derive(Debug, Clone, PartialEq)]
20pub struct AccessibilityPreferences {
21 pub high_contrast: bool,
23 pub reduced_motion: bool,
25 pub text_scale_factor: f64,
28}
29
30impl Default for AccessibilityPreferences {
31 fn default() -> Self {
32 Self {
33 high_contrast: false,
34 reduced_motion: false,
35 text_scale_factor: 1.0,
36 }
37 }
38}
39
40impl AccessibilityPreferences {
41 pub fn query() -> Self {
47 platform::query()
48 }
49
50 pub fn prefers_large_text(&self) -> bool {
52 self.text_scale_factor > 1.0
53 }
54}
55
56#[cfg(target_os = "linux")]
62mod platform {
63 use super::AccessibilityPreferences;
64 use crate::linux_helpers::{read_gsettings, read_portal_u32};
65
66 pub(super) fn query() -> AccessibilityPreferences {
67 let mut prefs = AccessibilityPreferences::default();
68
69 if let Some(v) = read_portal_u32("org.freedesktop.appearance", "contrast") {
72 prefs.high_contrast = v == 1;
73 }
74 if let Some(v) = read_portal_u32("org.freedesktop.appearance", "reduced-motion") {
75 prefs.reduced_motion = v == 1;
76 }
77
78 if !prefs.high_contrast
80 && let Some(theme) = read_gsettings("org.gnome.desktop.interface", "gtk-theme")
81 {
82 prefs.high_contrast = theme.contains("HighContrast");
83 }
84
85 if !prefs.high_contrast
87 && let Some(val) = read_gsettings("org.gnome.desktop.a11y.interface", "high-contrast")
88 {
89 prefs.high_contrast = val == "true";
90 }
91
92 if !prefs.reduced_motion
94 && let Some(val) = read_gsettings("org.gnome.desktop.interface", "enable-animations")
95 {
96 prefs.reduced_motion = val == "false";
97 }
98
99 if let Some(val) = read_gsettings("org.gnome.desktop.interface", "text-scaling-factor")
101 && let Ok(scale) = val.parse::<f64>()
102 {
103 prefs.text_scale_factor = scale;
104 }
105
106 prefs
107 }
108}
109
110#[cfg(target_os = "macos")]
112mod platform {
113 use super::AccessibilityPreferences;
114
115 pub(super) fn query() -> AccessibilityPreferences {
116 let mut prefs = AccessibilityPreferences::default();
117
118 let workspace = objc2_app_kit::NSWorkspace::sharedWorkspace();
119
120 prefs.high_contrast = workspace.accessibilityDisplayShouldIncreaseContrast();
122
123 prefs.reduced_motion = workspace.accessibilityDisplayShouldReduceMotion();
125
126 prefs
130 }
131}
132
133#[cfg(target_os = "windows")]
135mod platform {
136 use super::AccessibilityPreferences;
137
138 pub(super) fn query() -> AccessibilityPreferences {
139 let mut prefs = AccessibilityPreferences::default();
140
141 prefs.high_contrast = query_high_contrast();
142 let (reduced_motion, text_scale) = query_ui_settings();
143 prefs.reduced_motion = reduced_motion;
144 prefs.text_scale_factor = text_scale;
145
146 prefs
147 }
148
149 fn query_high_contrast() -> bool {
151 use std::mem;
152 use windows::Win32::UI::Accessibility::HIGHCONTRASTW;
153 use windows::Win32::UI::WindowsAndMessaging::{
154 SPI_GETHIGHCONTRAST, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, SystemParametersInfoW,
155 };
156
157 unsafe {
158 let mut hc = HIGHCONTRASTW {
159 cbSize: mem::size_of::<HIGHCONTRASTW>() as u32,
160 ..Default::default()
161 };
162 let ok = SystemParametersInfoW(
163 SPI_GETHIGHCONTRAST,
164 hc.cbSize,
165 Some(&mut hc as *mut _ as *mut _),
166 SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
167 );
168 if ok.is_ok() {
169 (hc.dwFlags.0 & 0x01) != 0
171 } else {
172 false
173 }
174 }
175 }
176
177 fn query_ui_settings() -> (bool, f64) {
179 use windows::UI::ViewManagement::UISettings;
180
181 let mut reduced_motion = false;
182 let mut text_scale = 1.0_f64;
183
184 if let Ok(settings) = UISettings::new() {
185 if let Ok(animations_enabled) = settings.AnimationsEnabled() {
187 reduced_motion = !animations_enabled;
188 }
189
190 if let Ok(scale) = settings.TextScaleFactor() {
192 text_scale = scale as f64;
193 }
194 }
195
196 (reduced_motion, text_scale)
197 }
198}
199
200#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
202mod platform {
203 use super::AccessibilityPreferences;
204
205 pub(super) fn query() -> AccessibilityPreferences {
206 AccessibilityPreferences::default()
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn default_preferences() {
216 let prefs = AccessibilityPreferences::default();
217 assert!(!prefs.high_contrast);
218 assert!(!prefs.reduced_motion);
219 assert!((prefs.text_scale_factor - 1.0).abs() < f64::EPSILON);
220 assert!(!prefs.prefers_large_text());
221 }
222
223 #[test]
224 fn large_text_threshold() {
225 let mut prefs = AccessibilityPreferences {
226 text_scale_factor: 1.25,
227 ..AccessibilityPreferences::default()
228 };
229 assert!(prefs.prefers_large_text());
230
231 prefs.text_scale_factor = 1.0;
232 assert!(!prefs.prefers_large_text());
233 }
234
235 #[test]
236 fn query_does_not_panic() {
237 let prefs = AccessibilityPreferences::query();
239 assert!(prefs.text_scale_factor > 0.0);
240 }
241}