1#![forbid(unsafe_op_in_unsafe_fn)]
2
3use std::{marker::PhantomData, mem::size_of, num::NonZeroIsize};
4
5use raw_window_handle::{RawWindowHandle, Win32WindowHandle};
6use windows::{
7 core::*,
8 Win32::{Foundation::*, System::LibraryLoader::*, UI::WindowsAndMessaging::*},
9};
10
11pub struct Window<EH: EventHandler> {
12 hwnd: HWND,
13 phantom_data: PhantomData<*const EH>,
14}
15
16pub trait EventHandler {
17 fn on_paint(&mut self);
18}
19
20impl<EH: EventHandler> Window<EH> {
21 pub fn new(size: (u32, u32)) -> Result<Self> {
22 unsafe {
23 RegisterClassExW(&WNDCLASSEXW {
24 cbSize: size_of::<WNDCLASSEXW>() as u32,
25 style: CS_HREDRAW | CS_VREDRAW,
26 lpfnWndProc: Some(wndproc::<EH>),
27 hInstance: GetModuleHandleW(None)?.into(),
28 hCursor: LoadCursorW(None, IDC_ARROW)?,
29 lpszClassName: w!("winwin-rs-class-name"),
30 ..Default::default()
31 });
32
33 let mut rect = RECT {
34 left: 0,
35 top: 0,
36 right: size.0 as i32,
37 bottom: size.1 as i32,
38 };
39 AdjustWindowRect(&mut rect, WS_OVERLAPPEDWINDOW, false)?;
40
41 let hwnd = CreateWindowExW(
42 WINDOW_EX_STYLE::default(),
43 w!("winwin-rs-class-name"),
44 w!("Winwin Window"),
45 WS_OVERLAPPEDWINDOW,
46 CW_USEDEFAULT,
47 CW_USEDEFAULT,
48 rect.right - rect.left,
49 rect.bottom - rect.top,
50 None,
51 None,
52 GetModuleHandleW(None)?,
53 None,
54 );
55
56 Ok(Self {
57 hwnd,
58 phantom_data: PhantomData,
59 })
60 }
61 }
62
63 pub fn raw_window_handle(&self) -> RawWindowHandle {
64 RawWindowHandle::Win32(Win32WindowHandle::new(
65 NonZeroIsize::new(self.hwnd.0).unwrap(),
66 ))
67 }
68
69 pub fn run(self, mut event_handler: EH) {
70 unsafe {
71 SetWindowLongPtrW(
72 self.hwnd,
73 GWLP_USERDATA,
74 &mut event_handler as *mut EH as isize,
75 );
76
77 let _ = ShowWindow(self.hwnd, SW_SHOW);
78
79 let mut msg = MSG::default();
80 while msg.message != WM_QUIT {
81 if PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).into() {
82 let _ = TranslateMessage(&msg);
83 DispatchMessageW(&msg);
84 }
85 }
86 }
87 }
88}
89
90unsafe extern "system" fn wndproc<EH: EventHandler>(
91 hwnd: HWND,
92 msg: u32,
93 wparam: WPARAM,
94 lparam: LPARAM,
95) -> LRESULT {
96 unsafe {
97 if msg == WM_DESTROY {
98 PostQuitMessage(0);
99 return LRESULT(0);
100 }
101
102 if let Some(mut ptr) =
103 std::ptr::NonNull::<EH>::new(GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *mut EH)
104 {
105 match msg {
106 WM_PAINT => {
107 ptr.as_mut().on_paint();
108 return LRESULT(0);
109 }
110 _ => {}
111 }
112 }
113
114 return DefWindowProcW(hwnd, msg, wparam, lparam);
115 }
116}