windows: More precise handling of WM_SETTINGCHANGE
and appearance updates (#33829)
This PR adds more fine-grained handling of the `WM_SETTINGCHANGE` message. Plus, we now only trigger the `appearance_changed` callback when the actual window appearance has changed, rather than calling it every time. Release Notes: - N/A
This commit is contained in:
parent
968587a745
commit
cdb7564d89
4 changed files with 89 additions and 46 deletions
|
@ -93,7 +93,7 @@ pub(crate) fn handle_msg(
|
||||||
WM_IME_STARTCOMPOSITION => handle_ime_position(handle, state_ptr),
|
WM_IME_STARTCOMPOSITION => handle_ime_position(handle, state_ptr),
|
||||||
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
|
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
|
||||||
WM_SETCURSOR => handle_set_cursor(handle, lparam, state_ptr),
|
WM_SETCURSOR => handle_set_cursor(handle, lparam, state_ptr),
|
||||||
WM_SETTINGCHANGE => handle_system_settings_changed(handle, lparam, state_ptr),
|
WM_SETTINGCHANGE => handle_system_settings_changed(handle, wparam, lparam, state_ptr),
|
||||||
WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr),
|
WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr),
|
||||||
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -1152,37 +1152,23 @@ fn handle_set_cursor(
|
||||||
|
|
||||||
fn handle_system_settings_changed(
|
fn handle_system_settings_changed(
|
||||||
handle: HWND,
|
handle: HWND,
|
||||||
|
wparam: WPARAM,
|
||||||
lparam: LPARAM,
|
lparam: LPARAM,
|
||||||
state_ptr: Rc<WindowsWindowStatePtr>,
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
) -> Option<isize> {
|
) -> Option<isize> {
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
if wparam.0 != 0 {
|
||||||
let display = lock.display;
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
// system settings
|
let display = lock.display;
|
||||||
lock.system_settings.update(display);
|
lock.system_settings.update(display, wparam.0);
|
||||||
// mouse double click
|
lock.click_state.system_update(wparam.0);
|
||||||
lock.click_state.system_update();
|
lock.border_offset.update(handle).log_err();
|
||||||
// window border offset
|
} else {
|
||||||
lock.border_offset.update(handle).log_err();
|
handle_system_theme_changed(handle, lparam, state_ptr)?;
|
||||||
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
|
// Force to trigger WM_NCCALCSIZE event to ensure that we handle auto hide
|
||||||
// taskbar correctly.
|
// taskbar correctly.
|
||||||
notify_frame_changed(handle);
|
notify_frame_changed(handle);
|
||||||
|
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,17 +1185,34 @@ fn handle_system_command(wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -
|
||||||
|
|
||||||
fn handle_system_theme_changed(
|
fn handle_system_theme_changed(
|
||||||
handle: HWND,
|
handle: HWND,
|
||||||
|
lparam: LPARAM,
|
||||||
state_ptr: Rc<WindowsWindowStatePtr>,
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
) -> Option<isize> {
|
) -> Option<isize> {
|
||||||
let mut callback = state_ptr
|
// lParam is a pointer to a string that indicates the area containing the system parameter
|
||||||
.state
|
// that was changed.
|
||||||
.borrow_mut()
|
let parameter = PCWSTR::from_raw(lparam.0 as _);
|
||||||
.callbacks
|
if unsafe { !parameter.is_null() && !parameter.is_empty() } {
|
||||||
.appearance_changed
|
if let Some(parameter_string) = unsafe { parameter.to_string() }.log_err() {
|
||||||
.take()?;
|
log::info!("System settings changed: {}", parameter_string);
|
||||||
callback();
|
match parameter_string.as_str() {
|
||||||
state_ptr.state.borrow_mut().callbacks.appearance_changed = Some(callback);
|
"ImmersiveColorSet" => {
|
||||||
configure_dwm_dark_mode(handle);
|
let new_appearance = system_appearance()
|
||||||
|
.context("unable to get system appearance when handling ImmersiveColorSet")
|
||||||
|
.log_err()?;
|
||||||
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
|
if new_appearance != lock.appearance {
|
||||||
|
lock.appearance = new_appearance;
|
||||||
|
let mut callback = lock.callbacks.appearance_changed.take()?;
|
||||||
|
drop(lock);
|
||||||
|
callback();
|
||||||
|
state_ptr.state.borrow_mut().callbacks.appearance_changed = Some(callback);
|
||||||
|
configure_dwm_dark_mode(handle, new_appearance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,32 @@ pub(crate) struct MouseWheelSettings {
|
||||||
impl WindowsSystemSettings {
|
impl WindowsSystemSettings {
|
||||||
pub(crate) fn new(display: WindowsDisplay) -> Self {
|
pub(crate) fn new(display: WindowsDisplay) -> Self {
|
||||||
let mut settings = Self::default();
|
let mut settings = Self::default();
|
||||||
settings.update(display);
|
settings.init(display);
|
||||||
settings
|
settings
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update(&mut self, display: WindowsDisplay) {
|
fn init(&mut self, display: WindowsDisplay) {
|
||||||
self.mouse_wheel_settings.update();
|
self.mouse_wheel_settings.update();
|
||||||
self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
|
self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update(&mut self, display: WindowsDisplay, wparam: usize) {
|
||||||
|
match wparam {
|
||||||
|
// SPI_SETWORKAREA
|
||||||
|
47 => self.update_taskbar_position(display),
|
||||||
|
// SPI_GETWHEELSCROLLLINES, SPI_GETWHEELSCROLLCHARS
|
||||||
|
104 | 108 => self.update_mouse_wheel_settings(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_mouse_wheel_settings(&mut self) {
|
||||||
|
self.mouse_wheel_settings.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_taskbar_position(&mut self, display: WindowsDisplay) {
|
||||||
|
self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseWheelSettings {
|
impl MouseWheelSettings {
|
||||||
|
|
|
@ -144,8 +144,8 @@ pub(crate) fn load_cursor(style: CursorStyle) -> Option<HCURSOR> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is used to configure the dark mode for the window built-in title bar.
|
/// 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) {
|
pub(crate) fn configure_dwm_dark_mode(hwnd: HWND, appearance: WindowAppearance) {
|
||||||
let dark_mode_enabled: BOOL = match system_appearance().log_err().unwrap_or_default() {
|
let dark_mode_enabled: BOOL = match appearance {
|
||||||
WindowAppearance::Dark | WindowAppearance::VibrantDark => true.into(),
|
WindowAppearance::Dark | WindowAppearance::VibrantDark => true.into(),
|
||||||
WindowAppearance::Light | WindowAppearance::VibrantLight => false.into(),
|
WindowAppearance::Light | WindowAppearance::VibrantLight => false.into(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub struct WindowsWindowState {
|
||||||
pub min_size: Option<Size<Pixels>>,
|
pub min_size: Option<Size<Pixels>>,
|
||||||
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
||||||
pub border_offset: WindowBorderOffset,
|
pub border_offset: WindowBorderOffset,
|
||||||
|
pub appearance: WindowAppearance,
|
||||||
pub scale_factor: f32,
|
pub scale_factor: f32,
|
||||||
pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>,
|
pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>,
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ impl WindowsWindowState {
|
||||||
display: WindowsDisplay,
|
display: WindowsDisplay,
|
||||||
gpu_context: &BladeContext,
|
gpu_context: &BladeContext,
|
||||||
min_size: Option<Size<Pixels>>,
|
min_size: Option<Size<Pixels>>,
|
||||||
|
appearance: WindowAppearance,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let scale_factor = {
|
let scale_factor = {
|
||||||
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
||||||
|
@ -118,6 +120,7 @@ impl WindowsWindowState {
|
||||||
logical_size,
|
logical_size,
|
||||||
fullscreen_restore_bounds,
|
fullscreen_restore_bounds,
|
||||||
border_offset,
|
border_offset,
|
||||||
|
appearance,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
restore_from_minimized,
|
restore_from_minimized,
|
||||||
min_size,
|
min_size,
|
||||||
|
@ -206,6 +209,7 @@ impl WindowsWindowStatePtr {
|
||||||
context.display,
|
context.display,
|
||||||
context.gpu_context,
|
context.gpu_context,
|
||||||
context.min_size,
|
context.min_size,
|
||||||
|
context.appearance,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
Ok(Rc::new_cyclic(|this| Self {
|
Ok(Rc::new_cyclic(|this| Self {
|
||||||
|
@ -338,6 +342,7 @@ struct WindowCreateContext<'a> {
|
||||||
main_receiver: flume::Receiver<Runnable>,
|
main_receiver: flume::Receiver<Runnable>,
|
||||||
gpu_context: &'a BladeContext,
|
gpu_context: &'a BladeContext,
|
||||||
main_thread_id_win32: u32,
|
main_thread_id_win32: u32,
|
||||||
|
appearance: WindowAppearance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsWindow {
|
impl WindowsWindow {
|
||||||
|
@ -387,6 +392,7 @@ impl WindowsWindow {
|
||||||
} else {
|
} else {
|
||||||
WindowsDisplay::primary_monitor().unwrap()
|
WindowsDisplay::primary_monitor().unwrap()
|
||||||
};
|
};
|
||||||
|
let appearance = system_appearance().unwrap_or_default();
|
||||||
let mut context = WindowCreateContext {
|
let mut context = WindowCreateContext {
|
||||||
inner: None,
|
inner: None,
|
||||||
handle,
|
handle,
|
||||||
|
@ -403,6 +409,7 @@ impl WindowsWindow {
|
||||||
main_receiver,
|
main_receiver,
|
||||||
gpu_context,
|
gpu_context,
|
||||||
main_thread_id_win32,
|
main_thread_id_win32,
|
||||||
|
appearance,
|
||||||
};
|
};
|
||||||
let lpparam = Some(&context as *const _ as *const _);
|
let lpparam = Some(&context as *const _ as *const _);
|
||||||
let creation_result = unsafe {
|
let creation_result = unsafe {
|
||||||
|
@ -426,7 +433,7 @@ impl WindowsWindow {
|
||||||
let state_ptr = context.inner.take().unwrap()?;
|
let state_ptr = context.inner.take().unwrap()?;
|
||||||
let hwnd = creation_result?;
|
let hwnd = creation_result?;
|
||||||
register_drag_drop(state_ptr.clone())?;
|
register_drag_drop(state_ptr.clone())?;
|
||||||
configure_dwm_dark_mode(hwnd);
|
configure_dwm_dark_mode(hwnd, appearance);
|
||||||
state_ptr.state.borrow_mut().border_offset.update(hwnd)?;
|
state_ptr.state.borrow_mut().border_offset.update(hwnd)?;
|
||||||
let placement = retrieve_window_placement(
|
let placement = retrieve_window_placement(
|
||||||
hwnd,
|
hwnd,
|
||||||
|
@ -543,7 +550,7 @@ impl PlatformWindow for WindowsWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appearance(&self) -> WindowAppearance {
|
fn appearance(&self) -> WindowAppearance {
|
||||||
system_appearance().log_err().unwrap_or_default()
|
self.0.state.borrow().appearance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
|
fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
|
||||||
|
@ -951,7 +958,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct ClickState {
|
pub(crate) struct ClickState {
|
||||||
button: MouseButton,
|
button: MouseButton,
|
||||||
last_click: Instant,
|
last_click: Instant,
|
||||||
|
@ -993,10 +1000,25 @@ impl ClickState {
|
||||||
self.current_count
|
self.current_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system_update(&mut self) {
|
pub fn system_update(&mut self, wparam: usize) {
|
||||||
self.double_click_spatial_tolerance_width = unsafe { GetSystemMetrics(SM_CXDOUBLECLK) };
|
match wparam {
|
||||||
self.double_click_spatial_tolerance_height = unsafe { GetSystemMetrics(SM_CYDOUBLECLK) };
|
// SPI_SETDOUBLECLKWIDTH
|
||||||
self.double_click_interval = Duration::from_millis(unsafe { GetDoubleClickTime() } as u64);
|
29 => {
|
||||||
|
self.double_click_spatial_tolerance_width =
|
||||||
|
unsafe { GetSystemMetrics(SM_CXDOUBLECLK) }
|
||||||
|
}
|
||||||
|
// SPI_SETDOUBLECLKHEIGHT
|
||||||
|
30 => {
|
||||||
|
self.double_click_spatial_tolerance_height =
|
||||||
|
unsafe { GetSystemMetrics(SM_CYDOUBLECLK) }
|
||||||
|
}
|
||||||
|
// SPI_SETDOUBLECLICKTIME
|
||||||
|
32 => {
|
||||||
|
self.double_click_interval =
|
||||||
|
Duration::from_millis(unsafe { GetDoubleClickTime() } as u64)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue