Skip to main content

agg_gui/
platform.rs

1//! Runtime platform conventions shared by widgets.
2//!
3//! Native builds default from the compiled target. WASM hosts can override this
4//! after inspecting the browser's client platform so shortcuts display and match
5//! the user's operating system rather than the `wasm32` compile target.
6
7use std::sync::atomic::{AtomicU8, Ordering};
8
9use crate::event::Modifiers;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum Platform {
13    MacOS,
14    Windows,
15    Linux,
16    Other,
17}
18
19static CURRENT_PLATFORM: AtomicU8 = AtomicU8::new(default_platform_code());
20
21pub fn set_platform(platform: Platform) {
22    CURRENT_PLATFORM.store(platform_code(platform), Ordering::Relaxed);
23}
24
25pub fn current_platform() -> Platform {
26    platform_from_code(CURRENT_PLATFORM.load(Ordering::Relaxed))
27}
28
29pub fn primary_modifier_label() -> &'static str {
30    match current_platform() {
31        Platform::MacOS => "Cmd",
32        Platform::Windows | Platform::Linux | Platform::Other => "Ctrl",
33    }
34}
35
36pub fn command_modifier_pressed(modifiers: Modifiers) -> bool {
37    match current_platform() {
38        Platform::MacOS => modifiers.meta,
39        Platform::Windows | Platform::Linux | Platform::Other => modifiers.ctrl,
40    }
41}
42
43pub fn command_modifier_released(modifiers: Modifiers) -> bool {
44    !modifiers.ctrl && !modifiers.meta
45}
46
47pub fn platform_from_name(name: &str) -> Platform {
48    let name = name.to_ascii_lowercase();
49    if name.contains("mac")
50        || name.contains("darwin")
51        || name.contains("iphone")
52        || name.contains("ipad")
53    {
54        Platform::MacOS
55    } else if name.contains("win") {
56        Platform::Windows
57    } else if name.contains("linux")
58        || name.contains("x11")
59        || name.contains("ubuntu")
60        || name.contains("fedora")
61        || name.contains("android")
62    {
63        Platform::Linux
64    } else {
65        Platform::Other
66    }
67}
68
69const fn default_platform_code() -> u8 {
70    if cfg!(target_os = "macos") {
71        platform_code(Platform::MacOS)
72    } else if cfg!(target_os = "windows") {
73        platform_code(Platform::Windows)
74    } else if cfg!(target_os = "linux") {
75        platform_code(Platform::Linux)
76    } else {
77        platform_code(Platform::Other)
78    }
79}
80
81const fn platform_code(platform: Platform) -> u8 {
82    match platform {
83        Platform::MacOS => 1,
84        Platform::Windows => 2,
85        Platform::Linux => 3,
86        Platform::Other => 4,
87    }
88}
89
90fn platform_from_code(code: u8) -> Platform {
91    match code {
92        1 => Platform::MacOS,
93        2 => Platform::Windows,
94        3 => Platform::Linux,
95        _ => Platform::Other,
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn parses_common_client_platform_names() {
105        assert_eq!(platform_from_name("macOS"), Platform::MacOS);
106        assert_eq!(platform_from_name("Win32"), Platform::Windows);
107        assert_eq!(platform_from_name("Linux x86_64"), Platform::Linux);
108        assert_eq!(platform_from_name("unknown"), Platform::Other);
109    }
110}