winwin/
lib.rs

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}