windows: Prefer WM_SETTINGCHANGE when handing theme changed events (#23727)

I recently noticed that on my Windows 11 machine, Zed no longer receive
the `WM_DWMCOLORIZATIONCOLORCHANGED` message when the system theme
changes. This functionality was present in the past. While this change
might be unexpected, it's understandable given Microsoft's history of
system updates.

This pull request proposes an alternative approach using the
`WM_SETTINGCHANGE` message to handle theme changes.

Release Notes:

- N/A
This commit is contained in:
张小白 2025-01-28 15:47:55 +08:00 committed by GitHub
parent 1b88734c6c
commit e083679e0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 14 deletions

View file

@ -2,15 +2,18 @@ use std::rc::Rc;
use ::util::ResultExt;
use anyhow::Context as _;
use windows::Win32::{
Foundation::*,
Graphics::Gdi::*,
System::SystemServices::*,
UI::{
Controls::*,
HiDpi::*,
Input::{Ime::*, KeyboardAndMouse::*},
WindowsAndMessaging::*,
use windows::{
core::PCWSTR,
Win32::{
Foundation::*,
Graphics::Gdi::*,
System::SystemServices::*,
UI::{
Controls::*,
HiDpi::*,
Input::{Ime::*, KeyboardAndMouse::*},
WindowsAndMessaging::*,
},
},
};
@ -88,8 +91,7 @@ pub(crate) fn handle_msg(
WM_IME_STARTCOMPOSITION => handle_ime_position(handle, state_ptr),
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
WM_SETCURSOR => handle_set_cursor(lparam, state_ptr),
WM_SETTINGCHANGE => handle_system_settings_changed(handle, state_ptr),
WM_DWMCOLORIZATIONCOLORCHANGED => handle_system_theme_changed(handle, state_ptr),
WM_SETTINGCHANGE => handle_system_settings_changed(handle, lparam, state_ptr),
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
_ => None,
};
@ -1187,6 +1189,7 @@ fn handle_set_cursor(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Op
fn handle_system_settings_changed(
handle: HWND,
lparam: LPARAM,
state_ptr: Rc<WindowsWindowStatePtr>,
) -> Option<isize> {
let mut lock = state_ptr.state.borrow_mut();
@ -1198,6 +1201,22 @@ fn handle_system_settings_changed(
// window border offset
lock.border_offset.update(handle).log_err();
drop(lock);
// lParam is a pointer to a string that indicates the area containing the system parameter
// that was changed.
let parameter = PCWSTR::from_raw(lparam.0 as _);
if unsafe { !parameter.is_null() && !parameter.is_empty() } {
if let Some(parameter_string) = unsafe { parameter.to_string() }.log_err() {
log::info!("System settings changed: {}", parameter_string);
match parameter_string.as_str() {
"ImmersiveColorSet" => {
handle_system_theme_changed(handle, state_ptr);
}
_ => {}
}
}
}
// Force to trigger WM_NCCALCSIZE event to ensure that we handle auto hide
// taskbar correctly.
notify_frame_changed(handle);
@ -1227,7 +1246,7 @@ fn handle_system_theme_changed(
.take()?;
callback();
state_ptr.state.borrow_mut().callbacks.appearance_changed = Some(callback);
set_dwm_window_appearance(handle);
configure_dwm_dark_mode(handle);
Some(0)
}

View file

@ -139,7 +139,8 @@ pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR {
}))
}
pub(crate) fn set_dwm_window_appearance(hwnd: HWND) {
/// This function is used to configure the dark mode for the window built-in title bar.
pub(crate) fn configure_dwm_dark_mode(hwnd: HWND) {
let dark_mode_enabled: BOOL = match system_appearance().log_err().unwrap_or_default() {
WindowAppearance::Dark | WindowAppearance::VibrantDark => true.into(),
WindowAppearance::Light | WindowAppearance::VibrantLight => false.into(),

View file

@ -443,7 +443,7 @@ impl WindowsWindow {
let state_ptr = context.inner.take().unwrap()?;
let hwnd = creation_result?;
register_drag_drop(state_ptr.clone())?;
set_dwm_window_appearance(hwnd);
configure_dwm_dark_mode(hwnd);
state_ptr.state.borrow_mut().border_offset.update(hwnd)?;
let placement = retrieve_window_placement(
hwnd,