use std::sync::OnceLock;
use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM};
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
use windows_sys::Win32::UI::Shell::{DefSubclassProc, RemoveWindowSubclass, SetWindowSubclass};
use windows_sys::Win32::UI::WindowsAndMessaging::{WM_DESTROY, WM_FONTCHANGE, WM_SETTINGCHANGE};
const SUBCLASS_ID: usize = 0x6b7574;
const FIRST_BUILD: u32 = 17763;
pub fn install(window: &winit::window::Window) -> bool {
use winit::raw_window_handle::{HasWindowHandle, RawWindowHandle};
let Ok(handle) = window.window_handle() else {
return false;
};
let RawWindowHandle::Win32(h) = handle.as_raw() else {
return false;
};
unsafe { SetWindowSubclass(h.hwnd.get() as HWND, Some(subclass_proc), SUBCLASS_ID, 0) != 0 }
}
unsafe extern "system" fn subclass_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
_id: usize,
_data: usize,
) -> LRESULT {
match msg {
WM_SETTINGCHANGE if is_color_scheme_change(lparam) => {
if let Some(refresh) = refresh_policy() {
unsafe { refresh() };
}
}
WM_FONTCHANGE => crate::system_fonts::changed(),
WM_DESTROY => unsafe {
RemoveWindowSubclass(hwnd, Some(subclass_proc), SUBCLASS_ID);
},
_ => {}
}
unsafe { DefSubclassProc(hwnd, msg, wparam, lparam) }
}
fn is_color_scheme_change(lparam: LPARAM) -> bool {
if lparam == 0 {
return false;
}
let area = lparam as *const u16;
let mut len = 0;
while len < 64 && unsafe { *area.add(len) } != 0 {
len += 1;
}
let area = unsafe { std::slice::from_raw_parts(area, len) };
String::from_utf16(area).is_ok_and(|a| a.eq_ignore_ascii_case("ImmersiveColorSet"))
}
type RefreshImmersiveColorPolicyState = unsafe extern "system" fn();
fn refresh_policy() -> Option<RefreshImmersiveColorPolicyState> {
static REFRESH: OnceLock<Option<RefreshImmersiveColorPolicyState>> = OnceLock::new();
*REFRESH.get_or_init(|| {
if windows_build()? < FIRST_BUILD {
return None;
}
let module = unsafe { LoadLibraryA(c"uxtheme.dll".as_ptr().cast()) };
if module == 0 {
return None;
}
const ORDINAL: usize = 104;
let f = unsafe { GetProcAddress(module, ORDINAL as *const u8) }?;
Some(unsafe {
std::mem::transmute::<
unsafe extern "system" fn() -> isize,
RefreshImmersiveColorPolicyState,
>(f)
})
})
}
fn windows_build() -> Option<u32> {
#[repr(C)]
struct OsVersionInfoW {
size: u32,
major: u32,
minor: u32,
build: u32,
platform: u32,
csd: [u16; 128],
}
type RtlGetVersion = unsafe extern "system" fn(*mut OsVersionInfoW) -> i32;
let module = unsafe { LoadLibraryA(c"ntdll.dll".as_ptr().cast()) };
if module == 0 {
return None;
}
let f = unsafe { GetProcAddress(module, c"RtlGetVersion".as_ptr().cast()) }?;
let f =
unsafe { std::mem::transmute::<unsafe extern "system" fn() -> isize, RtlGetVersion>(f) };
let mut info = OsVersionInfoW {
size: size_of::<OsVersionInfoW>() as u32,
major: 0,
minor: 0,
build: 0,
platform: 0,
csd: [0; 128],
};
(unsafe { f(&mut info) } >= 0 && info.major == 10).then_some(info.build)
}
#[cfg(test)]
mod tests {
use super::*;
fn wide(s: &str) -> Vec<u16> {
s.encode_utf16().chain([0]).collect()
}
#[test]
fn only_the_colour_scheme_is_a_colour_scheme_change() {
let set = wide("ImmersiveColorSet");
assert!(is_color_scheme_change(set.as_ptr() as LPARAM));
let lower = wide("immersivecolorset");
assert!(is_color_scheme_change(lower.as_ptr() as LPARAM));
let other = wide("intl");
assert!(!is_color_scheme_change(other.as_ptr() as LPARAM));
assert!(!is_color_scheme_change(0));
}
#[test]
fn the_refresh_is_found_on_this_build() {
assert!(windows_build().is_some_and(|b| b >= FIRST_BUILD));
assert!(refresh_policy().is_some());
}
}