From 9ea38931a51616ac830e36528c52381e58c109a1 Mon Sep 17 00:00:00 2001 From: chengcheng84 Date: Mon, 6 Apr 2026 09:33:09 +0800 Subject: [PATCH 1/2] feat: add Windows title bar theme support --- src-tauri/src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++ src/context/ThemeContext.tsx | 5 +++ 2 files changed, 92 insertions(+) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 64a8090..11bd1d7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3702,6 +3702,11 @@ pub fn run() { }; if let Some(main_window) = app.get_webview_window("main") { + #[cfg(target_os = "windows")] + { + windows_title_bar::apply_title_bar_theme(&main_window, false); + } + let has_notes_folder = app .state::() .app_config @@ -3792,6 +3797,7 @@ pub fn run() { install_cli, uninstall_cli, get_cli_status, + set_title_bar_theme, ]) .build(tauri::generate_context!()) .expect("error while building tauri application"); @@ -3814,3 +3820,84 @@ pub fn run() { } }); } + +#[cfg(target_os = "windows")] +mod windows_title_bar { + use tauri::WebviewWindow; + + #[allow(non_snake_case)] + mod dwm { + pub const DWMWA_USE_IMMERSIVE_DARK_MODE: u32 = 20; + pub const DWMWA_CAPTION_COLOR: u32 = 35; + pub const DWMWA_BORDER_COLOR: u32 = 34; + + extern "system" { + pub fn DwmSetWindowAttribute( + hwnd: isize, + attr: u32, + value: *const std::ffi::c_void, + size: u32, + ) -> i32; + } + } + + pub fn apply_title_bar_theme(window: &WebviewWindow, is_dark: bool) { + let Ok(hwnd) = window.hwnd() else { + return; + }; + let hwnd = hwnd.0 as isize; + + unsafe { + let set_attr = + |attr: u32, value: *const std::ffi::c_void, size: u32| { + let _ = dwm::DwmSetWindowAttribute(hwnd, attr, value, size); + }; + + let dark_mode: i32 = if is_dark { 1 } else { 0 }; + set_attr( + dwm::DWMWA_USE_IMMERSIVE_DARK_MODE, + &dark_mode as *const _ as *const std::ffi::c_void, + std::mem::size_of::() as u32, + ); + + if is_dark { + let caption_color: u32 = 0x00_0E_0C_0B; + set_attr( + dwm::DWMWA_CAPTION_COLOR, + &caption_color as *const _ as *const std::ffi::c_void, + std::mem::size_of::() as u32, + ); + set_attr( + dwm::DWMWA_BORDER_COLOR, + &caption_color as *const _ as *const std::ffi::c_void, + std::mem::size_of::() as u32, + ); + } else { + let caption_color: u32 = 0x00_FA_FA_F9; + set_attr( + dwm::DWMWA_CAPTION_COLOR, + &caption_color as *const _ as *const std::ffi::c_void, + std::mem::size_of::() as u32, + ); + set_attr( + dwm::DWMWA_BORDER_COLOR, + &caption_color as *const _ as *const std::ffi::c_void, + std::mem::size_of::() as u32, + ); + } + } + } +} + +#[tauri::command] +fn set_title_bar_theme(app: AppHandle, is_dark: bool) -> Result<(), String> { + #[cfg(target_os = "windows")] + { + if let Some(window) = app.get_webview_window("main") { + windows_title_bar::apply_title_bar_theme(&window, is_dark); + } + } + let _ = app; + let _ = is_dark; + Ok(()) +} diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index ee48436..c2c065c 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -6,6 +6,7 @@ import { useCallback, type ReactNode, } from "react"; +import { invoke } from "@tauri-apps/api/core"; import { getSettings, updateSettings } from "../services/notes"; import type { ThemeSettings, @@ -270,6 +271,10 @@ export function ThemeProvider({ children }: ThemeProviderProps) { } else { root.classList.remove("dark"); } + + invoke("set_title_bar_theme", { isDark: resolvedTheme === "dark" }).catch( + () => {}, + ); }, [resolvedTheme]); // Save theme mode to backend From a57ec5446f9178ecaee9cea11f1512b24dd3f137 Mon Sep 17 00:00:00 2001 From: chengcheng84 Date: Mon, 6 Apr 2026 09:48:36 +0800 Subject: [PATCH 2/2] fix: review --- src-tauri/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 11bd1d7..c15aa00 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3702,11 +3702,6 @@ pub fn run() { }; if let Some(main_window) = app.get_webview_window("main") { - #[cfg(target_os = "windows")] - { - windows_title_bar::apply_title_bar_theme(&main_window, false); - } - let has_notes_folder = app .state::() .app_config @@ -3893,11 +3888,16 @@ mod windows_title_bar { fn set_title_bar_theme(app: AppHandle, is_dark: bool) -> Result<(), String> { #[cfg(target_os = "windows")] { - if let Some(window) = app.get_webview_window("main") { - windows_title_bar::apply_title_bar_theme(&window, is_dark); + for (label, window) in app.webview_windows() { + if label == "main" || label.starts_with("preview-") { + windows_title_bar::apply_title_bar_theme(&window, is_dark); + } } } - let _ = app; - let _ = is_dark; + #[cfg(not(target_os = "windows"))] + { + let _ = app; + let _ = is_dark; + } Ok(()) }