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
|
/// which is inspired by the solution in https://github.com/ysc3839/win32-darkmode
|
||||||
use std::{ffi::c_void, ptr};
|
use std::{ffi::c_void, ptr};
|
||||||
|
|
||||||
use windows_sys::core::PCSTR;
|
use windows_sys::core::{PCSTR, PCWSTR};
|
||||||
use windows_sys::Win32::Foundation::{BOOL, HWND, NTSTATUS, S_OK};
|
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::LibraryLoader::{GetProcAddress, LoadLibraryA};
|
||||||
use windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW;
|
use windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW;
|
||||||
use windows_sys::Win32::UI::Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA};
|
use windows_sys::Win32::UI::Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA};
|
||||||
use windows_sys::Win32::UI::Controls::SetWindowTheme;
|
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 winit_core::window::Theme;
|
||||||
|
|
||||||
use super::util;
|
use super::util;
|
||||||
|
|
@ -51,13 +55,17 @@ static DARK_MODE_SUPPORTED: LazyLock<bool> = LazyLock::new(|| {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
static DARK_THEME_NAME: LazyLock<Vec<u16>> =
|
const DARK_THEME_NAME: PCWSTR = w!("DarkMode_Explorer");
|
||||||
LazyLock::new(|| util::encode_wide("DarkMode_Explorer"));
|
const LIGHT_THEME_NAME: PCWSTR = w!("");
|
||||||
static LIGHT_THEME_NAME: LazyLock<Vec<u16>> = LazyLock::new(|| util::encode_wide(""));
|
|
||||||
|
|
||||||
/// Attempt to set a theme on a window, if necessary.
|
/// Attempt to set a theme on a window, if necessary.
|
||||||
/// Returns the theme that was picked
|
/// 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 {
|
if *DARK_MODE_SUPPORTED {
|
||||||
let is_dark_mode = match preferred_theme {
|
let is_dark_mode = match preferred_theme {
|
||||||
Some(theme) => theme == Theme::Dark,
|
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 = if is_dark_mode { Theme::Dark } else { Theme::Light };
|
||||||
let theme_name = match theme {
|
let theme_name = match theme {
|
||||||
Theme::Dark => DARK_THEME_NAME.as_ptr(),
|
Theme::Dark => DARK_THEME_NAME,
|
||||||
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
|
Theme::Light => LIGHT_THEME_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = unsafe { SetWindowTheme(hwnd, theme_name, ptr::null()) };
|
let status = unsafe { SetWindowTheme(hwnd, theme_name, ptr::null()) };
|
||||||
|
|
||||||
if status == S_OK && set_dark_mode_for_window(hwnd, is_dark_mode) {
|
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;
|
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 {
|
pub fn should_use_dark_mode() -> bool {
|
||||||
should_apps_use_dark_mode() && !is_high_contrast()
|
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;
|
let preferred_theme = userdata.window_state_lock().preferred_theme;
|
||||||
|
|
||||||
if preferred_theme.is_none() {
|
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();
|
let mut window_state = userdata.window_state_lock();
|
||||||
|
|
||||||
if window_state.current_theme != new_theme {
|
if window_state.current_theme != new_theme {
|
||||||
|
|
|
||||||
|
|
@ -1099,7 +1099,7 @@ impl CoreWindow for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_theme(&self, theme: Option<Theme>) {
|
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> {
|
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
|
// If the system theme is dark, we need to set the window theme now
|
||||||
// before we update the window flags (and possibly show the
|
// before we update the window flags (and possibly show the
|
||||||
// window for the first time).
|
// 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 = {
|
||||||
let window_state = WindowState::new(
|
let window_state = WindowState::new(
|
||||||
|
|
|
||||||
|
|
@ -257,3 +257,5 @@ changelog entry.
|
||||||
- On macOS, don't panic on monitors with unknown bit-depths.
|
- On macOS, don't panic on monitors with unknown bit-depths.
|
||||||
- On macOS, fixed crash when closing the window on macOS 26+.
|
- 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, 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