Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3792,6 +3792,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");
Expand All @@ -3814,3 +3815,89 @@ 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::<i32>() 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::<u32>() as u32,
);
set_attr(
dwm::DWMWA_BORDER_COLOR,
&caption_color as *const _ as *const std::ffi::c_void,
std::mem::size_of::<u32>() 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::<u32>() as u32,
);
set_attr(
dwm::DWMWA_BORDER_COLOR,
&caption_color as *const _ as *const std::ffi::c_void,
std::mem::size_of::<u32>() as u32,
);
}
}
}
}

#[tauri::command]
fn set_title_bar_theme(app: AppHandle, is_dark: bool) -> Result<(), String> {
#[cfg(target_os = "windows")]
{
for (label, window) in app.webview_windows() {
if label == "main" || label.starts_with("preview-") {
windows_title_bar::apply_title_bar_theme(&window, is_dark);
}
}
}
#[cfg(not(target_os = "windows"))]
{
let _ = app;
let _ = is_dark;
}
Ok(())
}
5 changes: 5 additions & 0 deletions src/context/ThemeContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down