Files
ElyOffice/crates/ely-platform/src/accessibility.rs
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

95 lines
3.1 KiB
Rust

use crate::{env, settings::Motion};
/// `ELY_REDUCE_MOTION` wins, then the setting, then the OS.
pub fn reduce_motion(setting: Motion) -> bool {
let (env, system) = (env::flag("ELY_REDUCE_MOTION"), os_reduce_motion());
if env.is_none() && setting == Motion::System && system.is_none() {
log::info!("accessibility: no reduce-motion setting found, using full motion");
}
reduce_motion_from(env, setting, system)
}
fn reduce_motion_from(env: Option<bool>, setting: Motion, system: Option<bool>) -> bool {
let set = match setting {
Motion::System => None,
Motion::Reduced => Some(true),
Motion::Full => Some(false),
};
env.or(set).or(system).unwrap_or(false)
}
#[cfg(target_os = "macos")]
fn os_reduce_motion() -> Option<bool> {
Some(objc2_app_kit::NSWorkspace::sharedWorkspace().accessibilityDisplayShouldReduceMotion())
}
#[cfg(target_os = "linux")]
fn os_reduce_motion() -> Option<bool> {
let output = std::process::Command::new("gsettings")
.args(["get", "org.gnome.desktop.interface", "enable-animations"])
.output()
.map_err(|error| log::debug!("accessibility: gsettings did not run: {error}"))
.ok()?;
if !output.status.success() {
log::debug!("accessibility: gsettings has no enable-animations key");
return None;
}
animations_enabled(&String::from_utf8_lossy(&output.stdout)).map(|enabled| !enabled)
}
#[cfg(windows)]
fn os_reduce_motion() -> Option<bool> {
use windows_sys::Win32::UI::WindowsAndMessaging::{
SPI_GETCLIENTAREAANIMATION, SystemParametersInfoW,
};
let mut enabled: i32 = 1;
// SAFETY: a live i32, the size the call expects.
let read = unsafe {
SystemParametersInfoW(
SPI_GETCLIENTAREAANIMATION,
0,
(&mut enabled as *mut i32).cast(),
0,
)
};
(read != 0).then_some(enabled == 0)
}
#[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
fn os_reduce_motion() -> Option<bool> {
None
}
#[cfg(any(target_os = "linux", test))]
fn animations_enabled(gsettings: &str) -> Option<bool> {
match gsettings.trim() {
"true" => Some(true),
"false" => Some(false),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::{Motion, animations_enabled, reduce_motion_from};
#[test]
fn the_env_wins_then_the_setting_then_the_os_then_full_motion() {
assert!(reduce_motion_from(Some(true), Motion::Full, Some(false)));
assert!(!reduce_motion_from(Some(false), Motion::Reduced, Some(true)));
assert!(reduce_motion_from(None, Motion::Reduced, Some(false)));
assert!(!reduce_motion_from(None, Motion::Full, Some(true)));
assert!(reduce_motion_from(None, Motion::System, Some(true)));
assert!(!reduce_motion_from(None, Motion::System, None));
}
#[test]
fn gsettings_answers_parse_and_anything_else_is_no_answer() {
assert_eq!(animations_enabled("true\n"), Some(true));
assert_eq!(animations_enabled("false\n"), Some(false));
assert_eq!(animations_enabled("uint32 7\n"), None);
assert_eq!(animations_enabled(""), None);
}
}