use crate::platform::win::keyboard::KeyboardState;
use crate::platform::PlatformHandle;
use crate::utils::SizingStrategy;
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::WindowSettings;
use crate::{MouseCursor, WindowSize};
use dpi::{PhysicalSize, Size};
use raw_window_handle::{DisplayHandle, Win32WindowHandle};
use std::cell::{Cell, Ref, RefCell};
use std::num::NonZeroIsize;
use std::rc::Rc;
use windows_sys::Win32::UI::WindowsAndMessaging::PostMessageW;
pub(crate) struct WindowState {
pub hwnd: HWnd,
pub keyboard_state: RefCell<KeyboardState>,
pub mouse_button_counter: Cell<usize>,
pub mouse_was_outside_window: Cell<bool>,
pub cursor_icon: Cell<MouseCursor>,
pub user32: ExtendedUser32,
pub shared: Rc<WindowSharedState>,
#[cfg(feature = "opengl")]
pub gl_context: std::cell::OnceCell<super::gl::GlContext>,
}
impl WindowState {
pub fn new(hwnd: HWnd, user32: ExtendedUser32, shared: Rc<WindowSharedState>) -> Self {
Self {
hwnd,
keyboard_state: RefCell::new(KeyboardState::new()),
mouse_button_counter: Cell::new(0),
mouse_was_outside_window: true.into(),
cursor_icon: Cell::new(MouseCursor::Default),
user32,
shared,
#[cfg(feature = "opengl")]
gl_context: std::cell::OnceCell::new(),
}
}
pub fn size(&self) -> WindowSize {
self.shared.size()
}
pub fn scale_factor(&self) -> f64 {
self.shared.scale_factor()
}
pub(crate) fn keyboard_state(&self) -> Ref<'_, KeyboardState> {
self.keyboard_state.borrow()
}
pub fn request_close(&self) {
unsafe {
PostMessageW(
self.hwnd.as_raw(),
crate::platform::win::window::BV_WINDOW_MUST_CLOSE,
0,
0,
);
}
}
pub fn has_focus(&self) -> bool {
HWnd::get_focused_window() == self.hwnd.as_raw()
}
pub fn focus(&self) -> Result<(), super::Error> {
self.hwnd.set_focus()?;
Ok(())
}
pub fn resize(&self, size: Size) -> Result<(), super::Error> {
let dpi = self.shared.current_dpi.get();
let new_size = size.to_physical(self.shared.scale_factor());
self.hwnd.resize_and_activate(new_size, dpi, &self.user32)?;
Ok(())
}
pub fn set_mouse_cursor(&self, mouse_cursor: MouseCursor) -> Result<(), super::Error> {
self.cursor_icon.set(mouse_cursor);
if let Ok(cursor) = SystemCursor::load(mouse_cursor) {
cursor.set()
}
Ok(())
}
#[cfg(feature = "opengl")]
pub fn gl_context(&self) -> Option<crate::gl::GlContext> {
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_raw() 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_raw() as _) else { unreachable!() };
PlatformHandle { hwnd }
}
}
pub struct WindowSharedState {
pub parented: Cell<bool>,
pub is_alive: Cell<bool>,
pub current_size: Cell<PhysicalSize<u32>>,
pub current_dpi: Cell<Option<Dpi>>, pub fallback_scale_factor: Cell<Option<f64>>,
pub resize_host_originated: Cell<bool>,
pub destroy_host_originated: Cell<bool>,
pub user32: ExtendedUser32,
pub sizing_strategy: SizingStrategy,
}
impl WindowSharedState {
pub fn new(user32: ExtendedUser32, settings: &WindowSettings) -> Rc<Self> {
Self {
parented: (settings.parent.is_some() || settings.wait_for_parent).into(),
is_alive: true.into(),
current_dpi: None.into(),
current_size: settings.size.to_physical(1.0).into(),
fallback_scale_factor: settings.fallback_scale_factor.into(),
resize_host_originated: false.into(),
destroy_host_originated: false.into(),
sizing_strategy: SizingStrategy::from_settings(settings),
user32,
}
.into()
}
pub fn size(&self) -> WindowSize {
WindowSize::from_physical(self.current_size.get(), self.scale_factor())
}
pub fn scale_factor(&self) -> f64 {
if let Some(dpi) = self.current_dpi.get() {
dpi.scale_factor()
} else {
self.fallback_scale_factor.get().unwrap_or(1.0)
}
}
pub fn originate_host_resize(&self) -> impl Drop + use<'_> {
self.resize_host_originated.set(true);
Guard(&self.resize_host_originated)
}
pub fn originate_host_destroy(&self) -> impl Drop + use<'_> {
self.destroy_host_originated.set(true);
Guard(&self.destroy_host_originated)
}
}
struct Guard<'a>(&'a Cell<bool>);
impl<'a> Drop for Guard<'a> {
fn drop(&mut self) {
self.0.set(false);
}
}