use std::cell::UnsafeCell;
use crate::co;
use crate::decl::*;
use crate::gui::{privs::*, *};
use crate::msg::*;
use crate::prelude::*;
struct ThreadPack {
func: Box<dyn FnOnce() -> AnyResult<()>>,
}
pub(in crate::gui) struct BaseWnd {
hwnd: UnsafeCell<HWND>,
wnd_ty: WndTy,
layout: Layout,
before_events: BaseWndEvents,
user_events: BaseWndEvents,
after_events: BaseWndEvents,
}
impl BaseWnd {
const WM_UI_THREAD: co::WM = unsafe { co::WM::from_raw(co::WM::APP.raw() + 0x3fff) };
#[must_use]
pub(in crate::gui) fn new(wnd_ty: WndTy) -> Self {
let new_self = Self {
hwnd: UnsafeCell::new(HWND::NULL),
wnd_ty,
layout: Layout::new(),
before_events: BaseWndEvents::new(wnd_ty),
user_events: BaseWndEvents::new(wnd_ty),
after_events: BaseWndEvents::new(wnd_ty),
};
new_self.default_message_handlers();
new_self
}
#[must_use]
pub(in crate::gui) const fn wnd_ty(&self) -> WndTy {
self.wnd_ty
}
#[must_use]
pub(in crate::gui) const fn hwnd(&self) -> &HWND {
unsafe { &*self.hwnd.get() }
}
pub(in crate::gui) fn set_hwnd(&self, hwnd: HWND) {
*unsafe { &mut *self.hwnd.get() } = hwnd;
}
#[must_use]
pub(in crate::gui) fn before_on(&self) -> &BaseWndEvents {
&self.before_events
}
#[must_use]
pub(in crate::gui) fn on(&self) -> &BaseWndEvents {
if *self.hwnd() != HWND::NULL {
panic!("Cannot add event after window creation.");
}
&self.user_events }
#[must_use]
pub(in crate::gui) fn after_on(&self) -> &BaseWndEvents {
&self.after_events
}
pub(in crate::gui) fn process_msgs(&self, p: WndMsg) -> AnyResult<(bool, Option<isize>, bool)> {
Ok((
self.before_events.process_all_messages(p)?,
self.user_events.process_last_message(p).transpose()?,
self.after_events.process_all_messages(p)?,
))
}
pub(in crate::gui) fn clear_messages(&self) {
self.before_events.clear();
self.user_events.clear();
self.after_events.clear();
}
pub(in crate::gui) fn add_to_layout(&self, hchild: &HWND, resize_behavior: (Horz, Vert)) {
self.layout.add_child(&self.hwnd(), hchild, resize_behavior);
}
pub(in crate::gui) fn spawn_thread<F>(&self, func: F)
where
F: FnOnce() -> AnyResult<()> + Send + 'static,
{
let hwnd = unsafe { self.hwnd().raw_copy() };
std::thread::spawn(move || {
func().unwrap_or_else(|err| {
let pack = Box::new(ThreadPack { func: Box::new(|| Err(err)) });
let ptr_pack = Box::into_raw(pack);
hwnd.GetAncestor(co::GA::ROOTOWNER).map(|hwnd| unsafe {
hwnd.SendMessage(WndMsg {
msg_id: Self::WM_UI_THREAD,
wparam: Self::WM_UI_THREAD.raw() as _,
lparam: ptr_pack as _, });
});
});
});
}
pub(in crate::gui) fn run_ui_thread<F>(&self, func: F)
where
F: FnOnce() -> AnyResult<()> + Send + 'static,
{
let pack = Box::new(ThreadPack { func: Box::new(func) });
let ptr_pack = Box::into_raw(pack);
self.hwnd()
.GetAncestor(co::GA::ROOTOWNER)
.map(|hwnd| unsafe {
hwnd.SendMessage(WndMsg {
msg_id: Self::WM_UI_THREAD,
wparam: Self::WM_UI_THREAD.raw() as _,
lparam: ptr_pack as _, });
});
}
pub(in crate::gui) fn default_message_handlers(&self) {
let layout = self.layout.clone();
self.before_events.wm_size(move |p| {
layout.rearrange(p);
Ok(())
});
self.before_events.wm(Self::WM_UI_THREAD, |p| {
if unsafe { co::WM::from_raw(p.wparam as _) } == Self::WM_UI_THREAD {
let ptr_pack = p.lparam as *mut ThreadPack; let pack = unsafe { Box::from_raw(ptr_pack) };
let func = pack.func;
func().unwrap_or_else(|err| quit_error::post_quit_error(p, err));
}
Ok(0) });
}
pub(in crate::gui) fn run_main_loop(
haccel: Option<&HACCEL>,
process_dlg_msgs: bool,
) -> AnyResult<i32> {
let mut msg = MSG::default();
loop {
if !GetMessage(&mut msg, None, 0, 0).expect(DONTFAIL) {
return match {
let mut msg_error = quit_error::QUIT_ERROR.lock().unwrap();
msg_error.take()
} {
Some(msg_err) => Err(msg_err.into()), None => Ok(msg.wParam as _), };
}
let hwnd_top_level = msg
.hwnd
.GetAncestor(co::GA::ROOT)
.unwrap_or(unsafe { msg.hwnd.raw_copy() });
if let Some(haccel) = haccel {
if hwnd_top_level
.TranslateAccelerator(haccel, &mut msg)
.is_ok()
{
continue; }
}
if process_dlg_msgs && hwnd_top_level.IsDialogMessage(&mut msg) {
continue;
}
TranslateMessage(&msg);
unsafe {
DispatchMessage(&msg);
}
}
}
pub(in crate::gui) fn run_modal_loop(&self, process_dlg_msgs: bool) -> AnyResult<i32> {
let mut msg = MSG::default();
loop {
if !GetMessage(&mut msg, None, 0, 0).expect(DONTFAIL) {
PostQuitMessage(msg.wParam as _);
return Ok(0); }
if *self.hwnd() == HWND::NULL || !self.hwnd().IsWindow() {
return Ok(0); }
let hwnd_top_level = msg
.hwnd
.GetAncestor(co::GA::ROOT)
.unwrap_or(unsafe { msg.hwnd.raw_copy() });
if process_dlg_msgs && hwnd_top_level.IsDialogMessage(&mut msg) {
if *self.hwnd() == HWND::NULL {
return Ok(0); } else {
continue;
}
}
TranslateMessage(&msg);
unsafe {
DispatchMessage(&msg);
}
if *self.hwnd() == HWND::NULL || !self.hwnd().IsWindow() {
return Ok(0); }
}
}
}