use crate::platform::win::keyboard::KeyboardState;
use crate::platform::PlatformHandle;
use crate::wrappers::win32::cursor::SystemCursor;
use crate::wrappers::win32::h_instance::HInstance;
use crate::wrappers::win32::window::HWnd;
use crate::wrappers::win32::{Dpi, ExtendedUser32};
use crate::{Event, EventStatus, MouseCursor, WindowHandler, WindowScalePolicy, WindowSize};
use dpi::{PhysicalSize, Size};
use raw_window_handle::{DisplayHandle, Win32WindowHandle};
use std::cell::{Cell, OnceCell, Ref, RefCell};
use std::num::NonZeroIsize;
use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::UI::WindowsAndMessaging::PostMessageW;
pub(crate) struct WindowState {
pub hwnd: HWND,
pub current_size: Cell<PhysicalSize<u32>>,
pub current_dpi: Cell<Dpi>, pub keyboard_state: RefCell<KeyboardState>,
pub mouse_button_counter: Cell<usize>,
pub mouse_was_outside_window: Cell<bool>,
pub cursor_icon: Cell<MouseCursor>,
pub handler: OnceCell<Box<dyn WindowHandler>>,
pub scale_policy: WindowScalePolicy,
pub user32: ExtendedUser32,
#[cfg(feature = "opengl")]
pub gl_context: OnceCell<super::gl::GlContext>,
}
impl WindowState {
pub fn new(
hwnd: HWND, current_size: PhysicalSize<u32>, scale_policy: WindowScalePolicy,
user32: ExtendedUser32,
) -> Self {
Self {
hwnd,
current_dpi: Dpi::default().into(),
current_size: current_size.into(),
keyboard_state: RefCell::new(KeyboardState::new()),
mouse_button_counter: Cell::new(0),
mouse_was_outside_window: true.into(),
cursor_icon: Cell::new(MouseCursor::Default),
handler: OnceCell::new(),
scale_policy,
user32,
#[cfg(feature = "opengl")]
gl_context: OnceCell::new(),
}
}
pub(crate) fn handle_on_frame(&self) {
let Some(handler) = self.handler.get() else { return };
handler.on_frame()
}
pub(crate) fn handle_event(&self, event: Event) -> EventStatus {
let Some(handler) = self.handler.get() else {
return EventStatus::Ignored;
};
handler.on_event(event)
}
pub fn size(&self) -> WindowSize {
WindowSize::from_physical(self.current_size.get(), self.scale_factor())
}
pub fn scale_factor(&self) -> f64 {
match self.scale_policy {
WindowScalePolicy::ScaleFactor(scale) => scale,
WindowScalePolicy::SystemScaleFactor => self.current_dpi.get().scale_factor(),
}
}
pub(crate) fn keyboard_state(&self) -> Ref<'_, KeyboardState> {
self.keyboard_state.borrow()
}
pub fn send_resized(&self) {
if let Some(handler) = self.handler.get() {
handler
.resized(WindowSize::from_physical(self.current_size.get(), self.scale_factor()));
}
}
pub fn request_close(&self) {
unsafe {
PostMessageW(self.hwnd, crate::platform::win::window::BV_WINDOW_MUST_CLOSE, 0, 0);
}
}
pub fn has_focus(&self) -> bool {
HWnd::get_focused_window() == self.hwnd
}
pub fn focus(&self) {
self.hwnd().set_focus().unwrap()
}
fn hwnd(&self) -> HWnd {
unsafe { HWnd::from_raw(self.hwnd) }
}
pub fn resize(&self, size: Size) {
let dpi = self.current_dpi.get();
let new_size = size.to_physical(dpi.scale_factor());
self.hwnd().resize_and_activate(new_size, dpi, &self.user32).unwrap();
}
pub fn set_mouse_cursor(&self, mouse_cursor: MouseCursor) {
self.cursor_icon.set(mouse_cursor);
if let Ok(cursor) = SystemCursor::load(mouse_cursor) {
cursor.set()
}
}
#[cfg(feature = "opengl")]
pub fn gl_context(&self) -> Option<crate::gl::GlContext> {
use std::rc::Rc;
Some(crate::gl::GlContext::new(Rc::clone(self.gl_context.get()?)))
}
pub fn window_handle(&self) -> Option<raw_window_handle::WindowHandle<'_>> {
let Some(hwnd) = NonZeroIsize::new(self.hwnd as _) else { unreachable!() };
let mut handle = Win32WindowHandle::new(hwnd);
handle.hinstance = Some(HInstance::get_from_dll().addr());
Some(unsafe { raw_window_handle::WindowHandle::borrow_raw(handle.into()) })
}
pub fn display_handle(&self) -> DisplayHandle<'_> {
DisplayHandle::windows()
}
pub fn platform_handle(&self) -> PlatformHandle {
let Some(hwnd) = NonZeroIsize::new(self.hwnd as _) else { unreachable!() };
PlatformHandle { hwnd }
}
}