use crate::error::{Error, Result};
use once_cell::sync::Lazy;
use parking_lot::RwLock;
use std::sync::Arc;
use windows::Win32::{
Foundation::*,
UI::WindowsAndMessaging::*,
};
static APP_INSTANCE: Lazy<RwLock<Option<Arc<ApplicationInner>>>> = Lazy::new(|| RwLock::new(None));
#[derive(Clone)]
pub struct Application {
inner: Arc<ApplicationInner>,
}
struct ApplicationInner {
exit_code: RwLock<i32>,
should_exit: RwLock<bool>,
}
impl Application {
pub fn new() -> Result<Self> {
let mut app = APP_INSTANCE.write();
if app.is_some() {
return Err(Error::application("Application already created"));
}
let inner = Arc::new(ApplicationInner {
exit_code: RwLock::new(0),
should_exit: RwLock::new(false),
});
*app = Some(inner.clone());
Ok(Application { inner })
}
pub fn current() -> Option<Self> {
APP_INSTANCE
.read()
.as_ref()
.map(|inner| Application {
inner: inner.clone(),
})
}
pub fn run(&self) -> Result<()> {
unsafe {
let mut msg = MSG::default();
while GetMessageW(&mut msg, HWND(std::ptr::null_mut()), 0, 0).as_bool() {
if *self.inner.should_exit.read() {
break;
}
let _ = TranslateMessage(&msg);
let _ = DispatchMessageW(&msg);
}
Ok(())
}
}
pub fn exit_with_code(&self, code: i32) {
*self.inner.exit_code.write() = code;
*self.inner.should_exit.write() = true;
unsafe {
PostQuitMessage(code);
}
}
pub fn exit(&self) {
self.exit_with_code(0);
}
pub fn exit_code(&self) -> i32 {
*self.inner.exit_code.read()
}
pub fn should_exit(&self) -> bool {
*self.inner.should_exit.read()
}
}
impl Default for Application {
fn default() -> Self {
Self::new().expect("Failed to create application")
}
}