use std::rc::Rc;
use windows::Win32::Foundation::{ERROR_CLASS_ALREADY_EXISTS, GetLastError, HINSTANCE, HWND};
use windows::Win32::UI::WindowsAndMessaging::{
CreateWindowExW, DestroyWindow, GWLP_USERDATA, GetWindowLongPtrW, IsWindow, LoadCursorW,
RegisterClassExW, SetWindowLongPtrW, WNDCLASSEXW, WNDPROC, WS_EX_TOOLWINDOW, WS_POPUP,
};
use windows::core::PCWSTR;
use crate::error::{Call, Error, Result};
pub(crate) fn register_class(
name: PCWSTR,
proc: WNDPROC,
hinstance: HINSTANCE,
cursor: PCWSTR,
) -> Result<()> {
unsafe {
let class = WNDCLASSEXW {
cbSize: size_of::<WNDCLASSEXW>() as u32,
lpfnWndProc: proc,
hInstance: hinstance,
hCursor: LoadCursorW(None, cursor).call("LoadCursorW")?,
lpszClassName: name,
..Default::default()
};
if RegisterClassExW(&class) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS {
return Err(Error::last("RegisterClassExW"));
}
}
Ok(())
}
pub(crate) fn create_hidden(class: PCWSTR, hinstance: HINSTANCE) -> Result<HWND> {
unsafe {
CreateWindowExW(
WS_EX_TOOLWINDOW,
class,
class,
WS_POPUP,
0,
0,
0,
0,
None,
None,
Some(hinstance),
None,
)
.call("CreateWindowExW")
}
}
pub(crate) fn destroy(hwnd: HWND) {
unsafe {
if IsWindow(Some(hwnd)).as_bool() {
let _ = DestroyWindow(hwnd);
}
}
}
pub(crate) unsafe fn state_of<'a, T>(hwnd: HWND) -> Option<&'a T> {
unsafe { (GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *const T).as_ref() }
}
pub(crate) struct Window<T> {
hwnd: HWND,
state: Rc<T>,
}
impl<T> Window<T> {
pub(crate) fn attach(hwnd: HWND, state: Rc<T>) -> Self {
let count = Rc::into_raw(Rc::clone(&state));
unsafe {
SetWindowLongPtrW(hwnd, GWLP_USERDATA, count as isize);
}
Self { hwnd, state }
}
pub(crate) fn hwnd(&self) -> HWND {
self.hwnd
}
pub(crate) fn state(&self) -> &T {
&self.state
}
pub(crate) fn share(&self) -> Rc<T> {
Rc::clone(&self.state)
}
}
impl<T> Drop for Window<T> {
fn drop(&mut self) {
destroy(self.hwnd);
unsafe {
drop(Rc::from_raw(Rc::as_ptr(&self.state)));
}
}
}