win32: refresh title bar on Window::set_theme
This commit is contained in:
parent
317d62fb93
commit
a4af50ec13
4 changed files with 37 additions and 12 deletions
|
|
@ -3,13 +3,17 @@ use std::sync::LazyLock;
|
|||
/// which is inspired by the solution in https://github.com/ysc3839/win32-darkmode
|
||||
use std::{ffi::c_void, ptr};
|
||||
|
||||
use windows_sys::core::PCSTR;
|
||||
use windows_sys::Win32::Foundation::{BOOL, HWND, NTSTATUS, S_OK};
|
||||
use windows_sys::core::{PCSTR, PCWSTR};
|
||||
use windows_sys::w;
|
||||
use windows_sys::Win32::Foundation::{BOOL, HWND, LPARAM, NTSTATUS, S_OK, WPARAM};
|
||||
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
|
||||
use windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW;
|
||||
use windows_sys::Win32::UI::Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA};
|
||||
use windows_sys::Win32::UI::Controls::SetWindowTheme;
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{SystemParametersInfoA, SPI_GETHIGHCONTRAST};
|
||||
use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetActiveWindow;
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
DefWindowProcW, SystemParametersInfoA, SPI_GETHIGHCONTRAST, WM_NCACTIVATE,
|
||||
};
|
||||
use winit_core::window::Theme;
|
||||
|
||||
use super::util;
|
||||
|
|
@ -51,13 +55,17 @@ static DARK_MODE_SUPPORTED: LazyLock<bool> = LazyLock::new(|| {
|
|||
}
|
||||
});
|
||||
|
||||
static DARK_THEME_NAME: LazyLock<Vec<u16>> =
|
||||
LazyLock::new(|| util::encode_wide("DarkMode_Explorer"));
|
||||
static LIGHT_THEME_NAME: LazyLock<Vec<u16>> = LazyLock::new(|| util::encode_wide(""));
|
||||
const DARK_THEME_NAME: PCWSTR = w!("DarkMode_Explorer");
|
||||
const LIGHT_THEME_NAME: PCWSTR = w!("");
|
||||
|
||||
/// Attempt to set a theme on a window, if necessary.
|
||||
/// Returns the theme that was picked
|
||||
pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
|
||||
///
|
||||
/// `refresh_title_bar` is only needed when the system doesn't do it by itself,
|
||||
/// for cases like on window creation or system settings changes,
|
||||
/// the system will refresh the title bar automatically,
|
||||
/// if we always refresh the title bar, it will blink it on system settings changes
|
||||
pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>, refresh_title_bar: bool) -> Theme {
|
||||
if *DARK_MODE_SUPPORTED {
|
||||
let is_dark_mode = match preferred_theme {
|
||||
Some(theme) => theme == Theme::Dark,
|
||||
|
|
@ -66,13 +74,16 @@ pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
|
|||
|
||||
let theme = if is_dark_mode { Theme::Dark } else { Theme::Light };
|
||||
let theme_name = match theme {
|
||||
Theme::Dark => DARK_THEME_NAME.as_ptr(),
|
||||
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
|
||||
Theme::Dark => DARK_THEME_NAME,
|
||||
Theme::Light => LIGHT_THEME_NAME,
|
||||
};
|
||||
|
||||
let status = unsafe { SetWindowTheme(hwnd, theme_name, ptr::null()) };
|
||||
|
||||
if status == S_OK && set_dark_mode_for_window(hwnd, is_dark_mode) {
|
||||
if refresh_title_bar {
|
||||
unsafe { refresh_titlebar_theme_color(hwnd) };
|
||||
}
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
|
@ -123,6 +134,18 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn refresh_titlebar_theme_color(hwnd: HWND) {
|
||||
unsafe {
|
||||
if GetActiveWindow() == hwnd {
|
||||
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM::default(), LPARAM::default());
|
||||
DefWindowProcW(hwnd, WM_NCACTIVATE, true as _, LPARAM::default());
|
||||
} else {
|
||||
DefWindowProcW(hwnd, WM_NCACTIVATE, true as _, LPARAM::default());
|
||||
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM::default(), LPARAM::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_use_dark_mode() -> bool {
|
||||
should_apps_use_dark_mode() && !is_high_contrast()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2467,7 +2467,7 @@ unsafe fn public_window_callback_inner(
|
|||
let preferred_theme = userdata.window_state_lock().preferred_theme;
|
||||
|
||||
if preferred_theme.is_none() {
|
||||
let new_theme = try_theme(window, preferred_theme);
|
||||
let new_theme = try_theme(window, preferred_theme, false);
|
||||
let mut window_state = userdata.window_state_lock();
|
||||
|
||||
if window_state.current_theme != new_theme {
|
||||
|
|
|
|||
|
|
@ -1099,7 +1099,7 @@ impl CoreWindow for Window {
|
|||
}
|
||||
|
||||
fn set_theme(&self, theme: Option<Theme>) {
|
||||
try_theme(self.window.hwnd(), theme);
|
||||
self.window_state_lock().current_theme = try_theme(self.window.hwnd(), theme, true);
|
||||
}
|
||||
|
||||
fn theme(&self) -> Option<Theme> {
|
||||
|
|
@ -1196,7 +1196,7 @@ impl InitData<'_> {
|
|||
// If the system theme is dark, we need to set the window theme now
|
||||
// before we update the window flags (and possibly show the
|
||||
// window for the first time).
|
||||
let current_theme = try_theme(window, self.attributes.preferred_theme);
|
||||
let current_theme = try_theme(window, self.attributes.preferred_theme, false);
|
||||
|
||||
let window_state = {
|
||||
let window_state = WindowState::new(
|
||||
|
|
|
|||
|
|
@ -257,3 +257,5 @@ changelog entry.
|
|||
- On macOS, don't panic on monitors with unknown bit-depths.
|
||||
- On macOS, fixed crash when closing the window on macOS 26+.
|
||||
- On Windows, account for mouse wheel lines per scroll setting for `WindowEvent::MouseWheel`.
|
||||
- On Windows, `Window::theme` will return the correct theme after setting it through `Window::set_theme`.
|
||||
- On Windows, `Window::set_theme` will change the title bar color immediately now.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue