From ef8791906b2b053065b2790c5b940188074617ed Mon Sep 17 00:00:00 2001 From: xintaofei Date: Tue, 14 Apr 2026 10:13:18 +0800 Subject: [PATCH] fix(windows,linux): reduce dark mode white flash on window open Detect system dark mode on Windows (registry AppsUseLightTheme) and Linux (gsettings for GNOME, kreadconfig for KDE Plasma) to set native window background color before webview renders, matching the existing macOS behavior. Make should_use_dark_background() cross-platform and apply background_color in all platform branches of apply_platform_window_style. --- src-tauri/src/commands/windows.rs | 92 ++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/commands/windows.rs b/src-tauri/src/commands/windows.rs index 45c58f9..0850a97 100644 --- a/src-tauri/src/commands/windows.rs +++ b/src-tauri/src/commands/windows.rs @@ -96,7 +96,7 @@ fn is_system_dark_mode() -> bool { use std::sync::OnceLock; static CACHED: OnceLock = OnceLock::new(); *CACHED.get_or_init(|| { - std::process::Command::new("defaults") + crate::process::std_command("defaults") .args(["read", "-g", "AppleInterfaceStyle"]) .output() .map(|o| o.status.success()) // key exists only in dark mode @@ -104,9 +104,86 @@ fn is_system_dark_mode() -> bool { }) } +/// Detect Windows system dark mode via registry query. +/// `AppsUseLightTheme`: 0 = dark, 1 = light. +/// Uses `crate::process::std_command` to avoid flashing a console window. +/// On pre-1809 Windows where the key is absent, defaults to light mode. +#[cfg(target_os = "windows")] +fn is_system_dark_mode() -> bool { + use std::sync::OnceLock; + static CACHED: OnceLock = OnceLock::new(); + *CACHED.get_or_init(|| { + crate::process::std_command("reg") + .args([ + "query", + r"HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", + "/v", + "AppsUseLightTheme", + ]) + .output() + .ok() + .and_then(|o| { + let stdout = String::from_utf8_lossy(&o.stdout); + // Output: " AppsUseLightTheme REG_DWORD 0x0" + // Extract the last token on the matching line to avoid + // substring false-positives (e.g. "0x00000001" contains "0x0"). + stdout.lines().find(|l| l.contains("AppsUseLightTheme")).map(|line| { + line.split_whitespace() + .last() + .map(|val| val == "0x0" || val == "0x00000000") + .unwrap_or(false) + }) + }) + .unwrap_or(false) + }) +} + +/// Detect Linux system dark mode via desktop environment settings. +/// Covers GNOME (gsettings) and KDE Plasma (kreadconfig5/6). +/// Falls back to light mode on unsupported desktops (XFCE, etc.). +#[cfg(target_os = "linux")] +fn is_system_dark_mode() -> bool { + use std::sync::OnceLock; + static CACHED: OnceLock = OnceLock::new(); + *CACHED.get_or_init(|| { + // GNOME 42+: color-scheme = 'prefer-dark' + if let Ok(output) = crate::process::std_command("gsettings") + .args(["get", "org.gnome.desktop.interface", "color-scheme"]) + .output() + { + let s = String::from_utf8_lossy(&output.stdout); + if s.contains("prefer-dark") { + return true; + } + } + // Older GNOME / GTK: theme name contains "dark" + if let Ok(output) = crate::process::std_command("gsettings") + .args(["get", "org.gnome.desktop.interface", "gtk-theme"]) + .output() + { + let s = String::from_utf8_lossy(&output.stdout).to_lowercase(); + if s.contains("dark") { + return true; + } + } + // KDE Plasma 5/6: ColorScheme name contains "dark" + for cmd in ["kreadconfig6", "kreadconfig5"] { + if let Ok(output) = crate::process::std_command(cmd) + .args(["--group", "General", "--key", "ColorScheme"]) + .output() + { + let s = String::from_utf8_lossy(&output.stdout).to_lowercase(); + if s.contains("dark") { + return true; + } + } + } + false + }) +} + /// Determine whether the window should use a dark background, considering /// both the user's explicit preference (from DB) and the OS appearance. -#[cfg(target_os = "macos")] fn should_use_dark_background() -> bool { match CACHED_APPEARANCE_MODE.load(AtomicOrdering::Relaxed) { MODE_DARK => true, @@ -138,12 +215,21 @@ where #[cfg(target_os = "windows")] { + let builder = if should_use_dark_background() { + builder.background_color(tauri::window::Color(9, 9, 11, 255)) + } else { + builder + }; return builder.decorations(false); } #[cfg(not(any(target_os = "macos", target_os = "windows")))] { - builder + if should_use_dark_background() { + builder.background_color(tauri::window::Color(9, 9, 11, 255)) + } else { + builder + } } }