use std::cell::RefCell;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::dev_plugin::DevPlugin;
use platform_core::{EventHandler, SurfaceId};
use platform_desktop::{DesktopPathsProvider, WinitPlatform, WinitWindow, request_dynamic_surface};
use services_core::AppPathsProvider;
use ui_core::Surface;
use crate::app::App;
use crate::app_config::AppConfig;
use crate::surface::{SurfaceControl, SurfaceToken};
fn run_desktop_with_plugin<A: App, D: DevPlugin>(config: AppConfig, app: A, app_name: &str) {
let paths: Arc<dyn AppPathsProvider> = Arc::new(DesktopPathsProvider);
platform_desktop::DesktopFileDialogs::install();
platform_desktop::DesktopClipboard::install();
let platform = match WinitPlatform::try_new() {
Ok(p) => p,
Err(e) => {
tracing::error!("Failed to create event loop: {e}");
std::process::exit(1);
}
};
let config = super::dev_window::with_dev_overrides(config);
if let Err(e) = super::run_with_platform::<_, A, D>(platform, config, paths, app, app_name) {
tracing::error!("Event loop exited with error: {e}");
std::process::exit(1);
}
}
pub fn run_app_with_name<A: App>(config: AppConfig, app: A, app_name: &str) {
#[cfg(feature = "dev")]
{
if std::env::var("TELAR_DEVTOOLS").as_deref() == Ok("0") {
run_desktop_with_plugin::<A, ()>(config, app, app_name);
} else {
run_desktop_with_plugin::<A, crate::dev_tools::DevTools>(config, app, app_name);
}
}
#[cfg(not(feature = "dev"))]
run_desktop_with_plugin::<A, ()>(config, app, app_name);
}
struct WinitSurfaceControl {
close: Arc<AtomicBool>,
}
impl SurfaceControl for WinitSurfaceControl {
fn close(&self) {
self.close.store(true, Ordering::Relaxed);
}
fn is_closing(&self) -> bool {
self.close.load(Ordering::Relaxed)
}
}
pub fn open_window<A: App>(app: A) -> SurfaceToken {
let window_config = app.window_config().unwrap_or_default();
let paths: Arc<dyn AppPathsProvider> = Arc::new(DesktopPathsProvider);
platform_desktop::DesktopFileDialogs::install();
platform_desktop::DesktopClipboard::install();
let prefs = crate::prefs::UserPrefs::load("telar-window", paths.as_ref());
let backend = prefs
.backend
.unwrap_or_else(crate::config::compile_time_backend);
let mut handler = super::handler::build_app_handler::<WinitWindow, ()>(
Box::new(app),
paths,
Vec::new(),
Vec::new(),
backend,
prefs,
"telar-window".to_string(),
super::host::SurfaceRenderer::builtin(),
);
handler.surface = Some(Surface::new());
let boxed: Box<dyn EventHandler<WinitWindow>> = Box::new(handler);
let close = request_dynamic_surface(window_config, boxed);
SurfaceToken::new(Box::new(WinitSurfaceControl { close }))
}
pub fn run_app_windowed<A: App>(config: AppConfig, app: A, app_name: &str) {
let platform = match WinitPlatform::try_new() {
Ok(p) => p,
Err(e) => {
tracing::error!("Failed to create event loop: {e}");
std::process::exit(1);
}
};
let window = app.window_config().unwrap_or_else(|| config.window.clone());
let config = AppConfig { window, ..config };
let app = RefCell::new(Some(app));
let result = super::run_multi_with_platform(
platform,
vec![(SurfaceId(0), config)],
|_id| Arc::new(DesktopPathsProvider) as Arc<dyn AppPathsProvider>,
move |_id| {
app.borrow_mut()
.take()
.expect("windowed app factory is called once")
},
app_name,
);
if let Err(e) = result {
tracing::error!("Event loop exited with error: {e}");
std::process::exit(1);
}
}