pub mod reexports {
pub use winit;
}
use std::sync::Arc;
use crate::{
config::LaunchConfig,
renderer::{
LaunchProxy,
NativeEvent,
NativeGenericEvent,
WinitRenderer,
},
};
mod accessibility;
pub mod config;
mod drivers;
pub mod extensions;
pub mod integration;
pub mod plugins;
pub mod renderer;
#[cfg(feature = "tray")]
mod tray_icon;
mod window;
mod winit_mappings;
pub use extensions::*;
use futures_util::task::{
ArcWake,
waker,
};
use crate::winit::event_loop::EventLoopProxy;
pub mod winit {
pub use winit::*;
}
#[cfg(feature = "tray")]
pub mod tray {
pub use tray_icon::*;
pub use crate::tray_icon::*;
}
pub fn launch(mut launch_config: LaunchConfig) {
use std::collections::HashMap;
use freya_engine::prelude::{
FontCollection,
FontMgr,
TypefaceFontProvider,
};
use winit::event_loop::EventLoop;
#[cfg(all(not(debug_assertions), not(target_os = "android")))]
{
let previous_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
rfd::MessageDialog::new()
.set_title("Fatal Error")
.set_description(&panic_info.to_string())
.set_level(rfd::MessageLevel::Error)
.show();
previous_hook(panic_info);
std::process::exit(1);
}));
}
let event_loop = launch_config.event_loop.take().unwrap_or_else(|| {
EventLoop::<NativeEvent>::with_user_event()
.build()
.expect("Failed to create event loop.")
});
let proxy = event_loop.create_proxy();
let mut font_collection = FontCollection::new();
let def_mgr = FontMgr::default();
let font_mgr = FontMgr::custom_empty().unwrap_or_default();
let mut provider = TypefaceFontProvider::new();
for (font_name, font_data) in launch_config.embedded_fonts {
let typeface = font_mgr
.new_from_data(&font_data, None)
.unwrap_or_else(|| panic!("Failed to load font {font_name}."));
provider.register_typeface(typeface, Some(font_name.as_ref()));
}
let font_mgr: FontMgr = provider.into();
font_collection.set_default_font_manager(def_mgr, None);
font_collection.set_dynamic_font_manager(font_mgr.clone());
font_collection.paragraph_cache_mut().turn_on(false);
struct FuturesWaker(EventLoopProxy<NativeEvent>);
impl ArcWake for FuturesWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
_ = arc_self
.0
.send_event(NativeEvent::Generic(NativeGenericEvent::PollFutures));
}
}
let waker = waker(Arc::new(FuturesWaker(proxy.clone())));
#[cfg(feature = "hotreload")]
freya_core::hotreload::connect_subsecond();
let mut renderer = WinitRenderer {
windows: HashMap::default(),
#[cfg(feature = "tray")]
tray: launch_config.tray,
#[cfg(all(feature = "tray", not(target_os = "linux")))]
tray_icon: None,
resumed: false,
futures: launch_config
.tasks
.into_iter()
.map(|task| task(LaunchProxy(proxy.clone())))
.collect::<Vec<_>>(),
proxy,
font_manager: font_mgr,
font_collection,
windows_configs: launch_config.windows_configs,
plugins: launch_config.plugins,
fallback_fonts: launch_config.fallback_fonts,
waker,
exit_on_close: launch_config.exit_on_close,
gpu_resource_cache_limit: launch_config.gpu_resource_cache_limit,
};
#[cfg(feature = "tray")]
{
use crate::{
renderer::{
NativeTrayEvent,
NativeTrayEventAction,
},
tray::{
TrayIconEvent,
menu::MenuEvent,
},
};
let proxy = renderer.proxy.clone();
MenuEvent::set_event_handler(Some(move |event| {
let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
action: NativeTrayEventAction::MenuEvent(event),
}));
}));
let proxy = renderer.proxy.clone();
TrayIconEvent::set_event_handler(Some(move |event| {
let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
action: NativeTrayEventAction::TrayEvent(event),
}));
}));
#[cfg(target_os = "linux")]
if let Some(tray_icon) = renderer.tray.0.take() {
std::thread::spawn(move || {
if !gtk::is_initialized() {
if gtk::init().is_ok() {
tracing::debug!("Tray: GTK initialized");
} else {
tracing::error!("Tray: Failed to initialize GTK");
}
}
let _tray_icon = (tray_icon)();
gtk::main();
});
}
}
event_loop.run_app(&mut renderer).unwrap();
}