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

Use windows-rs instead of winapi-rs #1938

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 11 additions & 28 deletions Cargo.toml
Expand Up @@ -14,7 +14,14 @@ categories = ["gui"]
[package.metadata.docs.rs]
features = ["serde", "web-sys"]
default-target = "x86_64-unknown-linux-gnu"
targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "wasm32-unknown-unknown"]
targets = [
"i686-pc-windows-msvc",
"x86_64-pc-windows-msvc",
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
"wasm32-unknown-unknown",
]

[features]
default = ["x11", "wayland"]
Expand Down Expand Up @@ -59,34 +66,10 @@ features = ["display_link"]

[target.'cfg(target_os = "windows")'.dependencies]
parking_lot = "0.11"

[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3.6"
features = [
"combaseapi",
"commctrl",
"dwmapi",
"errhandlingapi",
"imm",
"hidusage",
"libloaderapi",
"objbase",
"ole2",
"processthreadsapi",
"shellapi",
"shellscalingapi",
"shobjidl_core",
"unknwnbase",
"winbase",
"windowsx",
"winerror",
"wingdi",
"winnt",
"winuser",
]
winapi = { path = "winapi" }

[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
wayland-client = { version = "0.28", features = [ "dlopen"] , optional = true }
wayland-client = { version = "0.28", features = ["dlopen"], optional = true }
sctk = { package = "smithay-client-toolkit", version = "0.12.3", optional = true }
mio = { version = "0.7", features = ["os-ext"], optional = true }
mio-misc = { version = "1.0", optional = true }
Expand Down Expand Up @@ -118,7 +101,7 @@ features = [
'Node',
'PointerEvent',
'Window',
'WheelEvent'
'WheelEvent',
]

[target.'cfg(target_arch = "wasm32")'.dependencies.wasm-bindgen]
Expand Down
26 changes: 13 additions & 13 deletions src/platform/windows.rs
Expand Up @@ -3,9 +3,9 @@
use std::os::raw::c_void;
use std::path::Path;

use libc;
use winapi::shared::minwindef::WORD;
use winapi::shared::windef::{HMENU, HWND};
use winapi::Windows::Win32::UI::{
KeyboardAndMouseInput::EnableWindow, MenusAndResources::HMENU, WindowsAndMessaging::HWND,
};

use crate::{
dpi::PhysicalSize,
Expand Down Expand Up @@ -72,11 +72,11 @@ impl<T> EventLoopExtWindows for EventLoop<T> {
/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExtWindows {
/// Returns the HINSTANCE of the window
fn hinstance(&self) -> *mut libc::c_void;
fn hinstance(&self) -> *mut c_void;
/// Returns the native handle that is used by this window.
///
/// The pointer will become invalid when the native window was destroyed.
fn hwnd(&self) -> *mut libc::c_void;
fn hwnd(&self) -> *mut c_void;

/// Enables or disables mouse and keyboard input to the specified window.
///
Expand All @@ -102,19 +102,19 @@ pub trait WindowExtWindows {

impl WindowExtWindows for Window {
#[inline]
fn hinstance(&self) -> *mut libc::c_void {
self.window.hinstance() as *mut _
fn hinstance(&self) -> *mut c_void {
self.window.hinstance().0 as *mut _
}

#[inline]
fn hwnd(&self) -> *mut libc::c_void {
self.window.hwnd() as *mut _
fn hwnd(&self) -> *mut c_void {
self.window.hwnd().0 as *mut _
}

#[inline]
fn set_enable(&self, enabled: bool) {
unsafe {
winapi::um::winuser::EnableWindow(self.hwnd() as _, enabled as _);
EnableWindow(HWND(self.hwnd() as isize), enabled);
}
}

Expand Down Expand Up @@ -239,7 +239,7 @@ impl MonitorHandleExtWindows for MonitorHandle {

#[inline]
fn hmonitor(&self) -> *mut c_void {
self.inner.hmonitor() as *mut _
self.inner.hmonitor().0 as *mut _
}
}

Expand Down Expand Up @@ -277,7 +277,7 @@ pub trait IconExtWindows: Sized {
///
/// In cases where the specified size does not exist in the file, Windows may perform scaling
/// to get an icon of the desired size.
fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
fn from_resource(ordinal: u32, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
}

impl IconExtWindows for Icon {
Expand All @@ -289,7 +289,7 @@ impl IconExtWindows for Icon {
Ok(Icon { inner: win_icon })
}

fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
fn from_resource(ordinal: u32, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_resource(ordinal, size)?;
Ok(Icon { inner: win_icon })
}
Expand Down
172 changes: 60 additions & 112 deletions src/platform_impl/windows/dark_mode.rs
@@ -1,73 +1,49 @@
use std::os::windows::ffi::OsStrExt;
/// 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 winapi::{
shared::{
basetsd::SIZE_T,
minwindef::{BOOL, DWORD, FALSE, UINT, ULONG, WORD},
ntdef::{LPSTR, NTSTATUS, NT_SUCCESS, PVOID, WCHAR},
windef::HWND,
winerror::S_OK,
use std::{ffi::OsStr, iter::once};

use winapi::Windows::Win32::{
System::{
SystemServices::{
GetProcAddress, LoadLibraryA, BOOL, PSTR, PWSTR, VER_EQUAL, VER_GREATER_EQUAL,
},
WindowsProgramming::{
VerSetConditionMask, VerifyVersionInfoW, OSVERSIONINFOEXW, VER_BUILDNUMBER,
VER_MAJORVERSION, VER_MINORVERSION,
},
},
UI::{
Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA},
Controls::SetWindowTheme,
WindowsAndMessaging::{
SystemParametersInfoA, HWND, SPI_GETHIGHCONTRAST, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS,
},
},
um::{libloaderapi, uxtheme, winuser},
};

use crate::window::Theme;

lazy_static! {
static ref WIN10_BUILD_VERSION: Option<DWORD> = {
// FIXME: RtlGetVersion is a documented windows API,
// should be part of winapi!

#[allow(non_snake_case)]
#[repr(C)]
struct OSVERSIONINFOW {
dwOSVersionInfoSize: ULONG,
dwMajorVersion: ULONG,
dwMinorVersion: ULONG,
dwBuildNumber: ULONG,
dwPlatformId: ULONG,
szCSDVersion: [WCHAR; 128],
}

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 = OSVERSIONINFOW {
dwOSVersionInfoSize: 0,
dwMajorVersion: 0,
dwMinorVersion: 0,
dwBuildNumber: 0,
dwPlatformId: 0,
szCSDVersion: [0; 128],
};

let status = (rtl_get_version)(&mut vi as _);

if NT_SUCCESS(status) && vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0 {
Some(vi.dwBuildNumber)
} else {
None
}
}
} else {
None
}
};

static ref DARK_MODE_SUPPORTED: bool = {
// We won't try to do anything for windows versions < 17763
// (Windows 10 October 2018 update)
match *WIN10_BUILD_VERSION {
Some(v) => v >= 17763,
None => false
}
let mut condition_mask = 0;
condition_mask = VerSetConditionMask(condition_mask, VER_MAJORVERSION, VER_EQUAL as u8);
condition_mask = VerSetConditionMask(condition_mask, VER_MINORVERSION, VER_EQUAL as u8);
condition_mask =
VerSetConditionMask(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL as u8);

VerifyVersionInfoW(
&mut OSVERSIONINFOEXW {
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: 17763,
..Default::default()
},
VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER,
condition_mask,
)
.as_bool()
};

static ref DARK_THEME_NAME: Vec<u16> = widestring("DarkMode_Explorer");
static ref LIGHT_THEME_NAME: Vec<u16> = widestring("");
}
Expand All @@ -87,13 +63,13 @@ pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
Theme::Light
};
let theme_name = match theme {
Theme::Dark => DARK_THEME_NAME.as_ptr(),
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
Theme::Dark => DARK_THEME_NAME.as_mut_ptr(),
Theme::Light => LIGHT_THEME_NAME.as_mut_ptr(),
};

let status = unsafe { uxtheme::SetWindowTheme(hwnd, theme_name as _, std::ptr::null()) };
let status = unsafe { SetWindowTheme(hwnd, PWSTR(theme_name), None) };

if status == S_OK && set_dark_mode_for_window(hwnd, is_dark_mode) {
if status.is_ok() && set_dark_mode_for_window(hwnd, is_dark_mode) {
return theme;
}
}
Expand All @@ -116,8 +92,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 std::os::raw::c_void,
cbData: usize,
}

lazy_static! {
Expand All @@ -128,17 +104,15 @@ 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 = is_dark_mode.into();

let mut data = WINDOWCOMPOSITIONATTRIBDATA {
Attrib: WCA_USEDARKMODECOLORS,
pvData: &mut is_dark_mode_bigbool as *mut _ as _,
cbData: std::mem::size_of_val(&is_dark_mode_bigbool) as _,
};

let status = set_window_composition_attribute(hwnd, &mut data as *mut _);

status != FALSE
set_window_composition_attribute(hwnd, &mut data as *mut _).as_bool()
}
} else {
false
Expand All @@ -153,26 +127,20 @@ fn should_apps_use_dark_mode() -> bool {
type ShouldAppsUseDarkMode = unsafe extern "system" fn() -> bool;
lazy_static! {
static ref SHOULD_APPS_USE_DARK_MODE: Option<ShouldAppsUseDarkMode> = {
unsafe {
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: WORD = 132;

let module = libloaderapi::LoadLibraryA("uxtheme.dll\0".as_ptr() as _);
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: u32 = 132;

if module.is_null() {
return None;
}
let module = unsafe { LoadLibraryA(PSTR("uxtheme.dll".as_mut_ptr())) };
if module.is_null() {
return None;
}

let handle = libloaderapi::GetProcAddress(
unsafe {
GetProcAddress(
module,
winuser::MAKEINTRESOURCEA(UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL),
);

if handle.is_null() {
None
} else {
Some(std::mem::transmute(handle))
}
PSTR(UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL as *mut u8),
)
}
.map(|func| std::mem::transmute(func))
};
}

Expand All @@ -181,41 +149,21 @@ fn should_apps_use_dark_mode() -> bool {
.unwrap_or(false)
}

// FIXME: This definition was missing from winapi. Can remove from
// here and use winapi once the following PR is released:
// https://github.com/retep998/winapi-rs/pull/815
#[repr(C)]
#[allow(non_snake_case)]
struct HIGHCONTRASTA {
cbSize: UINT,
dwFlags: DWORD,
lpszDefaultScheme: LPSTR,
}

const HCF_HIGHCONTRASTON: DWORD = 1;

fn is_high_contrast() -> bool {
let mut hc = HIGHCONTRASTA {
cbSize: 0,
dwFlags: 0,
lpszDefaultScheme: std::ptr::null_mut(),
};
let mut hc: HIGHCONTRASTA = unsafe { std::mem::zeroed() };

let ok = unsafe {
winuser::SystemParametersInfoA(
winuser::SPI_GETHIGHCONTRAST,
SystemParametersInfoA(
SPI_GETHIGHCONTRAST,
std::mem::size_of_val(&hc) as _,
&mut hc as *mut _ as _,
0,
SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
)
};

ok != FALSE && (HCF_HIGHCONTRASTON & hc.dwFlags) == 1
!ok.as_bool() && (HCF_HIGHCONTRASTON & hc.dwFlags) == HCF_HIGHCONTRASTON
}

fn widestring(src: &'static str) -> Vec<u16> {
OsStr::new(src)
.encode_wide()
.chain(Some(0).into_iter())
.collect()
OsStr::new(src).encode_wide().chain(once(0)).collect()
}