freya_winit/
lib.rs

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(launch_config: LaunchConfig) {
47    use std::collections::HashMap;
48
49    use freya_core::integration::*;
50    use freya_engine::prelude::{
51        FontCollection,
52        FontMgr,
53        TypefaceFontProvider,
54    };
55    use winit::event_loop::EventLoop;
56
57    let mut event_loop_builder = EventLoop::<NativeEvent>::with_user_event();
58
59    let event_loop = event_loop_builder
60        .build()
61        .expect("Failed to create event loop.");
62
63    let proxy = event_loop.create_proxy();
64
65    let mut font_collection = FontCollection::new();
66    let def_mgr = FontMgr::default();
67    let mut provider = TypefaceFontProvider::new();
68    for (font_name, font_data) in launch_config.embedded_fonts {
69        let ft_type = def_mgr
70            .new_from_data(&font_data, None)
71            .unwrap_or_else(|| panic!("Failed to load font {font_name}."));
72        provider.register_typeface(ft_type, Some(font_name.as_ref()));
73    }
74    let font_mgr: FontMgr = provider.into();
75    font_collection.set_default_font_manager(def_mgr, None);
76    font_collection.set_dynamic_font_manager(font_mgr.clone());
77    font_collection.paragraph_cache_mut().turn_on(false);
78
79    let screen_reader = ScreenReader::new();
80
81    struct FuturesWaker(EventLoopProxy<NativeEvent>);
82
83    impl ArcWake for FuturesWaker {
84        fn wake_by_ref(arc_self: &Arc<Self>) {
85            _ = arc_self
86                .0
87                .send_event(NativeEvent::Generic(NativeGenericEvent::PollFutures));
88        }
89    }
90
91    let waker = waker(Arc::new(FuturesWaker(proxy.clone())));
92
93    let mut renderer = WinitRenderer {
94        windows: HashMap::default(),
95        #[cfg(feature = "tray")]
96        tray: launch_config.tray,
97        #[cfg(all(feature = "tray", not(target_os = "linux")))]
98        tray_icon: None,
99        resumed: false,
100        futures: launch_config
101            .tasks
102            .into_iter()
103            .map(|task| task(LaunchProxy(proxy.clone())))
104            .collect::<Vec<_>>(),
105        proxy,
106        font_manager: font_mgr,
107        font_collection,
108        windows_configs: launch_config.windows_configs,
109        plugins: launch_config.plugins,
110        fallback_fonts: launch_config.fallback_fonts,
111        screen_reader,
112        waker,
113    };
114
115    #[cfg(feature = "tray")]
116    {
117        use crate::{
118            renderer::{
119                NativeTrayEvent,
120                NativeTrayEventAction,
121            },
122            tray::{
123                TrayIconEvent,
124                menu::MenuEvent,
125            },
126        };
127
128        let proxy = renderer.proxy.clone();
129        MenuEvent::set_event_handler(Some(move |event| {
130            let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
131                action: NativeTrayEventAction::MenuEvent(event),
132            }));
133        }));
134        let proxy = renderer.proxy.clone();
135        TrayIconEvent::set_event_handler(Some(move |event| {
136            let _ = proxy.send_event(NativeEvent::Tray(NativeTrayEvent {
137                action: NativeTrayEventAction::TrayEvent(event),
138            }));
139        }));
140
141        #[cfg(target_os = "linux")]
142        if let Some(tray_icon) = renderer.tray.0.take() {
143            std::thread::spawn(move || {
144                if !gtk::is_initialized() {
145                    if gtk::init().is_ok() {
146                        tracing::debug!("Tray: GTK initialized");
147                    } else {
148                        tracing::error!("Tray: Failed to initialize GTK");
149                    }
150                }
151
152                let _tray_icon = (tray_icon)();
153
154                gtk::main();
155            });
156        }
157    }
158
159    event_loop.run_app(&mut renderer).unwrap();
160}