Adopt windows-sys (#2057)

This commit is contained in:
Clemens Wasser 2022-03-07 22:58:12 +01:00 committed by GitHub
parent 78e5a395da
commit b222dde835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1424 additions and 1239 deletions

View file

@ -1,29 +1,35 @@
/// This is a simple implementation of support for Windows Dark Mode,
/// which is inspired by the solution in https://github.com/ysc3839/win32-darkmode
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::{ffi::c_void, ptr};
use winapi::{
shared::{
basetsd::SIZE_T,
minwindef::{BOOL, DWORD, FALSE, WORD},
ntdef::{NTSTATUS, NT_SUCCESS, PVOID},
windef::HWND,
winerror::S_OK,
use windows_sys::{
core::PCSTR,
Win32::{
Foundation::{BOOL, HWND, NTSTATUS, S_OK},
System::{
LibraryLoader::{GetProcAddress, LoadLibraryA},
SystemInformation::OSVERSIONINFOW,
},
UI::{
Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA},
Controls::SetWindowTheme,
WindowsAndMessaging::{SystemParametersInfoA, SPI_GETHIGHCONTRAST},
},
},
um::{libloaderapi, uxtheme, winnt, winuser},
};
use crate::window::Theme;
use super::util;
lazy_static! {
static ref WIN10_BUILD_VERSION: Option<DWORD> = {
type RtlGetVersion = unsafe extern "system" fn (*mut winnt::OSVERSIONINFOW) -> NTSTATUS;
static ref WIN10_BUILD_VERSION: Option<u32> = {
type RtlGetVersion = unsafe extern "system" fn (*mut OSVERSIONINFOW) -> NTSTATUS;
let handle = get_function!("ntdll.dll", RtlGetVersion);
if let Some(rtl_get_version) = handle {
unsafe {
let mut vi = winnt::OSVERSIONINFOW {
let mut vi = OSVERSIONINFOW {
dwOSVersionInfoSize: 0,
dwMajorVersion: 0,
dwMinorVersion: 0,
@ -32,9 +38,9 @@ lazy_static! {
szCSDVersion: [0; 128],
};
let status = (rtl_get_version)(&mut vi as _);
let status = (rtl_get_version)(&mut vi);
if NT_SUCCESS(status) && vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0 {
if status >= 0 && vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0 {
Some(vi.dwBuildNumber)
} else {
None
@ -54,8 +60,8 @@ lazy_static! {
}
};
static ref DARK_THEME_NAME: Vec<u16> = widestring("DarkMode_Explorer");
static ref LIGHT_THEME_NAME: Vec<u16> = widestring("");
static ref DARK_THEME_NAME: Vec<u16> = util::encode_wide("DarkMode_Explorer");
static ref LIGHT_THEME_NAME: Vec<u16> = util::encode_wide("");
}
/// Attempt to set a theme on a window, if necessary.
@ -77,7 +83,7 @@ pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
};
let status = unsafe { uxtheme::SetWindowTheme(hwnd, theme_name as _, std::ptr::null()) };
let status = unsafe { SetWindowTheme(hwnd, theme_name, ptr::null()) };
if status == S_OK && set_dark_mode_for_window(hwnd, is_dark_mode) {
return theme;
@ -103,8 +109,8 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
#[repr(C)]
struct WINDOWCOMPOSITIONATTRIBDATA {
Attrib: WINDOWCOMPOSITIONATTRIB,
pvData: PVOID,
cbData: SIZE_T,
pvData: *mut c_void,
cbData: usize,
}
lazy_static! {
@ -115,7 +121,7 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
if let Some(set_window_composition_attribute) = *SET_WINDOW_COMPOSITION_ATTRIBUTE {
unsafe {
// SetWindowCompositionAttribute needs a bigbool (i32), not bool.
let mut is_dark_mode_bigbool = is_dark_mode as BOOL;
let mut is_dark_mode_bigbool = BOOL::from(is_dark_mode);
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
Attrib: WCA_USEDARKMODECOLORS,
@ -123,9 +129,9 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
cbData: std::mem::size_of_val(&is_dark_mode_bigbool) as _,
};
let status = set_window_composition_attribute(hwnd, &mut data as *mut _);
let status = set_window_composition_attribute(hwnd, &mut data);
status != FALSE
status != false.into()
}
} else {
false
@ -141,24 +147,17 @@ fn should_apps_use_dark_mode() -> bool {
lazy_static! {
static ref SHOULD_APPS_USE_DARK_MODE: Option<ShouldAppsUseDarkMode> = {
unsafe {
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: WORD = 132;
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: PCSTR = 132 as PCSTR;
let module = libloaderapi::LoadLibraryA("uxtheme.dll\0".as_ptr() as _);
let module = LoadLibraryA("uxtheme.dll\0".as_ptr());
if module.is_null() {
if module == 0 {
return None;
}
let handle = libloaderapi::GetProcAddress(
module,
winuser::MAKEINTRESOURCEA(UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL),
);
let handle = GetProcAddress(module, UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL);
if handle.is_null() {
None
} else {
Some(std::mem::transmute(handle))
}
handle.map(|handle| std::mem::transmute(handle))
}
};
}
@ -169,27 +168,20 @@ fn should_apps_use_dark_mode() -> bool {
}
fn is_high_contrast() -> bool {
let mut hc = winuser::HIGHCONTRASTA {
let mut hc = HIGHCONTRASTA {
cbSize: 0,
dwFlags: 0,
lpszDefaultScheme: std::ptr::null_mut(),
lpszDefaultScheme: ptr::null_mut(),
};
let ok = unsafe {
winuser::SystemParametersInfoA(
winuser::SPI_GETHIGHCONTRAST,
SystemParametersInfoA(
SPI_GETHIGHCONTRAST,
std::mem::size_of_val(&hc) as _,
&mut hc as *mut _ as _,
0,
)
};
ok != FALSE && (winuser::HCF_HIGHCONTRASTON & hc.dwFlags) == 1
}
fn widestring(src: &'static str) -> Vec<u16> {
OsStr::new(src)
.encode_wide()
.chain(Some(0).into_iter())
.collect()
ok != false.into() && util::has_flag(hc.dwFlags, HCF_HIGHCONTRASTON)
}