Adopt windows-sys (#2057)
This commit is contained in:
parent
78e5a395da
commit
b222dde835
17 changed files with 1424 additions and 1239 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue