use std::cell::RefCell;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::backend::application as backend;
use crate::clipboard::Clipboard;
use crate::error::Error;
use crate::util;
pub trait AppHandler {
#[allow(unused_variables)]
fn command(&mut self, id: u32) {}
}
#[derive(Clone)]
pub struct Application {
pub(crate) backend_app: backend::Application,
state: Rc<RefCell<State>>,
}
struct State {
running: bool,
}
static APPLICATION_CREATED: AtomicBool = AtomicBool::new(false);
thread_local! {
static GLOBAL_APP: RefCell<Option<Application>> = RefCell::new(None);
}
impl Application {
pub fn new() -> Result<Application, Error> {
APPLICATION_CREATED
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.map_err(|_| Error::ApplicationAlreadyExists)?;
util::claim_main_thread();
let backend_app = backend::Application::new()?;
let state = Rc::new(RefCell::new(State { running: false }));
let app = Application { backend_app, state };
GLOBAL_APP.with(|global_app| {
*global_app.borrow_mut() = Some(app.clone());
});
Ok(app)
}
#[inline]
pub fn global() -> Application {
Application::try_global().expect("There is no globally active Application")
}
pub fn try_global() -> Option<Application> {
util::assert_main_thread_or_main_unclaimed();
GLOBAL_APP.with(|global_app| global_app.borrow().clone())
}
pub fn run(self, handler: Option<Box<dyn AppHandler>>) {
if let Ok(mut state) = self.state.try_borrow_mut() {
if state.running {
panic!("Application is already running");
}
state.running = true;
} else {
panic!("Application state already borrowed");
}
self.backend_app.run(handler);
GLOBAL_APP.with(|global_app| {
*global_app.borrow_mut() = None;
});
util::release_main_thread();
APPLICATION_CREATED
.compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)
.expect("Application marked as not created while still running.");
}
pub fn quit(&self) {
self.backend_app.quit()
}
pub fn clipboard(&self) -> Clipboard {
self.backend_app.clipboard().into()
}
pub fn get_locale() -> String {
backend::Application::get_locale()
}
}