use crate::interop::unmanaged_methods::{
create_window_ex, def_window_proc, destroy_window, get_last_error, hwnd_to_isize, register_class_ex, WindowStyles,
WindowsMessage, CW_USEDEFAULT,
};
use crate::wnd_proc_guard;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
pub type SimpleWndProc = Rc<dyn Fn(isize, u32, usize, isize) -> isize>;
ferroui_base::ferro_thread_local! {
static CLASS_ATOM: Cell<u16> = const { Cell::new(0) };
static INSTANCES: RefCell<HashMap<isize, Option<SimpleWndProc>>> = RefCell::new(HashMap::new());
static CREATING: RefCell<Option<Option<SimpleWndProc>>> = const { RefCell::new(None) };
}
pub struct SimpleWindow {
handle: Cell<isize>,
}
impl SimpleWindow {
fn static_constructor() {
let class_name = format!("FerroSimpleWindow-{:?}-{}", std::thread::current().id(), std::process::id());
CLASS_ATOM.set(register_class_ex(&class_name, 0, wnd_proc, 0));
}
fn class_atom() -> u16 {
if CLASS_ATOM.get() == 0 {
Self::static_constructor();
}
CLASS_ATOM.get()
}
pub fn new(wnd_proc: Option<SimpleWndProc>) -> SimpleWindow {
CREATING.with(|creating| *creating.borrow_mut() = Some(wnd_proc));
let hwnd = create_window_ex(
0,
Self::class_atom(),
WindowStyles::WS_OVERLAPPEDWINDOW.bits(),
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
);
CREATING.with(|creating| *creating.borrow_mut() = None);
wnd_proc_guard::resume_pending();
if hwnd == 0 {
panic!("The window could not be created (error code {})", get_last_error());
}
SimpleWindow { handle: Cell::new(hwnd) }
}
pub fn handle(&self) -> isize {
self.handle.get()
}
#[allow(dead_code)] pub fn dispose(&self) {
destroy_window(self.handle.get());
self.handle.set(0);
}
}
unsafe extern "system" fn wnd_proc(
hwnd: windows_sys::Win32::Foundation::HWND,
msg: u32,
w_param: usize,
l_param: isize,
) -> isize {
let hwnd = hwnd_to_isize(hwnd);
let handled = wnd_proc_guard::guard(None, || {
let known = INSTANCES.with(|instances| instances.borrow().contains_key(&hwnd));
if !known {
let creating = CREATING.with(|creating| creating.borrow_mut().take());
if let Some(window) = creating {
INSTANCES.with(|instances| instances.borrow_mut().insert(hwnd, window));
}
}
let window = INSTANCES.with(|instances| instances.borrow().get(&hwnd).cloned());
if msg == WindowsMessage::WM_DESTROY {
INSTANCES.with(|instances| instances.borrow_mut().remove(&hwnd));
}
window.flatten().map(|wnd_proc| wnd_proc(hwnd, msg, w_param, l_param))
});
match handled {
Some(result) => result,
None => def_window_proc(hwnd, msg, w_param, l_param),
}
}