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