Skip to main content

Mountain/IPC/WindServiceHandlers/NativeHost/
GetColorScheme.rs

1#![allow(unused_variables, dead_code, unused_imports)]
2
3//! Wire method: `nativeHost:getColorScheme`.
4//! Returns `{ dark, highContrast }`. Dark-mode probe covers macOS
5//! `AppleInterfaceStyle`, Windows `AppsUseLightTheme`, and a Linux ladder
6//! (GTK color-scheme → GTK theme name → `KDE_COLOR_SCHEME` → xfconf).
7//! High-contrast probe is Windows `HighContrast/Flags` and the GNOME a11y
8//! `high-contrast` key; other OSes return false.
9
10use std::sync::OnceLock;
11
12use serde_json::{Value, json};
13
14// Cache dark-mode result for the process lifetime. The system colour scheme
15// is queried by spawning `defaults`/`reg`/`gsettings` which adds ~5-15 ms
16// on cold start. The workbench calls `getOSColorScheme` during boot and again
17// on window focus; caching turns the second+ call into a sub-microsecond read.
18// If the user switches dark/light mode while editing, they are expected to
19// restart the editor (same behaviour as stock VS Code on Electron).
20static DARK_MODE_CACHE:OnceLock<bool> = OnceLock::new();
21
22pub async fn Fn() -> Result<Value, String> {
23	let Dark = *DARK_MODE_CACHE.get_or_init(detect_dark_mode);
24
25	let HighContrast = {
26		#[cfg(target_os = "windows")]
27		{
28			std::process::Command::new("reg")
29				.args(["query", "HKCU\\Control Panel\\Accessibility\\HighContrast", "/v", "Flags"])
30				.output()
31				.ok()
32				.map(|O| {
33					let Output = String::from_utf8_lossy(&O.stdout);
34					Output.contains("0x1") || Output.contains("REG_DWORD    1")
35				})
36				.unwrap_or(false)
37		}
38
39		#[cfg(not(target_os = "windows"))]
40		{
41			#[cfg(target_os = "linux")]
42			{
43				std::process::Command::new("gsettings")
44					.args(["get", "org.gnome.desktop.a11y.interface", "high-contrast"])
45					.output()
46					.ok()
47					.map(|O| String::from_utf8_lossy(&O.stdout).trim() == "true")
48					.unwrap_or(false)
49			}
50
51			#[cfg(not(target_os = "linux"))]
52			{
53				false
54			}
55		}
56	};
57
58	Ok(json!({ "dark": Dark, "highContrast": HighContrast }))
59}
60
61fn detect_dark_mode() -> bool {
62	// runs once then cached via OnceLock
63	#[cfg(target_os = "macos")]
64	{
65		std::process::Command::new("defaults")
66			.args(["read", "-g", "AppleInterfaceStyle"])
67			.output()
68			.ok()
69			.map(|O| String::from_utf8_lossy(&O.stdout).trim().to_lowercase().contains("dark"))
70			.unwrap_or(false)
71	}
72
73	#[cfg(target_os = "windows")]
74	{
75		std::process::Command::new("reg")
76			.args([
77				"query",
78				"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
79				"/v",
80				"AppsUseLightTheme",
81			])
82			.output()
83			.ok()
84			.map(|O| {
85				let Output = String::from_utf8_lossy(&O.stdout);
86				Output.contains("0x0") || Output.contains("REG_DWORD    0")
87			})
88			.unwrap_or(false)
89	}
90
91	#[cfg(target_os = "linux")]
92	{
93		let GtkDark = std::process::Command::new("gsettings")
94			.args(["get", "org.gnome.desktop.interface", "color-scheme"])
95			.output()
96			.ok()
97			.map(|O| String::from_utf8_lossy(&O.stdout).contains("dark"))
98			.unwrap_or(false);
99
100		if GtkDark {
101			return true;
102		}
103
104		let GtkTheme = std::process::Command::new("gsettings")
105			.args(["get", "org.gnome.desktop.interface", "gtk-theme"])
106			.output()
107			.ok()
108			.map(|O| String::from_utf8_lossy(&O.stdout).to_lowercase().contains("dark"))
109			.unwrap_or(false);
110
111		if GtkTheme {
112			return true;
113		}
114
115		let KdeDark = std::env::var("KDE_COLOR_SCHEME")
116			.ok()
117			.map(|V| V.to_lowercase().contains("dark"))
118			.unwrap_or(false);
119
120		if KdeDark {
121			return true;
122		}
123
124		let XfceDark = std::process::Command::new("xfconf-query")
125			.args(["-c", "xsettings", "-p", "/Net/ThemeName"])
126			.output()
127			.ok()
128			.map(|O| String::from_utf8_lossy(&O.stdout).to_lowercase().contains("dark"))
129			.unwrap_or(false);
130
131		XfceDark
132	}
133
134	#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
135	{
136		false
137	}
138}