1pub mod reexports {
2 pub use winit;
3}
4
5use std::sync::Arc;
6
7use crate::{
8 config::LaunchConfig,
9 renderer::{
10 LaunchProxy,
11 NativeEvent,
12 NativeGenericEvent,
13 WinitRenderer,
14 },
15};
16mod accessibility;
17pub mod config;
18mod drivers;
19pub mod extensions;
20pub mod integration;
21pub mod plugins;
22pub mod renderer;
23#[cfg(feature = "tray")]
24mod tray_icon;
25mod window;
26mod winit_mappings;
27
28pub use extensions::*;
29use futures_util::task::{
30 ArcWake,
31 waker,
32};
33
34use crate::winit::event_loop::EventLoopProxy;
35
36pub mod winit {
37 pub use winit::*;
38}
39
40#[cfg(feature = "tray")]
41pub mod tray {
42 pub use tray_icon::*;
43
44 pub use crate::tray_icon::*;
45}
46
47pub fn launch(mut launch_config: LaunchConfig) {
52 use std::collections::HashMap;
53
54 use freya_core::integration::*;
55 use freya_engine::prelude::{
56 FontCollection,
57 FontMgr,
58 TypefaceFontProvider,
59 };
60 use winit::event_loop::EventLoop;
61
62 #[cfg(all(not(debug_assertions), not(target_os = "android")))]
63 {
64 let previous_hook = std::panic::take_hook();
65 std::panic::set_hook(Box::new(move |panic_info| {
66 rfd::MessageDialog::new()
67 .set_title("Fatal Error")
68 .set_description(&panic_info.to_string())
69 .set_level(rfd::MessageLevel::Error)
70 .show();
71 previous_hook(panic_info);
72 std::process::exit(1);
73 }));
74 }
75
76 let event_loop = launch_config.event_loop.take().unwrap_or_else(|| {
77 EventLoop::<NativeEvent>::with_user_event()
78 .build()
79 .expect("Failed to create event loop.")
80 });
81
82 let proxy = event_loop.create_proxy();
83
84 let mut font_collection = FontCollection::new();
85 let def_mgr = FontMgr::default();
86 let font_mgr = FontMgr::custom_empty().unwrap_or_default();
87 let mut provider = TypefaceFontProvider::new();
88 for (font_name, font_data) in launch_config.embedded_fonts {
89 let typeface = font_mgr
90 .new_from_data(&font_data, None)
91 .unwrap_or_else(|| panic!("Failed to load font {font_name}."));
92 provider.register_typeface(typeface, Some(font_name.as_ref()));
93 }
94 let font_mgr: FontMgr = provider.into();
95 font_collection.set_default_font_manager(def_mgr, None);
96 font_collection.set_dynamic_font_manager(font_mgr.clone());
97 font_collection.paragraph_cache_mut().turn_on(false);
98
99 let screen_reader = ScreenReader::new();
100
101 struct FuturesWaker(EventLoopProxy<NativeEvent>);
102
103 impl ArcWake for FuturesWaker {
104 fn wake_by_ref(arc_self: &Arc<Self>) {
105 _ = arc_self
106 .0
107 .send_event(NativeEvent::Generic(NativeGenericEvent::PollFutures));
108 }
109 }
110
111 let waker = waker(Arc::new(FuturesWaker(proxy.clone())));
112
113 #[cfg(feature = "hotreload")]
114 freya_core::hotreload::connect_subsecond();
115
116 let mut renderer = WinitRenderer {
117 windows: HashMap::default(),
118 #[cfg(feature = "tray")]
119 tray: launch_config.tray,
120 #[cfg(all(feature = "tray", not(target_os = "linux")))]
121 tray_icon: None,
122 resumed: false,
123 futures: launch_config
124 .tasks
125 .into_iter()
126 .map(|task| task(LaunchProxy(proxy.clone())))
127 .collect::<Vec<_>>(),
128 proxy,
129 font_manager: font_mgr,
130 font_collection,
131 windows_configs: launch_config.windows_configs,
132 plugins: launch_config.plugins,
133 fallback_fonts: launch_config.fallback_fonts,
134 screen_reader,
135 waker,
136 exit_on_close: launch_config.exit_on_close,
137 gpu_resource_cache_limit: launch_config.gpu_resource_cache_limit,
138 };
139
140 #[cfg(feature = "tray")]
141 {
142 use crate::{
143 renderer::{
144 NativeTrayEvent,
145 NativeTrayEventAction,
146 },
147 tray::{
148 TrayIconEvent,
149 menu::MenuEvent,
150 },
151 };
152
153 let proxy = renderer.proxy.clone();
154 MenuEvent::set_event_handler(Some(move |event| {
155 let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
156 action: NativeTrayEventAction::MenuEvent(event),
157 }));
158 }));
159 let proxy = renderer.proxy.clone();
160 TrayIconEvent::set_event_handler(Some(move |event| {
161 let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
162 action: NativeTrayEventAction::TrayEvent(event),
163 }));
164 }));
165
166 #[cfg(target_os = "linux")]
167 if let Some(tray_icon) = renderer.tray.0.take() {
168 std::thread::spawn(move || {
169 if !gtk::is_initialized() {
170 if gtk::init().is_ok() {
171 tracing::debug!("Tray: GTK initialized");
172 } else {
173 tracing::error!("Tray: Failed to initialize GTK");
174 }
175 }
176
177 let _tray_icon = (tray_icon)();
178
179 gtk::main();
180 });
181 }
182 }
183
184 event_loop.run_app(&mut renderer).unwrap();
185}