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

@ -21,6 +21,8 @@ And please only add new entries to the top of this list, right below the `# Unre
- **Breaking:** Replaced `EventLoopExtMacOS` with `EventLoopBuilderExtMacOS` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtWindows` with `EventLoopBuilderExtWindows` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtUnix` with `EventLoopBuilderExtUnix` (which also has renamed methods).
- **Breaking:** The platform specific extensions for Windows `winit::platform::windows` have changed. All `HANDLE`-like types e.g. `HWND` and `HMENU` were converted from winapi types or `*mut c_void` to `isize`. This was done to be consistent with the type definitions in windows-sys and to not expose internal dependencies.
- The internal bindings to the [Windows API](https://docs.microsoft.com/en-us/windows/) were changed from the unofficial [winapi](https://github.com/retep998/winapi-rs) bindings to the official Microsoft [windows-sys](https://github.com/microsoft/windows-rs) bindings.
- On Wayland, fix resize and scale factor changes not being propagated properly.
# 0.26.1 (2022-01-05)

View file

@ -55,33 +55,35 @@ default_features = false
features = ["display_link"]
[target.'cfg(target_os = "windows")'.dependencies]
parking_lot = "0.11"
parking_lot = "0.12"
[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3.9"
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.33"
features = [
"combaseapi",
"commctrl",
"dwmapi",
"errhandlingapi",
"imm",
"hidusage",
"libloaderapi",
"objbase",
"ole2",
"processthreadsapi",
"shellapi",
"shellscalingapi",
"shobjidl_core",
"unknwnbase",
"winbase",
"windowsx",
"winerror",
"wingdi",
"winnt",
"winuser",
"mmsystem",
"timeapi"
"Win32_Devices_HumanInterfaceDevice",
"Win32_Foundation",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Win32_Graphics_Gdi",
"Win32_Media",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
"Win32_UI_Accessibility",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
"Win32_UI_Input_Ime",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Input_Pointer",
"Win32_UI_Input_Touch",
"Win32_UI_Shell",
"Win32_UI_TextServices",
"Win32_UI_WindowsAndMessaging",
]
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
@ -91,7 +93,7 @@ sctk = { package = "smithay-client-toolkit", version = "0.15.1", default_feature
mio = { version = "0.8", features = ["os-ext"], optional = true }
x11-dl = { version = "2.18.5", optional = true }
percent-encoding = { version = "2.0", optional = true }
parking_lot = { version = "0.11.0", optional = true }
parking_lot = { version = "0.12.0", optional = true }
libc = "0.2.64"
[target.'cfg(target_arch = "wasm32")'.dependencies.web_sys]

View file

@ -1,11 +1,7 @@
#![cfg(target_os = "windows")]
use std::os::raw::c_void;
use std::path::Path;
use winapi::shared::minwindef::WORD;
use winapi::shared::windef::{HMENU, HWND};
use crate::{
dpi::PhysicalSize,
event::DeviceId,
@ -15,6 +11,15 @@ use crate::{
window::{BadIcon, Icon, Theme, Window, WindowBuilder},
};
/// Window Handle type used by Win32 API
pub type HWND = isize;
/// Menu Handle type used by Win32 API
pub type HMENU = isize;
/// Monitor Handle type used by Win32 API
pub type HMONITOR = isize;
/// Instance Handle type used by Win32 API
pub type HINSTANCE = isize;
/// Additional methods on `EventLoop` that are specific to Windows.
pub trait EventLoopBuilderExtWindows {
/// Whether to allow the event loop to be created off of the main thread.
@ -70,11 +75,11 @@ impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExtWindows {
/// Returns the HINSTANCE of the window
fn hinstance(&self) -> *mut c_void;
fn hinstance(&self) -> HINSTANCE;
/// 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 c_void;
fn hwnd(&self) -> HWND;
/// Enables or disables mouse and keyboard input to the specified window.
///
@ -100,13 +105,13 @@ pub trait WindowExtWindows {
impl WindowExtWindows for Window {
#[inline]
fn hinstance(&self) -> *mut c_void {
self.window.hinstance() as *mut _
fn hinstance(&self) -> HINSTANCE {
self.window.hinstance()
}
#[inline]
fn hwnd(&self) -> *mut c_void {
self.window.hwnd() as *mut _
fn hwnd(&self) -> HWND {
self.window.hwnd()
}
#[inline]
@ -150,10 +155,12 @@ pub trait WindowBuilderExtWindows {
///
/// Parent and menu are mutually exclusive; a child window cannot have a menu!
///
/// The menu must have been manually created beforehand with [`winapi::um::winuser::CreateMenu`] or similar.
/// The menu must have been manually created beforehand with [`CreateMenu`] or similar.
///
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
/// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
///
/// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu
fn with_menu(self, menu: HMENU) -> WindowBuilder;
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
@ -224,7 +231,7 @@ pub trait MonitorHandleExtWindows {
fn native_id(&self) -> String;
/// Returns the handle of the monitor - `HMONITOR`.
fn hmonitor(&self) -> *mut c_void;
fn hmonitor(&self) -> HMONITOR;
}
impl MonitorHandleExtWindows for MonitorHandle {
@ -234,8 +241,8 @@ impl MonitorHandleExtWindows for MonitorHandle {
}
#[inline]
fn hmonitor(&self) -> *mut c_void {
self.inner.hmonitor() as *mut _
fn hmonitor(&self) -> HMONITOR {
self.inner.hmonitor()
}
}
@ -273,7 +280,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: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
}
impl IconExtWindows for Icon {
@ -285,7 +292,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: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_resource(ordinal, size)?;
Ok(Icon { inner: win_icon })
}

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)
}

View file

@ -0,0 +1,140 @@
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
use std::ffi::c_void;
use windows_sys::{
core::{IUnknown, GUID, HRESULT},
Win32::{
Foundation::{BOOL, HWND, POINTL},
System::Com::{
IAdviseSink, IDataObject, IEnumFORMATETC, IEnumSTATDATA, FORMATETC, STGMEDIUM,
},
UI::Shell::ITaskbarList,
},
};
#[repr(C)]
pub struct IUnknownVtbl {
pub QueryInterface: unsafe extern "system" fn(
This: *mut IUnknown,
riid: *const GUID,
ppvObject: *mut *mut c_void,
) -> HRESULT,
pub AddRef: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
pub Release: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
}
#[repr(C)]
pub struct IDataObjectVtbl {
pub parent: IUnknownVtbl,
pub GetData: unsafe extern "system" fn(
This: *mut IDataObject,
pformatetcIn: *const FORMATETC,
pmedium: *mut STGMEDIUM,
) -> HRESULT,
pub GetDataHere: unsafe extern "system" fn(
This: *mut IDataObject,
pformatetc: *const FORMATETC,
pmedium: *mut STGMEDIUM,
) -> HRESULT,
QueryGetData:
unsafe extern "system" fn(This: *mut IDataObject, pformatetc: *const FORMATETC) -> HRESULT,
pub GetCanonicalFormatEtc: unsafe extern "system" fn(
This: *mut IDataObject,
pformatetcIn: *const FORMATETC,
pformatetcOut: *mut FORMATETC,
) -> HRESULT,
pub SetData: unsafe extern "system" fn(
This: *mut IDataObject,
pformatetc: *const FORMATETC,
pformatetcOut: *const FORMATETC,
fRelease: BOOL,
) -> HRESULT,
pub EnumFormatEtc: unsafe extern "system" fn(
This: *mut IDataObject,
dwDirection: u32,
ppenumFormatEtc: *mut *mut IEnumFORMATETC,
) -> HRESULT,
pub DAdvise: unsafe extern "system" fn(
This: *mut IDataObject,
pformatetc: *const FORMATETC,
advf: u32,
pAdvSInk: *const IAdviseSink,
pdwConnection: *mut u32,
) -> HRESULT,
pub DUnadvise: unsafe extern "system" fn(This: *mut IDataObject, dwConnection: u32) -> HRESULT,
pub EnumDAdvise: unsafe extern "system" fn(
This: *mut IDataObject,
ppenumAdvise: *const *const IEnumSTATDATA,
) -> HRESULT,
}
#[repr(C)]
pub struct IDropTargetVtbl {
pub parent: IUnknownVtbl,
pub DragEnter: unsafe extern "system" fn(
This: *mut IDropTarget,
pDataObj: *const IDataObject,
grfKeyState: u32,
pt: *const POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
pub DragOver: unsafe extern "system" fn(
This: *mut IDropTarget,
grfKeyState: u32,
pt: *const POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
pub DragLeave: unsafe extern "system" fn(This: *mut IDropTarget) -> HRESULT,
pub Drop: unsafe extern "system" fn(
This: *mut IDropTarget,
pDataObj: *const IDataObject,
grfKeyState: u32,
pt: *const POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
}
#[repr(C)]
pub struct IDropTarget {
pub lpVtbl: *const IDropTargetVtbl,
}
#[repr(C)]
pub struct ITaskbarListVtbl {
pub parent: IUnknownVtbl,
pub HrInit: unsafe extern "system" fn(This: *mut ITaskbarList) -> HRESULT,
pub AddTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
pub DeleteTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
pub ActivateTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
pub SetActiveAlt: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
}
#[repr(C)]
pub struct ITaskbarList2Vtbl {
pub parent: ITaskbarListVtbl,
pub MarkFullscreenWindow: unsafe extern "system" fn(
This: *mut ITaskbarList2,
hwnd: HWND,
fFullscreen: BOOL,
) -> HRESULT,
}
#[repr(C)]
pub struct ITaskbarList2 {
pub lpVtbl: *const ITaskbarList2Vtbl,
}
pub const CLSID_TaskbarList: GUID = GUID {
data1: 0x56fdf344,
data2: 0xfd6d,
data3: 0x11d0,
data4: [0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90],
};
pub const IID_ITaskbarList2: GUID = GUID {
data1: 0x602d4995,
data2: 0xb13a,
data3: 0x429b,
data4: [0xa6, 0x6e, 0x19, 0x35, 0xe4, 0x4f, 0x43, 0x17],
};

View file

@ -2,24 +2,26 @@
use std::sync::Once;
use windows_sys::Win32::{
Foundation::{HWND, S_OK},
Graphics::Gdi::{
GetDC, GetDeviceCaps, MonitorFromWindow, HMONITOR, LOGPIXELSX, MONITOR_DEFAULTTONEAREST,
},
UI::{
HiDpi::{
DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, MDT_EFFECTIVE_DPI,
PROCESS_PER_MONITOR_DPI_AWARE,
},
WindowsAndMessaging::IsProcessDPIAware,
},
};
use crate::platform_impl::platform::util::{
ENABLE_NON_CLIENT_DPI_SCALING, GET_DPI_FOR_MONITOR, GET_DPI_FOR_WINDOW, SET_PROCESS_DPI_AWARE,
SET_PROCESS_DPI_AWARENESS, SET_PROCESS_DPI_AWARENESS_CONTEXT,
};
use winapi::{
shared::{
minwindef::FALSE,
windef::{DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, HMONITOR, HWND},
winerror::S_OK,
},
um::{
shellscalingapi::{MDT_EFFECTIVE_DPI, PROCESS_PER_MONITOR_DPI_AWARE},
wingdi::{GetDeviceCaps, LOGPIXELSX},
winuser::{self, MONITOR_DEFAULTTONEAREST},
},
};
const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4isize as _;
const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4;
pub fn become_dpi_aware() {
static ENABLE_DPI_AWARENESS: Once = Once::new();
@ -28,7 +30,7 @@ pub fn become_dpi_aware() {
if let Some(SetProcessDpiAwarenessContext) = *SET_PROCESS_DPI_AWARENESS_CONTEXT {
// We are on Windows 10 Anniversary Update (1607) or later.
if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
== FALSE
== false.into()
{
// V2 only works with Windows 10 Creators Update (1703). Try using the older
// V1 if we can't set V2.
@ -76,8 +78,8 @@ pub fn dpi_to_scale_factor(dpi: u32) -> f64 {
}
pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
let hdc = winuser::GetDC(hwnd);
if hdc.is_null() {
let hdc = GetDC(hwnd);
if hdc == 0 {
panic!("[winit] `GetDC` returned null!");
}
if let Some(GetDpiForWindow) = *GET_DPI_FOR_WINDOW {
@ -88,8 +90,8 @@ pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
}
} else if let Some(GetDpiForMonitor) = *GET_DPI_FOR_MONITOR {
// We are on Windows 8.1 or later.
let monitor = winuser::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if monitor.is_null() {
let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if monitor == 0 {
return BASE_DPI;
}
@ -102,7 +104,7 @@ pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
}
} else {
// We are on Vista or later.
if winuser::IsProcessDPIAware() != FALSE {
if IsProcessDPIAware() != false.into() {
// If the process is DPI aware, then scaling must be handled by the application using
// this DPI value.
GetDeviceCaps(hdc, LOGPIXELSX) as u32

View file

@ -1,29 +1,28 @@
use std::{
ffi::OsString,
ffi::{c_void, OsString},
os::windows::ffi::OsStringExt,
path::PathBuf,
ptr,
sync::atomic::{AtomicUsize, Ordering},
};
use winapi::{
ctypes::c_void,
shared::{
guiddef::REFIID,
minwindef::{DWORD, UINT, ULONG},
windef::{HWND, POINTL},
winerror::S_OK,
},
um::{
objidl::IDataObject,
oleidl::{IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_NONE},
shellapi, unknwnbase,
winnt::HRESULT,
use windows_sys::{
core::{IUnknown, GUID, HRESULT},
Win32::{
Foundation::{DV_E_FORMATETC, HWND, POINTL, S_OK},
System::{
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
Ole::{DROPEFFECT_COPY, DROPEFFECT_NONE},
SystemServices::CF_HDROP,
},
UI::Shell::{DragFinish, DragQueryFileW, HDROP},
},
};
use crate::platform_impl::platform::WindowId;
use crate::platform_impl::platform::{
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
WindowId,
};
use crate::{event::Event, window::WindowId as SuperWindowId};
#[repr(C)]
@ -32,7 +31,7 @@ pub struct FileDropHandlerData {
refcount: AtomicUsize,
window: HWND,
send_event: Box<dyn Fn(Event<'static, ()>)>,
cursor_effect: DWORD,
cursor_effect: u32,
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
}
@ -60,8 +59,8 @@ impl FileDropHandler {
// Implement IUnknown
pub unsafe extern "system" fn QueryInterface(
_this: *mut unknwnbase::IUnknown,
_riid: REFIID,
_this: *mut IUnknown,
_riid: *const GUID,
_ppvObject: *mut *mut c_void,
) -> HRESULT {
// This function doesn't appear to be required for an `IDropTarget`.
@ -69,28 +68,28 @@ impl FileDropHandler {
unimplemented!();
}
pub unsafe extern "system" fn AddRef(this: *mut unknwnbase::IUnknown) -> ULONG {
pub unsafe extern "system" fn AddRef(this: *mut IUnknown) -> u32 {
let drop_handler_data = Self::from_interface(this);
let count = drop_handler_data.refcount.fetch_add(1, Ordering::Release) + 1;
count as ULONG
count as u32
}
pub unsafe extern "system" fn Release(this: *mut unknwnbase::IUnknown) -> ULONG {
pub unsafe extern "system" fn Release(this: *mut IUnknown) -> u32 {
let drop_handler = Self::from_interface(this);
let count = drop_handler.refcount.fetch_sub(1, Ordering::Release) - 1;
if count == 0 {
// Destroy the underlying data
Box::from_raw(drop_handler as *mut FileDropHandlerData);
}
count as ULONG
count as u32
}
pub unsafe extern "system" fn DragEnter(
this: *mut IDropTarget,
pDataObj: *const IDataObject,
_grfKeyState: DWORD,
_grfKeyState: u32,
_pt: *const POINTL,
pdwEffect: *mut DWORD,
pdwEffect: *mut u32,
) -> HRESULT {
use crate::event::WindowEvent::HoveredFile;
let drop_handler = Self::from_interface(this);
@ -113,9 +112,9 @@ impl FileDropHandler {
pub unsafe extern "system" fn DragOver(
this: *mut IDropTarget,
_grfKeyState: DWORD,
_grfKeyState: u32,
_pt: *const POINTL,
pdwEffect: *mut DWORD,
pdwEffect: *mut u32,
) -> HRESULT {
let drop_handler = Self::from_interface(this);
*pdwEffect = drop_handler.cursor_effect;
@ -139,9 +138,9 @@ impl FileDropHandler {
pub unsafe extern "system" fn Drop(
this: *mut IDropTarget,
pDataObj: *const IDataObject,
_grfKeyState: DWORD,
_grfKeyState: u32,
_pt: *const POINTL,
_pdwEffect: *mut DWORD,
_pdwEffect: *mut u32,
) -> HRESULT {
use crate::event::WindowEvent::DroppedFile;
let drop_handler = Self::from_interface(this);
@ -152,7 +151,7 @@ impl FileDropHandler {
});
});
if let Some(hdrop) = hdrop {
shellapi::DragFinish(hdrop);
DragFinish(hdrop);
}
S_OK
@ -162,38 +161,23 @@ impl FileDropHandler {
&mut *(this as *mut _)
}
unsafe fn iterate_filenames<F>(
data_obj: *const IDataObject,
callback: F,
) -> Option<shellapi::HDROP>
unsafe fn iterate_filenames<F>(data_obj: *const IDataObject, callback: F) -> Option<HDROP>
where
F: Fn(PathBuf),
{
use winapi::{
shared::{
winerror::{DV_E_FORMATETC, SUCCEEDED},
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
},
um::{
objidl::{FORMATETC, TYMED_HGLOBAL},
shellapi::DragQueryFileW,
winuser::CF_HDROP,
},
};
let drop_format = FORMATETC {
cfFormat: CF_HDROP as CLIPFORMAT,
ptd: ptr::null(),
dwAspect: DVASPECT_CONTENT,
cfFormat: CF_HDROP as u16,
ptd: ptr::null_mut(),
dwAspect: DVASPECT_CONTENT as u32,
lindex: -1,
tymed: TYMED_HGLOBAL,
tymed: TYMED_HGLOBAL as u32,
};
let mut medium = std::mem::zeroed();
let get_data_result = (*data_obj).GetData(&drop_format, &mut medium);
if SUCCEEDED(get_data_result) {
let hglobal = (*medium.u).hGlobal();
let hdrop = (*hglobal) as shellapi::HDROP;
let get_data_fn = (*(*data_obj).cast::<IDataObjectVtbl>()).GetData;
let get_data_result = get_data_fn(data_obj as *mut _, &drop_format, &mut medium);
if get_data_result >= 0 {
let hdrop = medium.Anonymous.hGlobal;
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
@ -207,7 +191,7 @@ impl FileDropHandler {
// Fill path_buf with the null-terminated file name
let mut path_buf = Vec::with_capacity(str_len);
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT);
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as u32);
path_buf.set_len(str_len);
callback(OsString::from_wide(&path_buf[0..character_count]).into());
@ -235,13 +219,13 @@ impl FileDropHandlerData {
impl Drop for FileDropHandler {
fn drop(&mut self) {
unsafe {
FileDropHandler::Release(self.data as *mut unknwnbase::IUnknown);
FileDropHandler::Release(self.data as *mut IUnknown);
}
}
}
static DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
parent: unknwnbase::IUnknownVtbl {
parent: IUnknownVtbl {
QueryInterface: FileDropHandler::QueryInterface,
AddRef: FileDropHandler::AddRef,
Release: FileDropHandler::Release,

View file

@ -1,37 +1,60 @@
use std::{
char,
os::raw::c_int,
ptr,
sync::atomic::{AtomicBool, AtomicPtr, Ordering},
sync::atomic::{AtomicBool, AtomicIsize, Ordering},
};
use windows_sys::Win32::{
Foundation::{LPARAM, WPARAM},
UI::{
Input::KeyboardAndMouse::{
GetKeyState, GetKeyboardLayout, GetKeyboardState, MapVirtualKeyA, ToUnicodeEx,
VIRTUAL_KEY, VK_0, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9, VK_A, VK_ADD,
VK_APPS, VK_B, VK_BACK, VK_BROWSER_BACK, VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD,
VK_BROWSER_HOME, VK_BROWSER_REFRESH, VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_C,
VK_CAPITAL, VK_CONTROL, VK_CONVERT, VK_D, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN,
VK_E, VK_END, VK_ESCAPE, VK_F, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15,
VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_F3,
VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_G, VK_H, VK_HOME, VK_I, VK_INSERT, VK_J,
VK_K, VK_KANA, VK_KANJI, VK_L, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL,
VK_LEFT, VK_LMENU, VK_LSHIFT, VK_LWIN, VK_M, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE,
VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP, VK_MENU, VK_MULTIPLY, VK_N, VK_NEXT, VK_NONCONVERT,
VK_NUMLOCK, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5,
VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_O, VK_OEM_1, VK_OEM_102, VK_OEM_2,
VK_OEM_3, VK_OEM_4, VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_COMMA, VK_OEM_MINUS,
VK_OEM_PERIOD, VK_OEM_PLUS, VK_P, VK_PAUSE, VK_PRIOR, VK_Q, VK_R, VK_RCONTROL,
VK_RETURN, VK_RIGHT, VK_RMENU, VK_RSHIFT, VK_RWIN, VK_S, VK_SCROLL, VK_SHIFT, VK_SLEEP,
VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT, VK_T, VK_TAB, VK_U, VK_UP, VK_V, VK_VOLUME_DOWN,
VK_VOLUME_MUTE, VK_VOLUME_UP, VK_W, VK_X, VK_Y, VK_Z,
},
TextServices::HKL,
WindowsAndMessaging::{MAPVK_VK_TO_CHAR, MAPVK_VSC_TO_VK_EX},
},
};
use crate::event::{ModifiersState, ScanCode, VirtualKeyCode};
use winapi::{
shared::minwindef::{HKL, HKL__, LPARAM, UINT, WPARAM},
um::winuser,
};
use super::util::has_flag;
fn key_pressed(vkey: c_int) -> bool {
unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) }
fn key_pressed(vkey: VIRTUAL_KEY) -> bool {
unsafe { has_flag(GetKeyState(vkey as i32), 1 << 15) }
}
pub fn get_key_mods() -> ModifiersState {
let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU);
let filter_out_altgr = layout_uses_altgr() && key_pressed(VK_RMENU);
let mut mods = ModifiersState::empty();
mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT));
mods.set(ModifiersState::SHIFT, key_pressed(VK_SHIFT));
mods.set(
ModifiersState::CTRL,
key_pressed(winuser::VK_CONTROL) && !filter_out_altgr,
key_pressed(VK_CONTROL) && !filter_out_altgr,
);
mods.set(
ModifiersState::ALT,
key_pressed(winuser::VK_MENU) && !filter_out_altgr,
key_pressed(VK_MENU) && !filter_out_altgr,
);
mods.set(
ModifiersState::LOGO,
key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN),
key_pressed(VK_LWIN) || key_pressed(VK_RWIN),
);
mods
}
@ -85,19 +108,19 @@ impl From<ModifiersStateSide> for ModifiersState {
}
}
pub fn get_pressed_keys() -> impl Iterator<Item = c_int> {
pub fn get_pressed_keys() -> impl Iterator<Item = VIRTUAL_KEY> {
let mut keyboard_state = vec![0u8; 256];
unsafe { winuser::GetKeyboardState(keyboard_state.as_mut_ptr()) };
unsafe { GetKeyboardState(keyboard_state.as_mut_ptr()) };
keyboard_state
.into_iter()
.enumerate()
.filter(|(_, p)| (*p & (1 << 7)) != 0) // whether or not a key is pressed is communicated via the high-order bit
.map(|(i, _)| i as c_int)
.map(|(i, _)| i as u16)
}
unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
let mut unicode_bytes = [0u16; 5];
let len = winuser::ToUnicodeEx(
let len = ToUnicodeEx(
v_key,
0,
keyboard_state.as_ptr(),
@ -126,10 +149,10 @@ unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<c
/// [source]: https://github.com/mozilla/gecko-dev/blob/265e6721798a455604328ed5262f430cfcc37c2f/widget/windows/KeyboardLayout.cpp#L4356-L4416
fn layout_uses_altgr() -> bool {
unsafe {
static ACTIVE_LAYOUT: AtomicPtr<HKL__> = AtomicPtr::new(ptr::null_mut());
static ACTIVE_LAYOUT: AtomicIsize = AtomicIsize::new(0);
static USES_ALTGR: AtomicBool = AtomicBool::new(false);
let hkl = winuser::GetKeyboardLayout(0);
let hkl = GetKeyboardLayout(0);
let old_hkl = ACTIVE_LAYOUT.swap(hkl, Ordering::SeqCst);
if hkl == old_hkl {
@ -139,8 +162,8 @@ fn layout_uses_altgr() -> bool {
let mut keyboard_state_altgr = [0u8; 256];
// AltGr is an alias for Ctrl+Alt for... some reason. Whatever it is, those are the keypresses
// we have to emulate to do an AltGr test.
keyboard_state_altgr[winuser::VK_MENU as usize] = 0x80;
keyboard_state_altgr[winuser::VK_CONTROL as usize] = 0x80;
keyboard_state_altgr[VK_MENU as usize] = 0x80;
keyboard_state_altgr[VK_CONTROL as usize] = 0x80;
let keyboard_state_empty = [0u8; 256];
@ -160,206 +183,204 @@ fn layout_uses_altgr() -> bool {
}
}
pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
pub fn vkey_to_winit_vkey(vkey: VIRTUAL_KEY) -> Option<VirtualKeyCode> {
// VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
match vkey {
//winuser::VK_LBUTTON => Some(VirtualKeyCode::Lbutton),
//winuser::VK_RBUTTON => Some(VirtualKeyCode::Rbutton),
//winuser::VK_CANCEL => Some(VirtualKeyCode::Cancel),
//winuser::VK_MBUTTON => Some(VirtualKeyCode::Mbutton),
//winuser::VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1),
//winuser::VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2),
winuser::VK_BACK => Some(VirtualKeyCode::Back),
winuser::VK_TAB => Some(VirtualKeyCode::Tab),
//winuser::VK_CLEAR => Some(VirtualKeyCode::Clear),
winuser::VK_RETURN => Some(VirtualKeyCode::Return),
winuser::VK_LSHIFT => Some(VirtualKeyCode::LShift),
winuser::VK_RSHIFT => Some(VirtualKeyCode::RShift),
winuser::VK_LCONTROL => Some(VirtualKeyCode::LControl),
winuser::VK_RCONTROL => Some(VirtualKeyCode::RControl),
winuser::VK_LMENU => Some(VirtualKeyCode::LAlt),
winuser::VK_RMENU => Some(VirtualKeyCode::RAlt),
winuser::VK_PAUSE => Some(VirtualKeyCode::Pause),
winuser::VK_CAPITAL => Some(VirtualKeyCode::Capital),
winuser::VK_KANA => Some(VirtualKeyCode::Kana),
//winuser::VK_HANGUEL => Some(VirtualKeyCode::Hanguel),
//winuser::VK_HANGUL => Some(VirtualKeyCode::Hangul),
//winuser::VK_JUNJA => Some(VirtualKeyCode::Junja),
//winuser::VK_FINAL => Some(VirtualKeyCode::Final),
//winuser::VK_HANJA => Some(VirtualKeyCode::Hanja),
winuser::VK_KANJI => Some(VirtualKeyCode::Kanji),
winuser::VK_ESCAPE => Some(VirtualKeyCode::Escape),
winuser::VK_CONVERT => Some(VirtualKeyCode::Convert),
winuser::VK_NONCONVERT => Some(VirtualKeyCode::NoConvert),
//winuser::VK_ACCEPT => Some(VirtualKeyCode::Accept),
//winuser::VK_MODECHANGE => Some(VirtualKeyCode::Modechange),
winuser::VK_SPACE => Some(VirtualKeyCode::Space),
winuser::VK_PRIOR => Some(VirtualKeyCode::PageUp),
winuser::VK_NEXT => Some(VirtualKeyCode::PageDown),
winuser::VK_END => Some(VirtualKeyCode::End),
winuser::VK_HOME => Some(VirtualKeyCode::Home),
winuser::VK_LEFT => Some(VirtualKeyCode::Left),
winuser::VK_UP => Some(VirtualKeyCode::Up),
winuser::VK_RIGHT => Some(VirtualKeyCode::Right),
winuser::VK_DOWN => Some(VirtualKeyCode::Down),
//winuser::VK_SELECT => Some(VirtualKeyCode::Select),
//winuser::VK_PRINT => Some(VirtualKeyCode::Print),
//winuser::VK_EXECUTE => Some(VirtualKeyCode::Execute),
winuser::VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot),
winuser::VK_INSERT => Some(VirtualKeyCode::Insert),
winuser::VK_DELETE => Some(VirtualKeyCode::Delete),
//winuser::VK_HELP => Some(VirtualKeyCode::Help),
0x30 => Some(VirtualKeyCode::Key0),
0x31 => Some(VirtualKeyCode::Key1),
0x32 => Some(VirtualKeyCode::Key2),
0x33 => Some(VirtualKeyCode::Key3),
0x34 => Some(VirtualKeyCode::Key4),
0x35 => Some(VirtualKeyCode::Key5),
0x36 => Some(VirtualKeyCode::Key6),
0x37 => Some(VirtualKeyCode::Key7),
0x38 => Some(VirtualKeyCode::Key8),
0x39 => Some(VirtualKeyCode::Key9),
0x41 => Some(VirtualKeyCode::A),
0x42 => Some(VirtualKeyCode::B),
0x43 => Some(VirtualKeyCode::C),
0x44 => Some(VirtualKeyCode::D),
0x45 => Some(VirtualKeyCode::E),
0x46 => Some(VirtualKeyCode::F),
0x47 => Some(VirtualKeyCode::G),
0x48 => Some(VirtualKeyCode::H),
0x49 => Some(VirtualKeyCode::I),
0x4A => Some(VirtualKeyCode::J),
0x4B => Some(VirtualKeyCode::K),
0x4C => Some(VirtualKeyCode::L),
0x4D => Some(VirtualKeyCode::M),
0x4E => Some(VirtualKeyCode::N),
0x4F => Some(VirtualKeyCode::O),
0x50 => Some(VirtualKeyCode::P),
0x51 => Some(VirtualKeyCode::Q),
0x52 => Some(VirtualKeyCode::R),
0x53 => Some(VirtualKeyCode::S),
0x54 => Some(VirtualKeyCode::T),
0x55 => Some(VirtualKeyCode::U),
0x56 => Some(VirtualKeyCode::V),
0x57 => Some(VirtualKeyCode::W),
0x58 => Some(VirtualKeyCode::X),
0x59 => Some(VirtualKeyCode::Y),
0x5A => Some(VirtualKeyCode::Z),
winuser::VK_LWIN => Some(VirtualKeyCode::LWin),
winuser::VK_RWIN => Some(VirtualKeyCode::RWin),
winuser::VK_APPS => Some(VirtualKeyCode::Apps),
winuser::VK_SLEEP => Some(VirtualKeyCode::Sleep),
winuser::VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0),
winuser::VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1),
winuser::VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2),
winuser::VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3),
winuser::VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4),
winuser::VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5),
winuser::VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6),
winuser::VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7),
winuser::VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8),
winuser::VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9),
winuser::VK_MULTIPLY => Some(VirtualKeyCode::NumpadMultiply),
winuser::VK_ADD => Some(VirtualKeyCode::NumpadAdd),
//winuser::VK_SEPARATOR => Some(VirtualKeyCode::Separator),
winuser::VK_SUBTRACT => Some(VirtualKeyCode::NumpadSubtract),
winuser::VK_DECIMAL => Some(VirtualKeyCode::NumpadDecimal),
winuser::VK_DIVIDE => Some(VirtualKeyCode::NumpadDivide),
winuser::VK_F1 => Some(VirtualKeyCode::F1),
winuser::VK_F2 => Some(VirtualKeyCode::F2),
winuser::VK_F3 => Some(VirtualKeyCode::F3),
winuser::VK_F4 => Some(VirtualKeyCode::F4),
winuser::VK_F5 => Some(VirtualKeyCode::F5),
winuser::VK_F6 => Some(VirtualKeyCode::F6),
winuser::VK_F7 => Some(VirtualKeyCode::F7),
winuser::VK_F8 => Some(VirtualKeyCode::F8),
winuser::VK_F9 => Some(VirtualKeyCode::F9),
winuser::VK_F10 => Some(VirtualKeyCode::F10),
winuser::VK_F11 => Some(VirtualKeyCode::F11),
winuser::VK_F12 => Some(VirtualKeyCode::F12),
winuser::VK_F13 => Some(VirtualKeyCode::F13),
winuser::VK_F14 => Some(VirtualKeyCode::F14),
winuser::VK_F15 => Some(VirtualKeyCode::F15),
winuser::VK_F16 => Some(VirtualKeyCode::F16),
winuser::VK_F17 => Some(VirtualKeyCode::F17),
winuser::VK_F18 => Some(VirtualKeyCode::F18),
winuser::VK_F19 => Some(VirtualKeyCode::F19),
winuser::VK_F20 => Some(VirtualKeyCode::F20),
winuser::VK_F21 => Some(VirtualKeyCode::F21),
winuser::VK_F22 => Some(VirtualKeyCode::F22),
winuser::VK_F23 => Some(VirtualKeyCode::F23),
winuser::VK_F24 => Some(VirtualKeyCode::F24),
winuser::VK_NUMLOCK => Some(VirtualKeyCode::Numlock),
winuser::VK_SCROLL => Some(VirtualKeyCode::Scroll),
winuser::VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward),
winuser::VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward),
winuser::VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh),
winuser::VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop),
winuser::VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch),
winuser::VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites),
winuser::VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome),
winuser::VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute),
winuser::VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown),
winuser::VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp),
winuser::VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack),
winuser::VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack),
winuser::VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop),
winuser::VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause),
winuser::VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail),
winuser::VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect),
/*winuser::VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1),
winuser::VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/
winuser::VK_OEM_PLUS => Some(VirtualKeyCode::Equals),
winuser::VK_OEM_COMMA => Some(VirtualKeyCode::Comma),
winuser::VK_OEM_MINUS => Some(VirtualKeyCode::Minus),
winuser::VK_OEM_PERIOD => Some(VirtualKeyCode::Period),
winuser::VK_OEM_1 => map_text_keys(vkey),
winuser::VK_OEM_2 => map_text_keys(vkey),
winuser::VK_OEM_3 => map_text_keys(vkey),
winuser::VK_OEM_4 => map_text_keys(vkey),
winuser::VK_OEM_5 => map_text_keys(vkey),
winuser::VK_OEM_6 => map_text_keys(vkey),
winuser::VK_OEM_7 => map_text_keys(vkey),
/* winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */
winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102),
/*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
winuser::VK_PACKET => Some(VirtualKeyCode::Packet),
winuser::VK_ATTN => Some(VirtualKeyCode::Attn),
winuser::VK_CRSEL => Some(VirtualKeyCode::Crsel),
winuser::VK_EXSEL => Some(VirtualKeyCode::Exsel),
winuser::VK_EREOF => Some(VirtualKeyCode::Ereof),
winuser::VK_PLAY => Some(VirtualKeyCode::Play),
winuser::VK_ZOOM => Some(VirtualKeyCode::Zoom),
winuser::VK_NONAME => Some(VirtualKeyCode::Noname),
winuser::VK_PA1 => Some(VirtualKeyCode::Pa1),
winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
//VK_LBUTTON => Some(VirtualKeyCode::Lbutton),
//VK_RBUTTON => Some(VirtualKeyCode::Rbutton),
//VK_CANCEL => Some(VirtualKeyCode::Cancel),
//VK_MBUTTON => Some(VirtualKeyCode::Mbutton),
//VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1),
//VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2),
VK_BACK => Some(VirtualKeyCode::Back),
VK_TAB => Some(VirtualKeyCode::Tab),
//VK_CLEAR => Some(VirtualKeyCode::Clear),
VK_RETURN => Some(VirtualKeyCode::Return),
VK_LSHIFT => Some(VirtualKeyCode::LShift),
VK_RSHIFT => Some(VirtualKeyCode::RShift),
VK_LCONTROL => Some(VirtualKeyCode::LControl),
VK_RCONTROL => Some(VirtualKeyCode::RControl),
VK_LMENU => Some(VirtualKeyCode::LAlt),
VK_RMENU => Some(VirtualKeyCode::RAlt),
VK_PAUSE => Some(VirtualKeyCode::Pause),
VK_CAPITAL => Some(VirtualKeyCode::Capital),
VK_KANA => Some(VirtualKeyCode::Kana),
//VK_HANGUEL => Some(VirtualKeyCode::Hanguel),
//VK_HANGUL => Some(VirtualKeyCode::Hangul),
//VK_JUNJA => Some(VirtualKeyCode::Junja),
//VK_FINAL => Some(VirtualKeyCode::Final),
//VK_HANJA => Some(VirtualKeyCode::Hanja),
VK_KANJI => Some(VirtualKeyCode::Kanji),
VK_ESCAPE => Some(VirtualKeyCode::Escape),
VK_CONVERT => Some(VirtualKeyCode::Convert),
VK_NONCONVERT => Some(VirtualKeyCode::NoConvert),
//VK_ACCEPT => Some(VirtualKeyCode::Accept),
//VK_MODECHANGE => Some(VirtualKeyCode::Modechange),
VK_SPACE => Some(VirtualKeyCode::Space),
VK_PRIOR => Some(VirtualKeyCode::PageUp),
VK_NEXT => Some(VirtualKeyCode::PageDown),
VK_END => Some(VirtualKeyCode::End),
VK_HOME => Some(VirtualKeyCode::Home),
VK_LEFT => Some(VirtualKeyCode::Left),
VK_UP => Some(VirtualKeyCode::Up),
VK_RIGHT => Some(VirtualKeyCode::Right),
VK_DOWN => Some(VirtualKeyCode::Down),
//VK_SELECT => Some(VirtualKeyCode::Select),
//VK_PRINT => Some(VirtualKeyCode::Print),
//VK_EXECUTE => Some(VirtualKeyCode::Execute),
VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot),
VK_INSERT => Some(VirtualKeyCode::Insert),
VK_DELETE => Some(VirtualKeyCode::Delete),
//VK_HELP => Some(VirtualKeyCode::Help),
VK_0 => Some(VirtualKeyCode::Key0),
VK_1 => Some(VirtualKeyCode::Key1),
VK_2 => Some(VirtualKeyCode::Key2),
VK_3 => Some(VirtualKeyCode::Key3),
VK_4 => Some(VirtualKeyCode::Key4),
VK_5 => Some(VirtualKeyCode::Key5),
VK_6 => Some(VirtualKeyCode::Key6),
VK_7 => Some(VirtualKeyCode::Key7),
VK_8 => Some(VirtualKeyCode::Key8),
VK_9 => Some(VirtualKeyCode::Key9),
VK_A => Some(VirtualKeyCode::A),
VK_B => Some(VirtualKeyCode::B),
VK_C => Some(VirtualKeyCode::C),
VK_D => Some(VirtualKeyCode::D),
VK_E => Some(VirtualKeyCode::E),
VK_F => Some(VirtualKeyCode::F),
VK_G => Some(VirtualKeyCode::G),
VK_H => Some(VirtualKeyCode::H),
VK_I => Some(VirtualKeyCode::I),
VK_J => Some(VirtualKeyCode::J),
VK_K => Some(VirtualKeyCode::K),
VK_L => Some(VirtualKeyCode::L),
VK_M => Some(VirtualKeyCode::M),
VK_N => Some(VirtualKeyCode::N),
VK_O => Some(VirtualKeyCode::O),
VK_P => Some(VirtualKeyCode::P),
VK_Q => Some(VirtualKeyCode::Q),
VK_R => Some(VirtualKeyCode::R),
VK_S => Some(VirtualKeyCode::S),
VK_T => Some(VirtualKeyCode::T),
VK_U => Some(VirtualKeyCode::U),
VK_V => Some(VirtualKeyCode::V),
VK_W => Some(VirtualKeyCode::W),
VK_X => Some(VirtualKeyCode::X),
VK_Y => Some(VirtualKeyCode::Y),
VK_Z => Some(VirtualKeyCode::Z),
VK_LWIN => Some(VirtualKeyCode::LWin),
VK_RWIN => Some(VirtualKeyCode::RWin),
VK_APPS => Some(VirtualKeyCode::Apps),
VK_SLEEP => Some(VirtualKeyCode::Sleep),
VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0),
VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1),
VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2),
VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3),
VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4),
VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5),
VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6),
VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7),
VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8),
VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9),
VK_MULTIPLY => Some(VirtualKeyCode::NumpadMultiply),
VK_ADD => Some(VirtualKeyCode::NumpadAdd),
//VK_SEPARATOR => Some(VirtualKeyCode::Separator),
VK_SUBTRACT => Some(VirtualKeyCode::NumpadSubtract),
VK_DECIMAL => Some(VirtualKeyCode::NumpadDecimal),
VK_DIVIDE => Some(VirtualKeyCode::NumpadDivide),
VK_F1 => Some(VirtualKeyCode::F1),
VK_F2 => Some(VirtualKeyCode::F2),
VK_F3 => Some(VirtualKeyCode::F3),
VK_F4 => Some(VirtualKeyCode::F4),
VK_F5 => Some(VirtualKeyCode::F5),
VK_F6 => Some(VirtualKeyCode::F6),
VK_F7 => Some(VirtualKeyCode::F7),
VK_F8 => Some(VirtualKeyCode::F8),
VK_F9 => Some(VirtualKeyCode::F9),
VK_F10 => Some(VirtualKeyCode::F10),
VK_F11 => Some(VirtualKeyCode::F11),
VK_F12 => Some(VirtualKeyCode::F12),
VK_F13 => Some(VirtualKeyCode::F13),
VK_F14 => Some(VirtualKeyCode::F14),
VK_F15 => Some(VirtualKeyCode::F15),
VK_F16 => Some(VirtualKeyCode::F16),
VK_F17 => Some(VirtualKeyCode::F17),
VK_F18 => Some(VirtualKeyCode::F18),
VK_F19 => Some(VirtualKeyCode::F19),
VK_F20 => Some(VirtualKeyCode::F20),
VK_F21 => Some(VirtualKeyCode::F21),
VK_F22 => Some(VirtualKeyCode::F22),
VK_F23 => Some(VirtualKeyCode::F23),
VK_F24 => Some(VirtualKeyCode::F24),
VK_NUMLOCK => Some(VirtualKeyCode::Numlock),
VK_SCROLL => Some(VirtualKeyCode::Scroll),
VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward),
VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward),
VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh),
VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop),
VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch),
VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites),
VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome),
VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute),
VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown),
VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp),
VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack),
VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack),
VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop),
VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause),
VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail),
VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect),
/*VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1),
VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/
VK_OEM_PLUS => Some(VirtualKeyCode::Equals),
VK_OEM_COMMA => Some(VirtualKeyCode::Comma),
VK_OEM_MINUS => Some(VirtualKeyCode::Minus),
VK_OEM_PERIOD => Some(VirtualKeyCode::Period),
VK_OEM_1 => map_text_keys(vkey),
VK_OEM_2 => map_text_keys(vkey),
VK_OEM_3 => map_text_keys(vkey),
VK_OEM_4 => map_text_keys(vkey),
VK_OEM_5 => map_text_keys(vkey),
VK_OEM_6 => map_text_keys(vkey),
VK_OEM_7 => map_text_keys(vkey),
/* VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */
VK_OEM_102 => Some(VirtualKeyCode::OEM102),
/*VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
VK_PACKET => Some(VirtualKeyCode::Packet),
VK_ATTN => Some(VirtualKeyCode::Attn),
VK_CRSEL => Some(VirtualKeyCode::Crsel),
VK_EXSEL => Some(VirtualKeyCode::Exsel),
VK_EREOF => Some(VirtualKeyCode::Ereof),
VK_PLAY => Some(VirtualKeyCode::Play),
VK_ZOOM => Some(VirtualKeyCode::Zoom),
VK_NONAME => Some(VirtualKeyCode::Noname),
VK_PA1 => Some(VirtualKeyCode::Pa1),
VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
_ => None,
}
}
pub fn handle_extended_keys(
vkey: c_int,
mut scancode: UINT,
vkey: VIRTUAL_KEY,
mut scancode: u32,
extended: bool,
) -> Option<(c_int, UINT)> {
) -> Option<(VIRTUAL_KEY, u32)> {
// Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/
scancode |= if extended { 0xE000 } else { 0x0000 };
let vkey = match vkey {
winuser::VK_SHIFT => unsafe {
winuser::MapVirtualKeyA(scancode, winuser::MAPVK_VSC_TO_VK_EX) as _
},
winuser::VK_CONTROL => {
VK_SHIFT => (unsafe { MapVirtualKeyA(scancode, MAPVK_VSC_TO_VK_EX) } as u16),
VK_CONTROL => {
if extended {
winuser::VK_RCONTROL
VK_RCONTROL
} else {
winuser::VK_LCONTROL
VK_LCONTROL
}
}
winuser::VK_MENU => {
VK_MENU => {
if extended {
winuser::VK_RMENU
VK_RMENU
} else {
winuser::VK_LMENU
VK_LMENU
}
}
_ => {
@ -367,20 +388,20 @@ pub fn handle_extended_keys(
// When VK_PAUSE is pressed it emits a LeftControl + NumLock scancode event sequence, but reports VK_PAUSE
// as the virtual key on both events, or VK_PAUSE on the first event or 0xFF when using raw input.
// Don't emit anything for the LeftControl event in the pair...
0xE01D if vkey == winuser::VK_PAUSE => return None,
0xE01D if vkey == VK_PAUSE => return None,
// ...and emit the Pause event for the second event in the pair.
0x45 if vkey == winuser::VK_PAUSE || vkey == 0xFF => {
0x45 if vkey == VK_PAUSE || vkey == 0xFF => {
scancode = 0xE059;
winuser::VK_PAUSE
VK_PAUSE
}
// VK_PAUSE has an incorrect vkey value when used with modifiers. VK_PAUSE also reports a different
// scancode when used with modifiers than when used without
0xE046 => {
scancode = 0xE059;
winuser::VK_PAUSE
VK_PAUSE
}
// VK_SCROLL has an incorrect vkey value when used with modifiers.
0x46 => winuser::VK_SCROLL,
0x46 => VK_SCROLL,
_ => vkey,
}
}
@ -392,18 +413,16 @@ pub fn process_key_params(
wparam: WPARAM,
lparam: LPARAM,
) -> Option<(ScanCode, Option<VirtualKeyCode>)> {
let scancode = ((lparam >> 16) & 0xff) as UINT;
let scancode = ((lparam >> 16) & 0xff) as u32;
let extended = (lparam & 0x01000000) != 0;
handle_extended_keys(wparam as _, scancode, extended)
handle_extended_keys(wparam as u16, scancode, extended)
.map(|(vkey, scancode)| (scancode, vkey_to_winit_vkey(vkey)))
}
// This is needed as windows doesn't properly distinguish
// some virtual key codes for different keyboard layouts
fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
let char_key =
unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) }
& 0x7FFF;
fn map_text_keys(win_virtual_key: VIRTUAL_KEY) -> Option<VirtualKeyCode> {
let char_key = unsafe { MapVirtualKeyA(win_virtual_key as u32, MAPVK_VK_TO_CHAR) } & 0x7FFF;
match char::from_u32(char_key) {
Some(';') => Some(VirtualKeyCode::Semicolon),
Some('/') => Some(VirtualKeyCode::Slash),

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,9 @@ use std::{
time::Instant,
};
use winapi::{
shared::{minwindef::DWORD, windef::HWND},
um::winuser,
use windows_sys::Win32::{
Foundation::HWND,
Graphics::Gdi::{RedrawWindow, RDW_INTERNALPAINT},
};
use crate::{
@ -24,7 +24,7 @@ pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
pub(crate) struct EventLoopRunner<T: 'static> {
// The event loop's win32 handles
pub(super) thread_msg_target: HWND,
wait_thread_id: DWORD,
wait_thread_id: u32,
control_flow: Cell<ControlFlow>,
runner_state: Cell<RunnerState>,
@ -63,7 +63,7 @@ enum BufferedEvent<T: 'static> {
}
impl<T> EventLoopRunner<T> {
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: DWORD) -> EventLoopRunner<T> {
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: u32) -> EventLoopRunner<T> {
EventLoopRunner {
thread_msg_target,
wait_thread_id,
@ -113,7 +113,7 @@ impl<T> EventLoopRunner<T> {
self.thread_msg_target
}
pub fn wait_thread_id(&self) -> DWORD {
pub fn wait_thread_id(&self) -> u32 {
self.wait_thread_id
}
@ -208,18 +208,16 @@ impl<T> EventLoopRunner<T> {
self.move_state_to(RunnerState::HandlingRedrawEvents);
}
self.call_event_handler(event);
} else if self.should_buffer() {
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.event_buffer
.borrow_mut()
.push_back(BufferedEvent::from_event(event))
} else {
if self.should_buffer() {
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.event_buffer
.borrow_mut()
.push_back(BufferedEvent::from_event(event))
} else {
self.move_state_to(RunnerState::HandlingMainEvents);
self.call_event_handler(event);
self.dispatch_buffered_events();
}
self.move_state_to(RunnerState::HandlingMainEvents);
self.call_event_handler(event);
self.dispatch_buffered_events();
}
}
@ -394,12 +392,7 @@ impl<T> EventLoopRunner<T> {
};
self.call_event_handler(Event::NewEvents(start_cause));
self.dispatch_buffered_events();
winuser::RedrawWindow(
self.thread_msg_target,
ptr::null(),
ptr::null_mut(),
winuser::RDW_INTERNALPAINT,
);
RedrawWindow(self.thread_msg_target, ptr::null(), 0, RDW_INTERNALPAINT);
}
unsafe fn call_redraw_events_cleared(&self) {

View file

@ -1,18 +1,22 @@
use std::{fmt, io, iter::once, mem, os::windows::ffi::OsStrExt, path::Path, ptr, sync::Arc};
use std::{fmt, io, mem, path::Path, ptr, sync::Arc};
use winapi::{
ctypes::{c_int, wchar_t},
shared::{
minwindef::{BYTE, LPARAM, WORD, WPARAM},
windef::{HICON, HWND},
use windows_sys::{
core::PCWSTR,
Win32::{
Foundation::HWND,
System::LibraryLoader::GetModuleHandleW,
UI::WindowsAndMessaging::{
CreateIcon, DestroyIcon, LoadImageW, SendMessageW, HICON, ICON_BIG, ICON_SMALL,
IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE, WM_SETICON,
},
},
um::libloaderapi,
um::winuser,
};
use crate::dpi::PhysicalSize;
use crate::icon::*;
use super::util;
impl Pixel {
fn to_bgra(&mut self) {
mem::swap(&mut self.r, &mut self.b);
@ -21,28 +25,28 @@ impl Pixel {
impl RgbaIcon {
fn into_windows_icon(self) -> Result<WinIcon, BadIcon> {
let mut rgba = self.rgba;
let rgba = self.rgba;
let pixel_count = rgba.len() / PIXEL_SIZE;
let mut and_mask = Vec::with_capacity(pixel_count);
let pixels =
unsafe { std::slice::from_raw_parts_mut(rgba.as_mut_ptr() as *mut Pixel, pixel_count) };
unsafe { std::slice::from_raw_parts_mut(rgba.as_ptr() as *mut Pixel, pixel_count) };
for pixel in pixels {
and_mask.push(pixel.a.wrapping_sub(std::u8::MAX)); // invert alpha channel
pixel.to_bgra();
}
assert_eq!(and_mask.len(), pixel_count);
let handle = unsafe {
winuser::CreateIcon(
ptr::null_mut(),
self.width as c_int,
self.height as c_int,
CreateIcon(
0,
self.width as i32,
self.height as i32,
1,
(PIXEL_SIZE * 8) as BYTE,
and_mask.as_ptr() as *const BYTE,
rgba.as_ptr() as *const BYTE,
) as HICON
(PIXEL_SIZE * 8) as u8,
and_mask.as_ptr(),
rgba.as_ptr(),
)
};
if !handle.is_null() {
if handle != 0 {
Ok(WinIcon::from_handle(handle))
} else {
Err(BadIcon::OsError(io::Error::last_os_error()))
@ -52,8 +56,8 @@ impl RgbaIcon {
#[derive(Debug)]
pub enum IconType {
Small = winuser::ICON_SMALL as isize,
Big = winuser::ICON_BIG as isize,
Small = ICON_SMALL as isize,
Big = ICON_BIG as isize,
}
#[derive(Debug)]
@ -77,51 +81,46 @@ impl WinIcon {
path: P,
size: Option<PhysicalSize<u32>>,
) -> Result<Self, BadIcon> {
let wide_path: Vec<u16> = path
.as_ref()
.as_os_str()
.encode_wide()
.chain(once(0))
.collect();
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
let wide_path = util::encode_wide(path.as_ref());
let handle = unsafe {
winuser::LoadImageW(
ptr::null_mut(),
wide_path.as_ptr() as *const wchar_t,
winuser::IMAGE_ICON,
width as c_int,
height as c_int,
winuser::LR_DEFAULTSIZE | winuser::LR_LOADFROMFILE,
) as HICON
LoadImageW(
0,
wide_path.as_ptr(),
IMAGE_ICON,
width as i32,
height as i32,
LR_DEFAULTSIZE | LR_LOADFROMFILE,
)
};
if !handle.is_null() {
Ok(WinIcon::from_handle(handle))
if handle != 0 {
Ok(WinIcon::from_handle(handle as HICON))
} else {
Err(BadIcon::OsError(io::Error::last_os_error()))
}
}
pub fn from_resource(
resource_id: WORD,
resource_id: u16,
size: Option<PhysicalSize<u32>>,
) -> Result<Self, BadIcon> {
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
let handle = unsafe {
winuser::LoadImageW(
libloaderapi::GetModuleHandleW(ptr::null_mut()),
winuser::MAKEINTRESOURCEW(resource_id),
winuser::IMAGE_ICON,
width as c_int,
height as c_int,
winuser::LR_DEFAULTSIZE,
) as HICON
LoadImageW(
GetModuleHandleW(ptr::null()),
resource_id as PCWSTR,
IMAGE_ICON,
width as i32,
height as i32,
LR_DEFAULTSIZE,
)
};
if !handle.is_null() {
Ok(WinIcon::from_handle(handle))
if handle != 0 {
Ok(WinIcon::from_handle(handle as HICON))
} else {
Err(BadIcon::OsError(io::Error::last_os_error()))
}
@ -134,12 +133,7 @@ impl WinIcon {
pub fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
unsafe {
winuser::SendMessageW(
hwnd,
winuser::WM_SETICON,
icon_type as WPARAM,
self.as_raw_handle() as LPARAM,
);
SendMessageW(hwnd, WM_SETICON, icon_type as usize, self.as_raw_handle());
}
}
@ -152,7 +146,7 @@ impl WinIcon {
impl Drop for RaiiIcon {
fn drop(&mut self) {
unsafe { winuser::DestroyIcon(self.handle) };
unsafe { DestroyIcon(self.handle) };
}
}
@ -164,6 +158,6 @@ impl fmt::Debug for WinIcon {
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
unsafe {
winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM);
SendMessageW(hwnd, WM_SETICON, icon_type as usize, 0);
}
}

View file

@ -1,6 +1,9 @@
#![cfg(target_os = "windows")]
use winapi::{self, shared::windef::HMENU, shared::windef::HWND};
use windows_sys::Win32::{
Foundation::{HANDLE, HWND},
UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX},
};
pub(crate) use self::{
event_loop::{
@ -52,7 +55,7 @@ unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}
// Cursor name in UTF-16. Used to set cursor in `WM_SETCURSOR`.
#[derive(Debug, Clone, Copy)]
pub struct Cursor(pub *const winapi::ctypes::wchar_t);
pub struct Cursor(pub *const u16);
unsafe impl Send for Cursor {}
unsafe impl Sync for Cursor {}
@ -68,7 +71,7 @@ impl DeviceId {
impl DeviceId {
pub fn persistent_identifier(&self) -> Option<String> {
if self.0 != 0 {
raw_input::get_raw_input_device_name(self.0 as _)
raw_input::get_raw_input_device_name(self.0 as HANDLE)
} else {
None
}
@ -91,15 +94,59 @@ unsafe impl Sync for WindowId {}
impl WindowId {
pub const unsafe fn dummy() -> Self {
use std::ptr::null_mut;
WindowId(null_mut())
WindowId(0)
}
}
#[inline(always)]
const fn get_xbutton_wparam(x: u32) -> u16 {
loword(x)
}
#[inline(always)]
const fn get_x_lparam(x: u32) -> u16 {
loword(x)
}
#[inline(always)]
const fn get_y_lparam(x: u32) -> u16 {
hiword(x)
}
#[inline(always)]
const fn loword(x: u32) -> u16 {
(x & 0xFFFF) as u16
}
#[inline(always)]
const fn hiword(x: u32) -> u16 {
((x >> 16) & 0xFFFF) as u16
}
#[inline(always)]
unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
#[cfg(target_pointer_width = "64")]
return windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex);
#[cfg(target_pointer_width = "32")]
return windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize;
}
#[inline(always)]
unsafe fn set_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize) -> isize {
#[cfg(target_pointer_width = "64")]
return windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong);
#[cfg(target_pointer_width = "32")]
return windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(
hwnd,
nindex,
dwnewlong as i32,
) as isize;
}
#[macro_use]
mod util;
mod dark_mode;
mod definitions;
mod dpi;
mod drop_handler;
mod event;

View file

@ -1,22 +1,28 @@
use winapi::{
shared::{
minwindef::{BOOL, DWORD, LPARAM, TRUE, WORD},
windef::{HDC, HMONITOR, HWND, LPRECT, POINT},
},
um::{wingdi, winuser},
};
use std::{
collections::{BTreeSet, VecDeque},
io, mem, ptr,
ffi::OsString,
hash::Hash,
io, mem,
os::windows::prelude::OsStringExt,
ptr,
};
use windows_sys::Win32::{
Foundation::{BOOL, HWND, LPARAM, POINT, RECT},
Graphics::Gdi::{
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT,
DM_PELSWIDTH, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW, MONITOR_DEFAULTTONEAREST,
MONITOR_DEFAULTTOPRIMARY,
},
};
use super::util;
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
platform_impl::platform::{
dpi::{dpi_to_scale_factor, get_monitor_dpi},
util::has_flag,
window::Window,
},
};
@ -27,7 +33,7 @@ pub struct VideoMode {
pub(crate) bit_depth: u16,
pub(crate) refresh_rate: u16,
pub(crate) monitor: MonitorHandle,
pub(crate) native_video_mode: wingdi::DEVMODEW,
pub(crate) native_video_mode: DEVMODEW,
}
impl PartialEq for VideoMode {
@ -94,20 +100,20 @@ unsafe impl Send for MonitorHandle {}
unsafe extern "system" fn monitor_enum_proc(
hmonitor: HMONITOR,
_hdc: HDC,
_place: LPRECT,
_place: *mut RECT,
data: LPARAM,
) -> BOOL {
let monitors = data as *mut VecDeque<MonitorHandle>;
(*monitors).push_back(MonitorHandle::new(hmonitor));
TRUE // continue enumeration
true.into() // continue enumeration
}
pub fn available_monitors() -> VecDeque<MonitorHandle> {
let mut monitors: VecDeque<MonitorHandle> = VecDeque::new();
unsafe {
winuser::EnumDisplayMonitors(
ptr::null_mut(),
ptr::null_mut(),
EnumDisplayMonitors(
0,
ptr::null(),
Some(monitor_enum_proc),
&mut monitors as *mut _ as LPARAM,
);
@ -117,12 +123,12 @@ pub fn available_monitors() -> VecDeque<MonitorHandle> {
pub fn primary_monitor() -> MonitorHandle {
const ORIGIN: POINT = POINT { x: 0, y: 0 };
let hmonitor = unsafe { winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY) };
let hmonitor = unsafe { MonitorFromPoint(ORIGIN, MONITOR_DEFAULTTOPRIMARY) };
MonitorHandle::new(hmonitor)
}
pub fn current_monitor(hwnd: HWND) -> MonitorHandle {
let hmonitor = unsafe { winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) };
let hmonitor = unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) };
MonitorHandle::new(hmonitor)
}
@ -137,16 +143,16 @@ impl Window {
}
}
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() };
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<MONITORINFOEXW, io::Error> {
let mut monitor_info: MONITORINFOEXW = unsafe { mem::zeroed() };
monitor_info.monitorInfo.cbSize = mem::size_of::<MONITORINFOEXW>() as u32;
let status = unsafe {
winuser::GetMonitorInfoW(
GetMonitorInfoW(
hmonitor,
&mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO,
&mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO,
)
};
if status == 0 {
if status == false.into() {
Err(io::Error::last_os_error())
} else {
Ok(monitor_info)
@ -161,7 +167,11 @@ impl MonitorHandle {
#[inline]
pub fn name(&self) -> Option<String> {
let monitor_info = get_monitor_info(self.0).unwrap();
Some(util::wchar_ptr_to_string(monitor_info.szDevice.as_ptr()))
Some(
OsString::from_wide(&monitor_info.szDevice)
.to_string_lossy()
.to_string(),
)
}
#[inline]
@ -176,19 +186,19 @@ impl MonitorHandle {
#[inline]
pub fn size(&self) -> PhysicalSize<u32> {
let monitor_info = get_monitor_info(self.0).unwrap();
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
PhysicalSize {
width: (monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) as u32,
height: (monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top) as u32,
width: (rc_monitor.right - rc_monitor.left) as u32,
height: (rc_monitor.bottom - rc_monitor.top) as u32,
}
}
#[inline]
pub fn position(&self) -> PhysicalPosition<i32> {
let monitor_info = get_monitor_info(self.0).unwrap();
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
PhysicalPosition {
x: monitor_info.rcMonitor.left,
y: monitor_info.rcMonitor.top,
x: rc_monitor.left,
y: rc_monitor.top,
}
}
@ -209,18 +219,16 @@ impl MonitorHandle {
unsafe {
let monitor_info = get_monitor_info(self.0).unwrap();
let device_name = monitor_info.szDevice.as_ptr();
let mut mode: wingdi::DEVMODEW = mem::zeroed();
mode.dmSize = mem::size_of_val(&mode) as WORD;
if winuser::EnumDisplaySettingsExW(device_name, i, &mut mode, 0) == 0 {
let mut mode: DEVMODEW = mem::zeroed();
mode.dmSize = mem::size_of_val(&mode) as u16;
if EnumDisplaySettingsExW(device_name, i, &mut mode, 0) == false.into() {
break;
}
i += 1;
const REQUIRED_FIELDS: DWORD = wingdi::DM_BITSPERPEL
| wingdi::DM_PELSWIDTH
| wingdi::DM_PELSHEIGHT
| wingdi::DM_DISPLAYFREQUENCY;
assert!(mode.dmFields & REQUIRED_FIELDS == REQUIRED_FIELDS);
const REQUIRED_FIELDS: u32 =
(DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY) as u32;
assert!(has_flag(mode.dmFields, REQUIRED_FIELDS));
modes.insert(RootVideoMode {
video_mode: VideoMode {

View file

@ -1,22 +1,26 @@
use std::{
ffi::OsString,
mem::{self, size_of},
os::windows::prelude::OsStringExt,
ptr,
};
use winapi::{
ctypes::wchar_t,
shared::{
hidusage::{HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC},
minwindef::{TRUE, UINT, USHORT},
windef::HWND,
use windows_sys::Win32::{
Devices::HumanInterfaceDevice::{
HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC,
},
um::{
winnt::HANDLE,
winuser::{
self, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER,
RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO,
RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT,
RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
Foundation::{HANDLE, HWND},
UI::{
Input::{
GetRawInputData, GetRawInputDeviceInfoW, GetRawInputDeviceList,
RegisterRawInputDevices, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST,
RAWINPUTHEADER, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME,
RID_DEVICE_INFO, RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE,
RID_INPUT, RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
},
WindowsAndMessaging::{
RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP, RI_MOUSE_MIDDLE_BUTTON_DOWN,
RI_MOUSE_MIDDLE_BUTTON_UP, RI_MOUSE_RIGHT_BUTTON_DOWN, RI_MOUSE_RIGHT_BUTTON_UP,
},
},
};
@ -25,23 +29,21 @@ use crate::{event::ElementState, platform_impl::platform::util};
#[allow(dead_code)]
pub fn get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>> {
let list_size = size_of::<RAWINPUTDEVICELIST>() as UINT;
let list_size = size_of::<RAWINPUTDEVICELIST>() as u32;
let mut num_devices = 0;
let status =
unsafe { winuser::GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) };
let status = unsafe { GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) };
if status == UINT::max_value() {
if status == u32::MAX {
return None;
}
let mut buffer = Vec::with_capacity(num_devices as _);
let num_stored = unsafe {
winuser::GetRawInputDeviceList(buffer.as_ptr() as _, &mut num_devices, list_size)
};
let num_stored =
unsafe { GetRawInputDeviceList(buffer.as_mut_ptr(), &mut num_devices, list_size) };
if num_stored == UINT::max_value() {
if num_stored == u32::MAX {
return None;
}
@ -63,9 +65,9 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
fn from(info: RID_DEVICE_INFO) -> Self {
unsafe {
match info.dwType {
RIM_TYPEMOUSE => RawDeviceInfo::Mouse(*info.u.mouse()),
RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(*info.u.keyboard()),
RIM_TYPEHID => RawDeviceInfo::Hid(*info.u.hid()),
RIM_TYPEMOUSE => RawDeviceInfo::Mouse(info.Anonymous.mouse),
RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(info.Anonymous.keyboard),
RIM_TYPEHID => RawDeviceInfo::Hid(info.Anonymous.hid),
_ => unreachable!(),
}
}
@ -75,13 +77,13 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
#[allow(dead_code)]
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
let info_size = size_of::<RID_DEVICE_INFO>() as u32;
info.cbSize = info_size;
let mut minimum_size = 0;
let status = unsafe {
winuser::GetRawInputDeviceInfoW(
GetRawInputDeviceInfoW(
handle,
RIDI_DEVICEINFO,
&mut info as *mut _ as _,
@ -89,7 +91,7 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
)
};
if status == UINT::max_value() || status == 0 {
if status == u32::MAX || status == 0 {
return None;
}
@ -101,17 +103,17 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
let mut minimum_size = 0;
let status = unsafe {
winuser::GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size)
GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size)
};
if status != 0 {
return None;
}
let mut name: Vec<wchar_t> = Vec::with_capacity(minimum_size as _);
let mut name: Vec<u16> = Vec::with_capacity(minimum_size as _);
let status = unsafe {
winuser::GetRawInputDeviceInfoW(
GetRawInputDeviceInfoW(
handle,
RIDI_DEVICENAME,
name.as_ptr() as _,
@ -119,7 +121,7 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
)
};
if status == UINT::max_value() || status == 0 {
if status == u32::MAX || status == 0 {
return None;
}
@ -127,17 +129,15 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
unsafe { name.set_len(minimum_size as _) };
Some(util::wchar_to_string(&name))
OsString::from_wide(&name).into_string().ok()
}
pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool {
let device_size = size_of::<RAWINPUTDEVICE>() as UINT;
let device_size = size_of::<RAWINPUTDEVICE>() as u32;
let success = unsafe {
winuser::RegisterRawInputDevices(devices.as_ptr() as _, devices.len() as _, device_size)
};
success == TRUE
unsafe {
RegisterRawInputDevices(devices.as_ptr(), devices.len() as u32, device_size) == true.into()
}
}
pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool {
@ -165,11 +165,11 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
let mut data: RAWINPUT = unsafe { mem::zeroed() };
let mut data_size = size_of::<RAWINPUT>() as UINT;
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
let mut data_size = size_of::<RAWINPUT>() as u32;
let header_size = size_of::<RAWINPUTHEADER>() as u32;
let status = unsafe {
winuser::GetRawInputData(
GetRawInputData(
handle,
RID_INPUT,
&mut data as *mut _ as _,
@ -178,7 +178,7 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
)
};
if status == UINT::max_value() || status == 0 {
if status == u32::MAX || status == 0 {
return None;
}
@ -186,9 +186,9 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
}
fn button_flags_to_element_state(
button_flags: USHORT,
down_flag: USHORT,
up_flag: USHORT,
button_flags: u32,
down_flag: u32,
up_flag: u32,
) -> Option<ElementState> {
// We assume the same button won't be simultaneously pressed and released.
if util::has_flag(button_flags, down_flag) {
@ -200,22 +200,22 @@ fn button_flags_to_element_state(
}
}
pub fn get_raw_mouse_button_state(button_flags: USHORT) -> [Option<ElementState>; 3] {
pub fn get_raw_mouse_button_state(button_flags: u32) -> [Option<ElementState>; 3] {
[
button_flags_to_element_state(
button_flags,
winuser::RI_MOUSE_LEFT_BUTTON_DOWN,
winuser::RI_MOUSE_LEFT_BUTTON_UP,
RI_MOUSE_LEFT_BUTTON_DOWN,
RI_MOUSE_LEFT_BUTTON_UP,
),
button_flags_to_element_state(
button_flags,
winuser::RI_MOUSE_MIDDLE_BUTTON_DOWN,
winuser::RI_MOUSE_MIDDLE_BUTTON_UP,
RI_MOUSE_MIDDLE_BUTTON_DOWN,
RI_MOUSE_MIDDLE_BUTTON_UP,
),
button_flags_to_element_state(
button_flags,
winuser::RI_MOUSE_RIGHT_BUTTON_DOWN,
winuser::RI_MOUSE_RIGHT_BUTTON_UP,
RI_MOUSE_RIGHT_BUTTON_DOWN,
RI_MOUSE_RIGHT_BUTTON_UP,
),
]
}

View file

@ -1,27 +1,42 @@
use std::{
io, mem,
ffi::{c_void, OsStr},
io,
iter::once,
mem,
ops::BitAnd,
os::raw::c_void,
ptr, slice,
os::windows::prelude::OsStrExt,
ptr,
sync::atomic::{AtomicBool, Ordering},
};
use crate::{dpi::PhysicalSize, window::CursorIcon};
use winapi::{
ctypes::wchar_t,
shared::{
minwindef::{BOOL, DWORD, UINT},
windef::{DPI_AWARENESS_CONTEXT, HMONITOR, HWND, LPRECT, RECT},
},
um::{
libloaderapi::{GetProcAddress, LoadLibraryA},
shellscalingapi::{MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS},
winbase::lstrlenW,
winnt::{HRESULT, LONG, LPCSTR},
winuser,
use windows_sys::{
core::{HRESULT, PCWSTR},
Win32::{
Foundation::{BOOL, HWND, RECT},
Graphics::Gdi::{ClientToScreen, InvalidateRgn, HMONITOR},
System::LibraryLoader::{GetProcAddress, LoadLibraryA},
UI::{
HiDpi::{DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS},
Input::KeyboardAndMouse::GetActiveWindow,
WindowsAndMessaging::{
AdjustWindowRectEx, ClipCursor, GetClientRect, GetClipCursor, GetMenu,
GetSystemMetrics, GetWindowLongW, GetWindowRect, SetWindowPos, ShowCursor,
GWL_EXSTYLE, GWL_STYLE, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP,
IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE,
IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,
SM_YVIRTUALSCREEN, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOMOVE,
SWP_NOREPOSITION, SWP_NOZORDER, WINDOW_EX_STYLE, WINDOW_STYLE,
},
},
},
};
use crate::{dpi::PhysicalSize, window::CursorIcon};
pub fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
string.as_ref().encode_wide().chain(once(0)).collect()
}
pub fn has_flag<T>(bitset: T, flag: T) -> bool
where
T: Copy + PartialEq + BitAnd<T, Output = T>,
@ -29,19 +44,9 @@ where
bitset & flag == flag
}
pub fn wchar_to_string(wchar: &[wchar_t]) -> String {
String::from_utf16_lossy(wchar)
}
pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String {
let len = unsafe { lstrlenW(wchar) } as usize;
let wchar_slice = unsafe { slice::from_raw_parts(wchar, len) };
wchar_to_string(wchar_slice)
}
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
let mut data: T = mem::zeroed();
if fun(&mut data) != 0 {
if fun(&mut data) != false.into() {
Some(data)
} else {
None
@ -49,7 +54,7 @@ pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
}
fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
if f() != 0 {
if f() != false.into() {
Ok(())
} else {
Err(io::Error::last_os_error())
@ -57,7 +62,7 @@ fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
}
pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
unsafe { status_map(|rect| winuser::GetWindowRect(hwnd, rect)) }
unsafe { status_map(|rect| GetWindowRect(hwnd, rect)) }
}
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
@ -65,8 +70,8 @@ pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
let mut rect = mem::zeroed();
let mut top_left = mem::zeroed();
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;
win_to_err(|| winuser::GetClientRect(hwnd, &mut rect))?;
win_to_err(|| ClientToScreen(hwnd, &mut top_left))?;
win_to_err(|| GetClientRect(hwnd, &mut rect))?;
rect.left += top_left.x;
rect.top += top_left.y;
rect.right += top_left.x;
@ -80,9 +85,9 @@ pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
let (width, height): (u32, u32) = size.into();
let rect = RECT {
left: 0,
right: width as LONG,
right: width as i32,
top: 0,
bottom: height as LONG,
bottom: height as i32,
};
let rect = adjust_window_rect(hwnd, rect).unwrap_or(rect);
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
@ -95,57 +100,53 @@ pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
RECT {
top: 0,
left: 0,
bottom: y as LONG,
right: x as LONG,
bottom: y as i32,
right: x as i32,
},
)
.expect("adjust_window_rect failed");
let outer_x = (rect.right - rect.left).abs() as _;
let outer_y = (rect.top - rect.bottom).abs() as _;
winuser::SetWindowPos(
SetWindowPos(
window,
ptr::null_mut(),
0,
0,
0,
outer_x,
outer_y,
winuser::SWP_ASYNCWINDOWPOS
| winuser::SWP_NOZORDER
| winuser::SWP_NOREPOSITION
| winuser::SWP_NOMOVE
| winuser::SWP_NOACTIVATE,
SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOACTIVATE,
);
winuser::InvalidateRgn(window, ptr::null_mut(), 0);
InvalidateRgn(window, 0, false.into());
}
}
pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
unsafe {
let style = winuser::GetWindowLongW(hwnd, winuser::GWL_STYLE);
let style_ex = winuser::GetWindowLongW(hwnd, winuser::GWL_EXSTYLE);
adjust_window_rect_with_styles(hwnd, style as _, style_ex as _, rect)
let style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
adjust_window_rect_with_styles(hwnd, style, style_ex, rect)
}
}
pub fn adjust_window_rect_with_styles(
hwnd: HWND,
style: DWORD,
style_ex: DWORD,
style: WINDOW_STYLE,
style_ex: WINDOW_EX_STYLE,
rect: RECT,
) -> Option<RECT> {
unsafe {
status_map(|r| {
*r = rect;
let b_menu = !winuser::GetMenu(hwnd).is_null() as BOOL;
let b_menu = GetMenu(hwnd) != 0;
if let (Some(get_dpi_for_window), Some(adjust_window_rect_ex_for_dpi)) =
(*GET_DPI_FOR_WINDOW, *ADJUST_WINDOW_RECT_EX_FOR_DPI)
{
let dpi = get_dpi_for_window(hwnd);
adjust_window_rect_ex_for_dpi(r, style as _, b_menu, style_ex as _, dpi)
adjust_window_rect_ex_for_dpi(r, style, b_menu.into(), style_ex, dpi)
} else {
winuser::AdjustWindowRectEx(r, style as _, b_menu, style_ex as _)
AdjustWindowRectEx(r, style, b_menu.into(), style_ex)
}
})
}
@ -155,14 +156,14 @@ pub fn set_cursor_hidden(hidden: bool) {
static HIDDEN: AtomicBool = AtomicBool::new(false);
let changed = HIDDEN.swap(hidden, Ordering::SeqCst) ^ hidden;
if changed {
unsafe { winuser::ShowCursor(!hidden as BOOL) };
unsafe { ShowCursor(BOOL::from(!hidden)) };
}
}
pub fn get_cursor_clip() -> Result<RECT, io::Error> {
unsafe {
let mut rect: RECT = mem::zeroed();
win_to_err(|| winuser::GetClipCursor(&mut rect)).map(|_| rect)
win_to_err(|| GetClipCursor(&mut rect)).map(|_| rect)
}
}
@ -175,56 +176,52 @@ pub fn set_cursor_clip(rect: Option<RECT>) -> Result<(), io::Error> {
.as_ref()
.map(|r| r as *const RECT)
.unwrap_or(ptr::null());
win_to_err(|| winuser::ClipCursor(rect_ptr))
win_to_err(|| ClipCursor(rect_ptr))
}
}
pub fn get_desktop_rect() -> RECT {
unsafe {
let left = winuser::GetSystemMetrics(winuser::SM_XVIRTUALSCREEN);
let top = winuser::GetSystemMetrics(winuser::SM_YVIRTUALSCREEN);
let left = GetSystemMetrics(SM_XVIRTUALSCREEN);
let top = GetSystemMetrics(SM_YVIRTUALSCREEN);
RECT {
left,
top,
right: left + winuser::GetSystemMetrics(winuser::SM_CXVIRTUALSCREEN),
bottom: top + winuser::GetSystemMetrics(winuser::SM_CYVIRTUALSCREEN),
right: left + GetSystemMetrics(SM_CXVIRTUALSCREEN),
bottom: top + GetSystemMetrics(SM_CYVIRTUALSCREEN),
}
}
}
pub fn is_focused(window: HWND) -> bool {
window == unsafe { winuser::GetActiveWindow() }
window == unsafe { GetActiveWindow() }
}
impl CursorIcon {
pub(crate) fn to_windows_cursor(self) -> *const wchar_t {
pub(crate) fn to_windows_cursor(self) -> PCWSTR {
match self {
CursorIcon::Arrow | CursorIcon::Default => winuser::IDC_ARROW,
CursorIcon::Hand => winuser::IDC_HAND,
CursorIcon::Crosshair => winuser::IDC_CROSS,
CursorIcon::Text | CursorIcon::VerticalText => winuser::IDC_IBEAM,
CursorIcon::NotAllowed | CursorIcon::NoDrop => winuser::IDC_NO,
CursorIcon::Arrow | CursorIcon::Default => IDC_ARROW,
CursorIcon::Hand => IDC_HAND,
CursorIcon::Crosshair => IDC_CROSS,
CursorIcon::Text | CursorIcon::VerticalText => IDC_IBEAM,
CursorIcon::NotAllowed | CursorIcon::NoDrop => IDC_NO,
CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => {
winuser::IDC_SIZEALL
IDC_SIZEALL
}
CursorIcon::EResize
| CursorIcon::WResize
| CursorIcon::EwResize
| CursorIcon::ColResize => winuser::IDC_SIZEWE,
| CursorIcon::ColResize => IDC_SIZEWE,
CursorIcon::NResize
| CursorIcon::SResize
| CursorIcon::NsResize
| CursorIcon::RowResize => winuser::IDC_SIZENS,
CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => {
winuser::IDC_SIZENESW
}
CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => {
winuser::IDC_SIZENWSE
}
CursorIcon::Wait => winuser::IDC_WAIT,
CursorIcon::Progress => winuser::IDC_APPSTARTING,
CursorIcon::Help => winuser::IDC_HELP,
_ => winuser::IDC_ARROW, // use arrow for the missing cases.
| CursorIcon::RowResize => IDC_SIZENS,
CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => IDC_SIZENESW,
CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => IDC_SIZENWSE,
CursorIcon::Wait => IDC_WAIT,
CursorIcon::Progress => IDC_APPSTARTING,
CursorIcon::Help => IDC_HELP,
_ => IDC_ARROW, // use arrow for the missing cases.
}
}
}
@ -236,17 +233,12 @@ pub(super) fn get_function_impl(library: &str, function: &str) -> Option<*const
assert_eq!(function.chars().last(), Some('\0'));
// Library names we will use are ASCII so we can use the A version to avoid string conversion.
let module = unsafe { LoadLibraryA(library.as_ptr() as LPCSTR) };
if module.is_null() {
let module = unsafe { LoadLibraryA(library.as_ptr()) };
if module == 0 {
return None;
}
let function_ptr = unsafe { GetProcAddress(module, function.as_ptr() as LPCSTR) };
if function_ptr.is_null() {
return None;
}
Some(function_ptr as _)
unsafe { GetProcAddress(module, function.as_ptr()) }.map(|function_ptr| function_ptr as _)
}
macro_rules! get_function {
@ -264,20 +256,20 @@ pub type SetProcessDpiAwareness =
unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT;
pub type SetProcessDpiAwarenessContext =
unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL;
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> UINT;
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32;
pub type GetDpiForMonitor = unsafe extern "system" fn(
hmonitor: HMONITOR,
dpi_type: MONITOR_DPI_TYPE,
dpi_x: *mut UINT,
dpi_y: *mut UINT,
dpi_x: *mut u32,
dpi_y: *mut u32,
) -> HRESULT;
pub type EnableNonClientDpiScaling = unsafe extern "system" fn(hwnd: HWND) -> BOOL;
pub type AdjustWindowRectExForDpi = unsafe extern "system" fn(
rect: LPRECT,
dwStyle: DWORD,
rect: *mut RECT,
dwStyle: u32,
bMenu: BOOL,
dwExStyle: DWORD,
dpi: UINT,
dwExStyle: u32,
dpi: u32,
) -> BOOL;
lazy_static! {

View file

@ -4,31 +4,54 @@ use parking_lot::Mutex;
use raw_window_handle::{RawWindowHandle, Win32Handle};
use std::{
cell::Cell,
ffi::OsStr,
io, mem,
os::windows::ffi::OsStrExt,
panic, ptr,
ffi::c_void,
io, mem, panic, ptr,
sync::{mpsc::channel, Arc},
};
use winapi::{
ctypes::c_int,
shared::{
minwindef::{HINSTANCE, LPARAM, UINT, WPARAM},
windef::{HWND, POINT, POINTS, RECT},
winerror::SUCCEEDED,
use windows_sys::Win32::{
Foundation::{
HINSTANCE, HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK,
WPARAM,
},
um::{
combaseapi, dwmapi,
imm::{CFS_POINT, COMPOSITIONFORM},
libloaderapi,
objbase::COINIT_APARTMENTTHREADED,
ole2,
oleidl::LPDROPTARGET,
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
wingdi::{CreateRectRgn, DeleteObject},
winnt::{LPCWSTR, SHORT},
winuser,
Graphics::{
Dwm::{DwmEnableBlurBehindWindow, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND},
Gdi::{
ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE,
DISP_CHANGE_BADPARAM, DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, RDW_INTERNALPAINT,
},
},
System::{
Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_APARTMENTTHREADED,
},
LibraryLoader::GetModuleHandleW,
Ole::{OleInitialize, RegisterDragDrop},
},
UI::{
Input::{
Ime::{
ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT,
COMPOSITIONFORM,
},
KeyboardAndMouse::{
EnableWindow, GetActiveWindow, MapVirtualKeyW, ReleaseCapture, SendInput, INPUT,
INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP,
VK_LMENU, VK_MENU,
},
Touch::{RegisterTouchWindow, TWF_WANTPALM},
},
WindowsAndMessaging::{
CreateWindowExW, FlashWindowEx, GetClientRect, GetCursorPos, GetForegroundWindow,
GetSystemMetrics, GetWindowPlacement, IsWindowVisible, LoadCursorW, PeekMessageW,
PostMessageW, RegisterClassExW, SetCursor, SetCursorPos, SetForegroundWindow,
SetWindowPlacement, SetWindowPos, SetWindowTextW, CS_HREDRAW, CS_OWNDC, CS_VREDRAW,
CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY,
GWLP_HINSTANCE, HTCAPTION, MAPVK_VK_TO_VSC, NID_READY, PM_NOREMOVE, SM_DIGITIZER,
SM_IMMENABLED, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER,
WM_NCLBUTTONDOWN, WNDCLASSEXW,
},
},
};
@ -39,9 +62,11 @@ use crate::{
monitor::MonitorHandle as RootMonitorHandle,
platform_impl::platform::{
dark_mode::try_theme,
definitions::ITaskbarList2,
definitions::{CLSID_TaskbarList, IID_ITaskbarList2},
dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi},
drop_handler::FileDropHandler,
event_loop::{self, EventLoopWindowTarget, WindowLongPtr, DESTROY_MSG_ID},
event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID},
icon::{self, IconType},
monitor, util,
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
@ -76,12 +101,9 @@ impl Window {
}
pub fn set_title(&self, text: &str) {
let text = OsStr::new(text)
.encode_wide()
.chain(Some(0).into_iter())
.collect::<Vec<_>>();
let wide_text = util::encode_wide(text);
unsafe {
winuser::SetWindowTextW(self.window.0, text.as_ptr() as LPCWSTR);
SetWindowTextW(self.hwnd(), wide_text.as_ptr());
}
}
@ -99,24 +121,19 @@ impl Window {
#[inline]
pub fn is_visible(&self) -> Option<bool> {
Some(unsafe { winuser::IsWindowVisible(self.window.0) == 1 })
Some(unsafe { IsWindowVisible(self.window.0) == 1 })
}
#[inline]
pub fn request_redraw(&self) {
unsafe {
winuser::RedrawWindow(
self.window.0,
ptr::null(),
ptr::null_mut(),
winuser::RDW_INTERNALPAINT,
);
RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT);
}
}
#[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
util::get_window_rect(self.window.0)
util::get_window_rect(self.hwnd())
.map(|rect| Ok(PhysicalPosition::new(rect.left as i32, rect.top as i32)))
.expect("Unexpected GetWindowRect failure; please report this error to https://github.com/rust-windowing/winit")
}
@ -124,7 +141,7 @@ impl Window {
#[inline]
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let mut position: POINT = unsafe { mem::zeroed() };
if unsafe { winuser::ClientToScreen(self.window.0, &mut position) } == 0 {
if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() {
panic!("Unexpected ClientToScreen failure: please report this error to https://github.com/rust-windowing/winit")
}
Ok(PhysicalPosition::new(position.x as i32, position.y as i32))
@ -144,26 +161,23 @@ impl Window {
});
unsafe {
winuser::SetWindowPos(
self.window.0,
ptr::null_mut(),
x as c_int,
y as c_int,
SetWindowPos(
self.hwnd(),
0,
x,
y,
0,
0,
winuser::SWP_ASYNCWINDOWPOS
| winuser::SWP_NOZORDER
| winuser::SWP_NOSIZE
| winuser::SWP_NOACTIVATE,
SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE,
);
winuser::InvalidateRgn(self.window.0, ptr::null_mut(), 0);
InvalidateRgn(self.hwnd(), 0, false.into());
}
}
#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() {
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
}
PhysicalSize::new(
@ -174,7 +188,7 @@ impl Window {
#[inline]
pub fn outer_size(&self) -> PhysicalSize<u32> {
util::get_window_rect(self.window.0)
util::get_window_rect(self.hwnd())
.map(|rect| {
PhysicalSize::new(
(rect.right - rect.left) as u32,
@ -198,7 +212,7 @@ impl Window {
});
});
util::set_inner_size_physical(self.window.0, width, height);
util::set_inner_size_physical(self.hwnd(), width, height);
}
#[inline]
@ -244,7 +258,7 @@ impl Window {
#[inline]
pub fn hinstance(&self) -> HINSTANCE {
unsafe { winuser::GetWindowLongPtrW(self.hwnd(), winuser::GWLP_HINSTANCE) as *mut _ }
unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) }
}
#[inline]
@ -259,8 +273,8 @@ impl Window {
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
self.window_state.lock().mouse.cursor = cursor;
self.thread_executor.execute_in_thread(move || unsafe {
let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor());
winuser::SetCursor(cursor);
let cursor = LoadCursorW(0, cursor.to_windows_cursor());
SetCursor(cursor);
});
}
@ -312,10 +326,10 @@ impl Window {
let mut point = POINT { x, y };
unsafe {
if winuser::ClientToScreen(self.window.0, &mut point) == 0 {
if ClientToScreen(self.hwnd(), &mut point) == false.into() {
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
}
if winuser::SetCursorPos(point.x, point.y) == 0 {
if SetCursorPos(point.x, point.y) == false.into() {
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
}
}
@ -327,18 +341,18 @@ impl Window {
unsafe {
let points = {
let mut pos = mem::zeroed();
winuser::GetCursorPos(&mut pos);
GetCursorPos(&mut pos);
pos
};
let points = POINTS {
x: points.x as SHORT,
y: points.y as SHORT,
x: points.x as i16,
y: points.y as i16,
};
winuser::ReleaseCapture();
winuser::PostMessageW(
self.window.0,
winuser::WM_NCLBUTTONDOWN,
winuser::HTCAPTION as WPARAM,
ReleaseCapture();
PostMessageW(
self.hwnd(),
WM_NCLBUTTONDOWN,
HTCAPTION as WPARAM,
&points as *const _ as LPARAM,
);
}
@ -348,7 +362,7 @@ impl Window {
#[inline]
pub fn id(&self) -> WindowId {
WindowId(self.window.0)
WindowId(self.hwnd())
}
#[inline]
@ -415,50 +429,43 @@ impl Window {
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Exclusive(ref video_mode))) =>
{
let monitor = video_mode.monitor();
let monitor_info = monitor::get_monitor_info(monitor.inner.hmonitor()).unwrap();
let mut display_name = OsStr::new(&monitor.inner.native_identifier())
.encode_wide()
.collect::<Vec<_>>();
// `encode_wide` does not add a null-terminator but
// `ChangeDisplaySettingsExW` requires a null-terminated
// string, so add it
display_name.push(0);
let mut native_video_mode = video_mode.video_mode.native_video_mode;
let native_video_mode = video_mode.video_mode.native_video_mode;
let res = unsafe {
winuser::ChangeDisplaySettingsExW(
display_name.as_ptr(),
&mut native_video_mode,
std::ptr::null_mut(),
winuser::CDS_FULLSCREEN,
std::ptr::null_mut(),
ChangeDisplaySettingsExW(
monitor_info.szDevice.as_ptr(),
&native_video_mode,
0,
CDS_FULLSCREEN,
ptr::null(),
)
};
debug_assert!(res != winuser::DISP_CHANGE_BADFLAGS);
debug_assert!(res != winuser::DISP_CHANGE_BADMODE);
debug_assert!(res != winuser::DISP_CHANGE_BADPARAM);
debug_assert!(res != winuser::DISP_CHANGE_FAILED);
assert_eq!(res, winuser::DISP_CHANGE_SUCCESSFUL);
debug_assert!(res != DISP_CHANGE_BADFLAGS);
debug_assert!(res != DISP_CHANGE_BADMODE);
debug_assert!(res != DISP_CHANGE_BADPARAM);
debug_assert!(res != DISP_CHANGE_FAILED);
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
}
(&Some(Fullscreen::Exclusive(_)), &None)
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
let res = unsafe {
winuser::ChangeDisplaySettingsExW(
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
winuser::CDS_FULLSCREEN,
std::ptr::null_mut(),
ChangeDisplaySettingsExW(
ptr::null(),
ptr::null(),
0,
CDS_FULLSCREEN,
ptr::null(),
)
};
debug_assert!(res != winuser::DISP_CHANGE_BADFLAGS);
debug_assert!(res != winuser::DISP_CHANGE_BADMODE);
debug_assert!(res != winuser::DISP_CHANGE_BADPARAM);
debug_assert!(res != winuser::DISP_CHANGE_FAILED);
assert_eq!(res, winuser::DISP_CHANGE_SUCCESSFUL);
debug_assert!(res != DISP_CHANGE_BADFLAGS);
debug_assert!(res != DISP_CHANGE_BADMODE);
debug_assert!(res != DISP_CHANGE_BADPARAM);
debug_assert!(res != DISP_CHANGE_FAILED);
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
}
_ => (),
}
@ -473,7 +480,7 @@ impl Window {
// fine, taking control back from the DWM and ensuring that the `SetWindowPos` call
// below goes through.
let mut msg = mem::zeroed();
winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0);
PeekMessageW(&mut msg, 0, 0, 0, PM_NOREMOVE);
}
// Update window style
@ -494,7 +501,7 @@ impl Window {
// Save window bounds before entering fullscreen
let placement = unsafe {
let mut placement = mem::zeroed();
winuser::GetWindowPlacement(window.0, &mut placement);
GetWindowPlacement(window.0, &mut placement);
placement
};
@ -512,16 +519,16 @@ impl Window {
let size: (u32, u32) = monitor.size().into();
unsafe {
winuser::SetWindowPos(
SetWindowPos(
window.0,
ptr::null_mut(),
0,
position.0,
position.1,
size.0 as i32,
size.1 as i32,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER,
SWP_ASYNCWINDOWPOS | SWP_NOZORDER,
);
winuser::InvalidateRgn(window.0, ptr::null_mut(), 0);
InvalidateRgn(window.0, 0, false.into());
}
}
None => {
@ -529,8 +536,8 @@ impl Window {
if let Some(SavedWindow { placement }) = window_state_lock.saved_window.take() {
drop(window_state_lock);
unsafe {
winuser::SetWindowPlacement(window.0, &placement);
winuser::InvalidateRgn(window.0, ptr::null_mut(), 0);
SetWindowPlacement(window.0, &placement);
InvalidateRgn(window.0, 0, false.into());
}
}
}
@ -577,7 +584,7 @@ impl Window {
#[inline]
pub fn current_monitor(&self) -> Option<RootMonitorHandle> {
Some(RootMonitorHandle {
inner: monitor::current_monitor(self.window.0),
inner: monitor::current_monitor(self.hwnd()),
})
}
@ -586,16 +593,16 @@ impl Window {
if let Some(ref window_icon) = window_icon {
window_icon
.inner
.set_for_window(self.window.0, IconType::Small);
.set_for_window(self.hwnd(), IconType::Small);
} else {
icon::unset_for_window(self.window.0, IconType::Small);
icon::unset_for_window(self.hwnd(), IconType::Small);
}
self.window_state.lock().window_icon = window_icon;
}
#[inline]
pub fn set_enable(&self, enabled: bool) {
unsafe { winuser::EnableWindow(self.hwnd() as _, enabled as _) };
unsafe { EnableWindow(self.hwnd(), enabled.into()) };
}
#[inline]
@ -603,24 +610,24 @@ impl Window {
if let Some(ref taskbar_icon) = taskbar_icon {
taskbar_icon
.inner
.set_for_window(self.window.0, IconType::Big);
.set_for_window(self.hwnd(), IconType::Big);
} else {
icon::unset_for_window(self.window.0, IconType::Big);
icon::unset_for_window(self.hwnd(), IconType::Big);
}
self.window_state.lock().taskbar_icon = taskbar_icon;
}
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
if unsafe { winuser::GetSystemMetrics(winuser::SM_IMMENABLED) } != 0 {
let mut composition_form = COMPOSITIONFORM {
if unsafe { GetSystemMetrics(SM_IMMENABLED) } != 0 {
let composition_form = COMPOSITIONFORM {
dwStyle: CFS_POINT,
ptCurrentPos: POINT { x, y },
rcArea: unsafe { mem::zeroed() },
};
unsafe {
let himc = winapi::um::imm::ImmGetContext(self.window.0);
winapi::um::imm::ImmSetCompositionWindow(himc, &mut composition_form);
winapi::um::imm::ImmReleaseContext(self.window.0, himc);
let himc = ImmGetContext(self.hwnd());
ImmSetCompositionWindow(himc, &composition_form);
ImmReleaseContext(self.hwnd(), himc);
}
}
}
@ -634,7 +641,7 @@ impl Window {
#[inline]
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
let window = self.window.clone();
let active_window_handle = unsafe { winuser::GetActiveWindow() };
let active_window_handle = unsafe { GetActiveWindow() };
if window.0 == active_window_handle {
return;
}
@ -643,23 +650,19 @@ impl Window {
let _ = &window;
let (flags, count) = request_type
.map(|ty| match ty {
UserAttentionType::Critical => {
(winuser::FLASHW_ALL | winuser::FLASHW_TIMERNOFG, u32::MAX)
}
UserAttentionType::Informational => {
(winuser::FLASHW_TRAY | winuser::FLASHW_TIMERNOFG, 0)
}
UserAttentionType::Critical => (FLASHW_ALL | FLASHW_TIMERNOFG, u32::MAX),
UserAttentionType::Informational => (FLASHW_TRAY | FLASHW_TIMERNOFG, 0),
})
.unwrap_or((winuser::FLASHW_STOP, 0));
.unwrap_or((FLASHW_STOP, 0));
let mut flash_info = winuser::FLASHWINFO {
cbSize: mem::size_of::<winuser::FLASHWINFO>() as UINT,
let flash_info = FLASHWINFO {
cbSize: mem::size_of::<FLASHWINFO>() as u32,
hwnd: window.0,
dwFlags: flags,
uCount: count,
dwTimeout: 0,
};
winuser::FlashWindowEx(&mut flash_info);
FlashWindowEx(&flash_info);
});
}
@ -675,7 +678,7 @@ impl Window {
let is_visible = window_flags.contains(WindowFlags::VISIBLE);
let is_minimized = window_flags.contains(WindowFlags::MINIMIZED);
let is_foreground = window.0 == unsafe { winuser::GetForegroundWindow() };
let is_foreground = window.0 == unsafe { GetForegroundWindow() };
if is_visible && !is_minimized && !is_foreground {
unsafe { force_window_active(window.0) };
@ -689,7 +692,7 @@ impl Drop for Window {
unsafe {
// The window must be destroyed from the same thread that created it, so we send a
// custom message to be handled by our callback to do the actual work.
winuser::PostMessageW(self.window.0, *DESTROY_MSG_ID, 0, 0);
PostMessageW(self.hwnd(), *DESTROY_MSG_ID, 0, 0);
}
}
}
@ -720,9 +723,9 @@ impl<'a, T: 'static> InitData<'a, T> {
unsafe fn create_window(&self, window: HWND) -> Window {
// Register for touch events if applicable
{
let digitizer = winuser::GetSystemMetrics(winuser::SM_DIGITIZER) as u32;
if digitizer & winuser::NID_READY != 0 {
winuser::RegisterTouchWindow(window, winuser::TWF_WANTPALM);
let digitizer = GetSystemMetrics(SM_DIGITIZER) as u32;
if digitizer & NID_READY != 0 {
RegisterTouchWindow(window, TWF_WANTPALM);
}
}
@ -758,9 +761,7 @@ impl<'a, T: 'static> InitData<'a, T> {
unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData<T> {
let file_drop_handler = if self.pl_attribs.drag_and_drop {
use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK};
let ole_init_result = ole2::OleInitialize(ptr::null_mut());
let ole_init_result = OleInitialize(ptr::null_mut());
// It is ok if the initialize result is `S_FALSE` because it might happen that
// multiple windows are created on the same thread.
if ole_init_result == OLE_E_WRONGCOMPOBJ {
@ -782,12 +783,11 @@ impl<'a, T: 'static> InitData<'a, T> {
}
}),
);
let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET;
assert_eq!(
ole2::RegisterDragDrop(win.window.0, handler_interface_ptr),
S_OK
);
let handler_interface_ptr =
&mut (*file_drop_handler.data).interface as *mut _ as *mut c_void;
assert_eq!(RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK);
Some(file_drop_handler)
} else {
None
@ -806,7 +806,7 @@ impl<'a, T: 'static> InitData<'a, T> {
// Returns a pointer to window user data on success.
// The user data will be registered for the window and can be accessed within the window event callback.
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<WindowLongPtr> {
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
let runner = self.event_loop.runner_shared.clone();
let result = runner.catch_unwind(|| {
let mut window = self.create_window(window);
@ -829,20 +829,20 @@ impl<'a, T: 'static> InitData<'a, T> {
// Empty region for the blur effect, so the window is fully transparent
let region = CreateRectRgn(0, 0, -1, -1);
let bb = dwmapi::DWM_BLURBEHIND {
dwFlags: dwmapi::DWM_BB_ENABLE | dwmapi::DWM_BB_BLURREGION,
fEnable: 1,
let bb = DWM_BLURBEHIND {
dwFlags: DWM_BB_ENABLE | DWM_BB_BLURREGION,
fEnable: true.into(),
hRgnBlur: region,
fTransitionOnMaximized: 0,
fTransitionOnMaximized: false.into(),
};
let hr = dwmapi::DwmEnableBlurBehindWindow(win.hwnd(), &bb);
if !SUCCEEDED(hr) {
let hr = DwmEnableBlurBehindWindow(win.hwnd(), &bb);
if hr < 0 {
warn!(
"Setting transparent window is failed. HRESULT Code: 0x{:X}",
hr
);
}
DeleteObject(region as _);
DeleteObject(region);
}
let attributes = self.attributes.clone();
@ -879,12 +879,8 @@ unsafe fn init<T>(
where
T: 'static,
{
let title = OsStr::new(&attributes.title)
.encode_wide()
.chain(Some(0).into_iter())
.collect::<Vec<_>>();
let title = util::encode_wide(&attributes.title);
// registering the window class
let class_name = register_window_class::<T>(&attributes.window_icon, &pl_attribs.taskbar_icon);
let mut window_flags = WindowFlags::empty();
@ -925,18 +921,18 @@ where
};
let (style, ex_style) = window_flags.to_window_styles();
let handle = winuser::CreateWindowExW(
let handle = CreateWindowExW(
ex_style,
class_name.as_ptr(),
title.as_ptr() as LPCWSTR,
title.as_ptr(),
style,
winuser::CW_USEDEFAULT,
winuser::CW_USEDEFAULT,
winuser::CW_USEDEFAULT,
winuser::CW_USEDEFAULT,
parent.unwrap_or(ptr::null_mut()),
pl_attribs.menu.unwrap_or(ptr::null_mut()),
libloaderapi::GetModuleHandleW(ptr::null()),
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
parent.unwrap_or(0),
pl_attribs.menu.unwrap_or(0),
GetModuleHandleW(ptr::null()),
&mut initdata as *mut _ as *mut _,
);
@ -945,7 +941,7 @@ where
panic::resume_unwind(panic_error)
}
if handle.is_null() {
if handle == 0 {
return Err(os_error!(io::Error::last_os_error()));
}
@ -958,30 +954,27 @@ unsafe fn register_window_class<T: 'static>(
window_icon: &Option<Icon>,
taskbar_icon: &Option<Icon>,
) -> Vec<u16> {
let class_name: Vec<_> = OsStr::new("Window Class")
.encode_wide()
.chain(Some(0).into_iter())
.collect();
let class_name = util::encode_wide("Window Class");
let h_icon = taskbar_icon
.as_ref()
.map(|icon| icon.inner.as_raw_handle())
.unwrap_or(ptr::null_mut());
.unwrap_or(0);
let h_icon_small = window_icon
.as_ref()
.map(|icon| icon.inner.as_raw_handle())
.unwrap_or(ptr::null_mut());
.unwrap_or(0);
let class = winuser::WNDCLASSEXW {
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC,
let class = WNDCLASSEXW {
cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
lpfnWndProc: Some(super::event_loop::public_window_callback::<T>),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
hInstance: GetModuleHandleW(ptr::null()),
hIcon: h_icon,
hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly
hbrBackground: ptr::null_mut(),
hCursor: 0, // must be null in order for cursor state to work properly
hbrBackground: 0,
lpszMenuName: ptr::null(),
lpszClassName: class_name.as_ptr(),
hIconSm: h_icon_small,
@ -991,7 +984,7 @@ unsafe fn register_window_class<T: 'static>(
// an error, and because errors here are detected during CreateWindowEx anyway.
// Also since there is no weird element in the struct, there is no reason for this
// call to fail.
winuser::RegisterClassExW(&class);
RegisterClassExW(&class);
class_name
}
@ -999,14 +992,14 @@ unsafe fn register_window_class<T: 'static>(
struct ComInitialized(*mut ());
impl Drop for ComInitialized {
fn drop(&mut self) {
unsafe { combaseapi::CoUninitialize() };
unsafe { CoUninitialize() };
}
}
thread_local! {
static COM_INITIALIZED: ComInitialized = {
unsafe {
combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_APARTMENTTHREADED);
CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED);
ComInitialized(ptr::null_mut())
}
};
@ -1033,17 +1026,17 @@ unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) {
let mut task_bar_list = task_bar_list_ptr.get();
if task_bar_list.is_null() {
use winapi::{shared::winerror::S_OK, Interface};
let hr = combaseapi::CoCreateInstance(
let hr = CoCreateInstance(
&CLSID_TaskbarList,
ptr::null_mut(),
combaseapi::CLSCTX_ALL,
&ITaskbarList2::uuidof(),
CLSCTX_ALL,
&IID_ITaskbarList2,
&mut task_bar_list as *mut _ as *mut _,
);
if hr != S_OK || (*task_bar_list).HrInit() != S_OK {
let hr_init = (*(*task_bar_list).lpVtbl).parent.HrInit;
if hr != S_OK || hr_init(task_bar_list.cast()) != S_OK {
// In some old windows, the taskbar object could not be created, we just ignore it
return;
}
@ -1051,7 +1044,8 @@ unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) {
}
task_bar_list = task_bar_list_ptr.get();
(*task_bar_list).MarkFullscreenWindow(handle, if fullscreen { 1 } else { 0 });
let mark_fullscreen_window = (*(*task_bar_list).lpVtbl).MarkFullscreenWindow;
mark_fullscreen_window(task_bar_list, handle, if fullscreen { 1 } else { 0 });
})
}
@ -1060,25 +1054,41 @@ unsafe fn force_window_active(handle: HWND) {
// This is a little hack which can "steal" the foreground window permission
// We only call this function in the window creation, so it should be fine.
// See : https://stackoverflow.com/questions/10740346/setforegroundwindow-only-working-while-visual-studio-is-open
let alt_sc = winuser::MapVirtualKeyW(winuser::VK_MENU as _, winuser::MAPVK_VK_TO_VSC);
let alt_sc = MapVirtualKeyW(VK_MENU as u32, MAPVK_VK_TO_VSC);
let mut inputs: [winuser::INPUT; 2] = mem::zeroed();
inputs[0].type_ = winuser::INPUT_KEYBOARD;
inputs[0].u.ki_mut().wVk = winuser::VK_LMENU as _;
inputs[0].u.ki_mut().wScan = alt_sc as _;
inputs[0].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY;
inputs[1].type_ = winuser::INPUT_KEYBOARD;
inputs[1].u.ki_mut().wVk = winuser::VK_LMENU as _;
inputs[1].u.ki_mut().wScan = alt_sc as _;
inputs[1].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY | winuser::KEYEVENTF_KEYUP;
let inputs = [
INPUT {
r#type: INPUT_KEYBOARD,
Anonymous: INPUT_0 {
ki: KEYBDINPUT {
wVk: VK_LMENU,
wScan: alt_sc as u16,
dwFlags: KEYEVENTF_EXTENDEDKEY,
dwExtraInfo: 0,
time: 0,
},
},
},
INPUT {
r#type: INPUT_KEYBOARD,
Anonymous: INPUT_0 {
ki: KEYBDINPUT {
wVk: VK_LMENU,
wScan: alt_sc as u16,
dwFlags: KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
dwExtraInfo: 0,
time: 0,
},
},
},
];
// Simulate a key press and release
winuser::SendInput(
inputs.len() as _,
inputs.as_mut_ptr(),
mem::size_of::<winuser::INPUT>() as _,
SendInput(
inputs.len() as u32,
inputs.as_ptr(),
mem::size_of::<INPUT>() as i32,
);
winuser::SetForegroundWindow(handle);
SetForegroundWindow(handle);
}

View file

@ -6,13 +6,20 @@ use crate::{
window::{CursorIcon, Fullscreen, Theme, WindowAttributes},
};
use parking_lot::MutexGuard;
use std::{io, ptr};
use winapi::{
shared::{
minwindef::DWORD,
windef::{HWND, RECT},
use std::io;
use windows_sys::Win32::{
Foundation::{HWND, RECT},
Graphics::Gdi::InvalidateRgn,
UI::WindowsAndMessaging::{
SendMessageW, SetWindowLongW, SetWindowPos, ShowWindow, GWL_EXSTYLE, GWL_STYLE,
HWND_NOTOPMOST, HWND_TOPMOST, SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED, SWP_NOACTIVATE,
SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE,
SW_SHOW, WINDOWPLACEMENT, WINDOW_EX_STYLE, WINDOW_STYLE, WS_BORDER, WS_CAPTION, WS_CHILD,
WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_LEFT,
WS_EX_NOREDIRECTIONBITMAP, WS_EX_TOPMOST, WS_EX_WINDOWEDGE, WS_MAXIMIZE, WS_MAXIMIZEBOX,
WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX,
WS_SYSMENU, WS_VISIBLE,
},
um::winuser,
};
/// Contains information about states and the window that the callback is going to use.
@ -39,7 +46,7 @@ pub struct WindowState {
#[derive(Clone)]
pub struct SavedWindow {
pub placement: winuser::WINDOWPLACEMENT,
pub placement: WINDOWPLACEMENT,
}
#[derive(Clone)]
@ -187,10 +194,8 @@ impl WindowFlags {
self
}
pub fn to_window_styles(self) -> (DWORD, DWORD) {
use winapi::um::winuser::*;
let (mut style, mut style_ex) = (0, 0);
pub fn to_window_styles(self) -> (WINDOW_STYLE, WINDOW_EX_STYLE) {
let (mut style, mut style_ex) = (WS_OVERLAPPED, WS_EX_LEFT);
if self.contains(WindowFlags::RESIZABLE) {
style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
@ -248,43 +253,40 @@ impl WindowFlags {
if diff.contains(WindowFlags::VISIBLE) {
unsafe {
winuser::ShowWindow(
ShowWindow(
window,
match new.contains(WindowFlags::VISIBLE) {
true => winuser::SW_SHOW,
false => winuser::SW_HIDE,
true => SW_SHOW,
false => SW_HIDE,
},
);
}
}
if diff.contains(WindowFlags::ALWAYS_ON_TOP) {
unsafe {
winuser::SetWindowPos(
SetWindowPos(
window,
match new.contains(WindowFlags::ALWAYS_ON_TOP) {
true => winuser::HWND_TOPMOST,
false => winuser::HWND_NOTOPMOST,
true => HWND_TOPMOST,
false => HWND_NOTOPMOST,
},
0,
0,
0,
0,
winuser::SWP_ASYNCWINDOWPOS
| winuser::SWP_NOMOVE
| winuser::SWP_NOSIZE
| winuser::SWP_NOACTIVATE,
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE,
);
winuser::InvalidateRgn(window, ptr::null_mut(), 0);
InvalidateRgn(window, 0, false.into());
}
}
if diff.contains(WindowFlags::MAXIMIZED) || new.contains(WindowFlags::MAXIMIZED) {
unsafe {
winuser::ShowWindow(
ShowWindow(
window,
match new.contains(WindowFlags::MAXIMIZED) {
true => winuser::SW_MAXIMIZE,
false => winuser::SW_RESTORE,
true => SW_MAXIMIZE,
false => SW_RESTORE,
},
);
}
@ -293,11 +295,11 @@ impl WindowFlags {
// Minimize operations should execute after maximize for proper window animations
if diff.contains(WindowFlags::MINIMIZED) {
unsafe {
winuser::ShowWindow(
ShowWindow(
window,
match new.contains(WindowFlags::MINIMIZED) {
true => winuser::SW_MINIMIZE,
false => winuser::SW_RESTORE,
true => SW_MINIMIZE,
false => SW_RESTORE,
},
);
}
@ -307,18 +309,15 @@ impl WindowFlags {
let (style, style_ex) = new.to_window_styles();
unsafe {
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
// This condition is necessary to avoid having an unrestorable window
if !new.contains(WindowFlags::MINIMIZED) {
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
SetWindowLongW(window, GWL_STYLE, style as i32);
SetWindowLongW(window, GWL_EXSTYLE, style_ex as i32);
}
let mut flags = winuser::SWP_NOZORDER
| winuser::SWP_NOMOVE
| winuser::SWP_NOSIZE
| winuser::SWP_FRAMECHANGED;
let mut flags = SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED;
// We generally don't want style changes here to affect window
// focus, but for fullscreen windows they must be activated
@ -326,12 +325,12 @@ impl WindowFlags {
if !new.contains(WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN)
&& !new.contains(WindowFlags::MARKER_BORDERLESS_FULLSCREEN)
{
flags |= winuser::SWP_NOACTIVATE;
flags |= SWP_NOACTIVATE;
}
// Refresh the window frame
winuser::SetWindowPos(window, ptr::null_mut(), 0, 0, 0, 0, flags);
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
SetWindowPos(window, 0, 0, 0, 0, 0, flags);
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
}
}
}