Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(windows): blinking title bar on changing system settings #983

Merged
Merged
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
5 changes: 5 additions & 0 deletions .changes/windows-theme-redraw-titlebar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Fix blinking title bar when changing system settings on Windows
24 changes: 15 additions & 9 deletions src/platform_impl/windows/dark_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ fn refresh_immersive_color_policy_state() {

/// Attempt to set a theme on a window, if necessary.
/// Returns the theme that was picked
pub fn try_window_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
pub fn try_window_theme(
hwnd: HWND,
preferred_theme: Option<Theme>,
redraw_title_bar: bool,
) -> Theme {
if *DARK_MODE_SUPPORTED {
let is_dark_mode = match preferred_theme {
Some(theme) => theme == Theme::Dark,
Expand All @@ -131,7 +135,7 @@ pub fn try_window_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
false => Theme::Light,
};

refresh_titlebar_theme_color(hwnd, is_dark_mode);
refresh_titlebar_theme_color(hwnd, is_dark_mode, redraw_title_bar);

theme
} else {
Expand Down Expand Up @@ -161,7 +165,7 @@ pub fn allow_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) {
}
}

fn refresh_titlebar_theme_color(hwnd: HWND, is_dark_mode: bool) {
fn refresh_titlebar_theme_color(hwnd: HWND, is_dark_mode: bool, redraw_title_bar: bool) {
if let Some(ver) = *WIN10_BUILD_VERSION {
if ver < 17763 {
let mut is_dark_mode_bigbool: i32 = is_dark_mode.into();
Expand All @@ -187,12 +191,14 @@ fn refresh_titlebar_theme_color(hwnd: HWND, is_dark_mode: bool) {
&dark_mode as *const BOOL as *const c_void,
std::mem::size_of::<BOOL>() as u32,
);
if GetActiveWindow() == hwnd {
DefWindowProcW(hwnd, WM_NCACTIVATE, None, None);
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM(true.into()), None);
} else {
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM(true.into()), None);
DefWindowProcW(hwnd, WM_NCACTIVATE, None, None);
if redraw_title_bar {
if GetActiveWindow() == hwnd {
DefWindowProcW(hwnd, WM_NCACTIVATE, None, None);
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM(true.into()), None);
} else {
DefWindowProcW(hwnd, WM_NCACTIVATE, WPARAM(true.into()), None);
DefWindowProcW(hwnd, WM_NCACTIVATE, None, None);
}
}
}
}
Expand Down
53 changes: 35 additions & 18 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ impl<T> EventLoopWindowTarget<T> {
pub fn set_theme(&self, theme: Option<Theme>) {
*self.preferred_theme.lock() = theme;
self.runner_shared.owned_windows(|window| {
let _ = unsafe { SendMessageW(window, WM_SETTINGCHANGE, WPARAM(0), LPARAM(0)) };
let _ = unsafe { SendMessageW(window, *CHANGE_THEME_MSG_ID, WPARAM(0), LPARAM(0)) };
});
}
}
Expand Down Expand Up @@ -624,6 +624,11 @@ lazy_static! {
pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
RegisterWindowMessageA(s!("Tao::SetRetainMaximized"))
};
/// Message sent by event loop when event loop's prefered theme changed.
/// WPARAM and LPARAM are unused.
pub static ref CHANGE_THEME_MSG_ID: u32 = unsafe {
RegisterWindowMessageA(s!("Tao::ChangeTheme"))
};
/// When the taskbar is created, it registers a message with the "TaskbarCreated" string and then broadcasts this message to all top-level windows
/// When the application receives this message, it should assume that any taskbar icons it added have been removed and add them again.
pub static ref S_U_TASKBAR_RESTART: u32 = unsafe {
Expand Down Expand Up @@ -2072,23 +2077,7 @@ unsafe fn public_window_callback_inner<T: 'static>(
}

win32wm::WM_SETTINGCHANGE => {
use crate::event::WindowEvent::ThemeChanged;

let preferred_theme = subclass_input.window_state.lock().preferred_theme;
let new_theme = try_window_theme(
window,
preferred_theme.or(*subclass_input.event_loop_preferred_theme.lock()),
);
let mut window_state = subclass_input.window_state.lock();

if window_state.current_theme != new_theme {
window_state.current_theme = new_theme;
mem::drop(window_state);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window.0 as _)),
event: ThemeChanged(new_theme),
});
}
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved
update_theme(subclass_input, window, true);
}

win32wm::WM_NCCALCSIZE => {
Expand Down Expand Up @@ -2197,6 +2186,9 @@ unsafe fn public_window_callback_inner<T: 'static>(
f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam.0 != 0)
});
result = ProcResult::Value(LRESULT(0));
} else if msg == *CHANGE_THEME_MSG_ID {
update_theme(subclass_input, window, false);
result = ProcResult::Value(LRESULT(0));
} else if msg == *S_U_TASKBAR_RESTART {
let window_state = subclass_input.window_state.lock();
let _ = set_skip_taskbar(window, window_state.skip_taskbar);
Expand All @@ -2216,6 +2208,31 @@ unsafe fn public_window_callback_inner<T: 'static>(
}
}

fn update_theme<T>(
subclass_input: &SubclassInput<T>,
window: HWND,
from_settings_change_event: bool,
) {
let mut window_state = subclass_input.window_state.lock();
let preferred_theme = window_state
.preferred_theme
.or(*subclass_input.event_loop_preferred_theme.lock());
if from_settings_change_event && preferred_theme.is_some() {
return;
}
let new_theme = try_window_theme(window, preferred_theme, !from_settings_change_event);
if window_state.current_theme != new_theme {
window_state.current_theme = new_theme;
mem::drop(window_state);
unsafe {
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window.0 as _)),
event: WindowEvent::ThemeChanged(new_theme),
})
};
}
}

fn is_show_window_contents_while_dragging_enabled() -> bool {
let mut is_enabled: BOOL = BOOL(0);
let result = unsafe {
Expand Down
8 changes: 6 additions & 2 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ use crate::{
},
};

use super::keyboard::{KeyEventBuilder, KEY_EVENT_BUILDERS};
use super::{
event_loop::CHANGE_THEME_MSG_ID,
keyboard::{KeyEventBuilder, KEY_EVENT_BUILDERS},
};

/// A simple non-owning wrapper around a window.
#[derive(Clone, Copy)]
Expand Down Expand Up @@ -940,7 +943,7 @@ impl Window {
}
window_state.preferred_theme = theme;
}
unsafe { SendMessageW(self.hwnd(), WM_SETTINGCHANGE, WPARAM(0), LPARAM(0)) };
unsafe { SendMessageW(self.hwnd(), *CHANGE_THEME_MSG_ID, WPARAM(0), LPARAM(0)) };
}

#[inline]
Expand Down Expand Up @@ -1163,6 +1166,7 @@ unsafe fn init<T: 'static>(
attributes
.preferred_theme
.or(*event_loop.preferred_theme.lock()),
false,
);

let window_state = {
Expand Down
Loading