kas_core/runner/
runner.rs1use super::{AppData, GraphicsInstance, Platform, ProxyAction, Result, Shared};
9use crate::config::{Config, ConfigFactory};
10#[allow(unused)] use crate::event::ConfigCx;
11use crate::theme::Theme;
12use crate::window::{WindowId, WindowIdFactory};
13use std::cell::RefCell;
14use std::rc::Rc;
15use winit::event_loop::{EventLoop, EventLoopProxy};
16
17#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
22#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
23pub struct PreLaunchState {
24 config: Rc<RefCell<Config>>,
25 config_writer: Option<Box<dyn FnMut(&Config)>>,
26 el: EventLoop<ProxyAction>,
27 platform: Platform,
28 window_id_factory: WindowIdFactory,
29}
30
31impl PreLaunchState {
32 pub fn new<C: ConfigFactory>(config: C) -> Result<Self> {
34 let mut cf = config;
35 let config = cf.read_config()?;
36 config.borrow_mut().init();
37
38 let el = EventLoop::with_user_event().build()?;
39 let platform = Platform::new(&el);
40 Ok(PreLaunchState {
41 config,
42 config_writer: cf.writer(),
43 el,
44 platform,
45 window_id_factory: Default::default(),
46 })
47 }
48
49 #[inline]
51 pub fn config(&self) -> &Rc<RefCell<Config>> {
52 &self.config
53 }
54
55 #[inline]
57 pub fn next_window_id(&mut self) -> WindowId {
58 self.window_id_factory.make_next()
59 }
60
61 #[inline]
63 pub fn platform(&self) -> Platform {
64 self.platform
65 }
66
67 pub fn create_proxy(&self) -> Proxy {
69 Proxy(self.el.create_proxy())
70 }
71
72 pub fn run<Data: AppData, G: GraphicsInstance, T: Theme<G::Shared>>(
74 self,
75 data: Data,
76 graphical: G,
77 theme: T,
78 windows: Vec<Box<super::Window<Data, G, T>>>,
79 ) -> Result<()> {
80 let shared = Shared::<Data, _, _>::new(
81 self.platform,
82 graphical,
83 theme,
84 self.config,
85 self.config_writer,
86 create_waker(&self.el),
87 #[cfg(feature = "accesskit")]
88 Proxy(self.el.create_proxy()),
89 self.window_id_factory,
90 )?;
91
92 let mut l = super::Loop::new(windows, shared, data);
93 self.el.run_app(&mut l)?;
94 Ok(())
95 }
96}
97
98impl Platform {
99 #[allow(clippy::needless_return)]
101 fn new(_el: &EventLoop<ProxyAction>) -> Platform {
102 #[cfg(target_os = "windows")]
105 return Platform::Windows;
106
107 #[cfg(any(
108 target_os = "linux",
109 target_os = "dragonfly",
110 target_os = "freebsd",
111 target_os = "netbsd",
112 target_os = "openbsd"
113 ))]
114 {
115 cfg_if::cfg_if! {
116 if #[cfg(all(feature = "wayland", feature = "x11"))] {
117 use winit::platform::wayland::EventLoopExtWayland;
118 return if _el.is_wayland() {
119 Platform::Wayland
120 } else {
121 Platform::X11
122 };
123 } else if #[cfg(feature = "wayland")] {
124 return Platform::Wayland;
125 } else if #[cfg(feature = "x11")] {
126 return Platform::X11;
127 } else {
128 compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
129 }
130 }
131 }
132
133 #[cfg(target_os = "macos")]
134 return Platform::MacOS;
135
136 #[cfg(target_os = "android")]
137 return Platform::Android;
138
139 #[cfg(target_os = "ios")]
140 return Platform::IOS;
141
142 #[cfg(target_arch = "wasm32")]
143 return Platform::Web;
144
145 }
147}
148
149fn create_waker(el: &EventLoop<ProxyAction>) -> std::task::Waker {
154 use std::sync::{Arc, Mutex};
155 use std::task::{RawWaker, RawWakerVTable, Waker};
156
157 type Data = Mutex<Proxy>;
160 let proxy = Proxy(el.create_proxy());
161 let a: Arc<Data> = Arc::new(Mutex::new(proxy));
162 let data = Arc::into_raw(a);
163
164 const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
165
166 unsafe fn clone(data: *const ()) -> RawWaker {
167 unsafe {
168 let a = Arc::from_raw(data as *const Data);
169 let c = Arc::into_raw(a.clone());
170 let _do_not_drop = Arc::into_raw(a);
171 RawWaker::new(c as *const (), &VTABLE)
172 }
173 }
174 unsafe fn wake(data: *const ()) {
175 unsafe {
176 let a = Arc::from_raw(data as *const Data);
177 a.lock().unwrap().wake_async();
178 }
179 }
180 unsafe fn wake_by_ref(data: *const ()) {
181 unsafe {
182 let a = Arc::from_raw(data as *const Data);
183 a.lock().unwrap().wake_async();
184 let _do_not_drop = Arc::into_raw(a);
185 }
186 }
187 unsafe fn drop(data: *const ()) {
188 unsafe {
189 let _ = Arc::from_raw(data as *const Data);
190 }
191 }
192
193 let raw_waker = RawWaker::new(data as *const (), &VTABLE);
194 unsafe { Waker::from_raw(raw_waker) }
195}
196
197#[derive(Clone)]
201pub struct Proxy(pub(super) EventLoopProxy<ProxyAction>);
202
203pub struct ClosedError;
207
208impl Proxy {
209 pub fn close(&self, id: WindowId) -> std::result::Result<(), ClosedError> {
211 self.0
212 .send_event(ProxyAction::Close(id))
213 .map_err(|_| ClosedError)
214 }
215
216 pub fn close_all(&self) -> std::result::Result<(), ClosedError> {
218 self.0
219 .send_event(ProxyAction::CloseAll)
220 .map_err(|_| ClosedError)
221 }
222
223 pub fn push<M: std::fmt::Debug + Send + 'static>(
229 &mut self,
230 msg: M,
231 ) -> std::result::Result<(), ClosedError> {
232 self.0
233 .send_event(ProxyAction::Message(kas::messages::SendErased::new(msg)))
234 .map_err(|_| ClosedError)
235 }
236
237 fn wake_async(&self) {
239 let _ = self.0.send_event(ProxyAction::WakeAsync);
241 }
242}