use crate::wrappers::win32::Rect;
use crate::PhySize;
use std::marker::PhantomData;
use std::num::NonZeroUsize;
use std::ptr::{null_mut, NonNull};
use windows::Win32::System::Ole::IDropTarget;
use windows_core::{Error, Interface, InterfaceRef, Result, HRESULT};
use windows_sys::Win32::Foundation::{SetLastError, HWND, S_OK};
use windows_sys::Win32::System::Ole::{RegisterDragDrop, RevokeDragDrop};
use windows_sys::Win32::UI::HiDpi::GetDpiForWindow;
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
GetFocus, ReleaseCapture, SetCapture, SetFocus, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{
DestroyWindow, GetWindowLongPtrW, SetTimer, SetWindowLongPtrW, SetWindowPos, ShowWindow,
GWLP_USERDATA, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOZORDER, SW_SHOW,
};
#[derive(Copy, Clone)]
pub struct HWnd<'a>(HWND, PhantomData<&'a ()>);
impl HWnd<'_> {
pub unsafe fn from_raw(hwnd: HWND) -> Self {
Self(hwnd, PhantomData)
}
pub fn as_raw(&self) -> HWND {
self.0
}
pub fn get_userdata_ptr<T>(&self) -> Option<NonNull<T>> {
let ptr = unsafe { GetWindowLongPtrW(self.0, GWLP_USERDATA) };
NonNull::new(ptr as *mut T)
}
pub fn set_userdata_ptr<T>(&self, data: *const T) -> Result<()> {
unsafe { SetLastError(0) };
let previous = unsafe { SetWindowLongPtrW(self.0, GWLP_USERDATA, data as isize) };
if previous != 0 {
return Ok(());
}
let error = Error::from_win32();
if error.code() == HRESULT(0) {
return Ok(());
}
Err(error)
}
pub fn get_dpi(&self) -> Result<u32> {
match unsafe { GetDpiForWindow(self.0) } {
0 => Err(Error::from_win32()),
dpi => Ok(dpi),
}
}
pub fn register_drag_drop(&self, drop_target: InterfaceRef<IDropTarget>) -> Result<()> {
let result = unsafe { RegisterDragDrop(self.0, drop_target.as_raw()) };
match result {
S_OK => Ok(()),
e => Err(Error::new(HRESULT(e), "RegisterDragDrop failed")),
}
}
pub fn revoke_drag_drop(&self) -> Result<()> {
let result = unsafe { RevokeDragDrop(self.0) };
match result {
S_OK => Ok(()),
e => Err(Error::new(HRESULT(e), "RegisterDragDrop failed")),
}
}
pub fn resize_nc_and_activate(&self, size: PhySize) -> Result<()> {
let result = unsafe {
SetWindowPos(
self.0,
null_mut(), 0, 0, size.width.try_into().unwrap_or(i32::MAX),
size.height.try_into().unwrap_or(i32::MAX),
SWP_NOZORDER | SWP_NOMOVE,
)
};
if result == 0 {
return Err(Error::from_win32());
}
Ok(())
}
pub fn resize_and_activate(&self, client_size: PhySize, style: u32) -> Result<()> {
let rect = Rect::from(client_size).client_area_to_nc_area(style)?;
self.resize_nc_and_activate(rect.size())
}
pub fn show_and_activate(&self) -> bool {
let result = unsafe { ShowWindow(self.0, SW_SHOW) };
result != 0
}
pub fn set_nc_rect(&self, nc_rect: Rect) -> Result<()> {
let size = nc_rect.size();
let result = unsafe {
SetWindowPos(
self.0,
null_mut(), nc_rect.0.left,
nc_rect.0.top,
size.width.try_into().unwrap_or(i32::MAX),
size.height.try_into().unwrap_or(i32::MAX),
SWP_NOZORDER | SWP_NOACTIVATE,
)
};
if result == 0 {
return Err(Error::from_win32());
}
Ok(())
}
pub fn set_timer(&self, timer_id: NonZeroUsize, elapse: u32) -> Result<()> {
let result = unsafe { SetTimer(self.0, timer_id.get(), elapse, None) };
if result == 0 {
return Err(Error::from_win32());
}
Ok(())
}
pub fn set_focus(&self) -> Result<()> {
let previous = unsafe { SetFocus(self.0) };
if !previous.is_null() {
return Ok(());
}
let error = Error::from_win32();
if error.code() == HRESULT(0) {
return Ok(());
}
Err(error)
}
pub fn destroy(&self) -> Result<()> {
let result = unsafe { DestroyWindow(self.0) };
if result == 0 {
return Err(Error::from_win32());
}
Ok(())
}
pub fn get_focused_window() -> HWND {
unsafe { GetFocus() }
}
pub fn set_capture(&self) {
unsafe { SetCapture(self.0) };
}
pub fn release_capture() {
unsafe { ReleaseCapture() };
}
pub fn start_cursor_leave_tracking(&self) -> Result<()> {
let mut track = TRACKMOUSEEVENT {
cbSize: size_of::<TRACKMOUSEEVENT>() as u32,
dwFlags: TME_LEAVE,
dwHoverTime: 0,
hwndTrack: self.0,
};
match unsafe { TrackMouseEvent(&mut track) } {
0 => Err(Error::from_win32()),
_ => Ok(()),
}
}
}