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 std::sync::mpsc;
16use winit::event_loop::{EventLoop, EventLoopProxy};
17
18#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
23#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
24pub struct PreLaunchState {
25 config: Rc<RefCell<Config>>,
26 config_writer: Option<Box<dyn FnMut(&Config)>>,
27 el: EventLoop,
28 platform: Platform,
29 proxy_tx: mpsc::SyncSender<ProxyAction>,
30 proxy_rx: mpsc::Receiver<ProxyAction>,
31 window_id_factory: WindowIdFactory,
32}
33
34impl PreLaunchState {
35 pub fn new<C: ConfigFactory>(config: C) -> Result<Self> {
37 let mut cf = config;
38 let config = cf.read_config()?;
39 config.borrow_mut().init();
40
41 let el = EventLoop::new()?;
42 let platform = Platform::new(&el);
43
44 let (proxy_tx, proxy_rx) = mpsc::sync_channel(16);
45
46 Ok(PreLaunchState {
47 config,
48 config_writer: cf.writer(),
49 el,
50 platform,
51 proxy_tx,
52 proxy_rx,
53 window_id_factory: Default::default(),
54 })
55 }
56
57 #[inline]
59 pub fn config(&self) -> &Rc<RefCell<Config>> {
60 &self.config
61 }
62
63 #[inline]
65 pub fn next_window_id(&mut self) -> WindowId {
66 self.window_id_factory.make_next()
67 }
68
69 #[inline]
71 pub fn platform(&self) -> Platform {
72 self.platform
73 }
74
75 pub fn create_proxy(&self) -> Proxy {
77 Proxy::new(self.proxy_tx.clone(), self.el.create_proxy())
78 }
79
80 pub fn run<Data: AppData, G: GraphicsInstance + 'static, T: Theme<G::Shared> + 'static>(
82 self,
83 data: Data,
84 graphical: G,
85 theme: T,
86 windows: Vec<Box<super::Window<Data, G, T>>>,
87 ) -> Result<()> {
88 let shared = Shared::<Data, _, _>::new(
89 self.platform,
90 graphical,
91 theme,
92 self.config,
93 self.config_writer,
94 create_waker(&self.el),
95 self.proxy_rx,
96 self.window_id_factory,
97 )?;
98
99 let l = super::Loop::new(windows, shared, data);
100 self.el.run_app(l)?;
101 Ok(())
102 }
103}
104
105impl Platform {
106 #[allow(clippy::needless_return)]
108 fn new(_el: &EventLoop) -> Platform {
109 #[cfg(target_os = "windows")]
112 return Platform::Windows;
113
114 #[cfg(any(
115 target_os = "linux",
116 target_os = "dragonfly",
117 target_os = "freebsd",
118 target_os = "netbsd",
119 target_os = "openbsd"
120 ))]
121 {
122 cfg_if::cfg_if! {
123 if #[cfg(all(feature = "wayland", feature = "x11"))] {
124 use winit::platform::wayland::EventLoopExtWayland;
125 return if _el.is_wayland() {
126 Platform::Wayland
127 } else {
128 Platform::X11
129 };
130 } else if #[cfg(feature = "wayland")] {
131 return Platform::Wayland;
132 } else if #[cfg(feature = "x11")] {
133 return Platform::X11;
134 } else {
135 compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
136 }
137 }
138 }
139
140 #[cfg(target_os = "macos")]
141 return Platform::MacOS;
142
143 #[cfg(target_os = "android")]
144 return Platform::Android;
145
146 #[cfg(target_os = "ios")]
147 return Platform::IOS;
148
149 #[cfg(target_arch = "wasm32")]
150 return Platform::Web;
151
152 }
154}
155
156fn create_waker(el: &EventLoop) -> std::task::Waker {
161 use std::sync::Arc;
162 use std::task::{RawWaker, RawWakerVTable, Waker};
163
164 let proxy = el.create_proxy();
166 let a: Arc<EventLoopProxy> = Arc::new(proxy);
167 let data = Arc::into_raw(a);
168
169 fn wake_async(proxy: &EventLoopProxy) {
170 proxy.wake_up();
172 }
173
174 const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
175
176 unsafe fn clone(data: *const ()) -> RawWaker {
177 unsafe {
178 let a = Arc::from_raw(data as *const EventLoopProxy);
179 let c = Arc::into_raw(a.clone());
180 let _do_not_drop = Arc::into_raw(a);
181 RawWaker::new(c as *const (), &VTABLE)
182 }
183 }
184 unsafe fn wake(data: *const ()) {
185 unsafe {
186 let a = Arc::from_raw(data as *const EventLoopProxy);
187 wake_async(&a);
188 }
189 }
190 unsafe fn wake_by_ref(data: *const ()) {
191 unsafe {
192 let a = Arc::from_raw(data as *const EventLoopProxy);
193 wake_async(&a);
194 let _do_not_drop = Arc::into_raw(a);
195 }
196 }
197 unsafe fn drop(data: *const ()) {
198 unsafe {
199 let _ = Arc::from_raw(data as *const EventLoopProxy);
200 }
201 }
202
203 let raw_waker = RawWaker::new(data as *const (), &VTABLE);
204 unsafe { Waker::from_raw(raw_waker) }
205}
206
207#[derive(Clone)]
211pub struct Proxy {
212 tx: mpsc::SyncSender<ProxyAction>,
213 waker: EventLoopProxy,
214}
215
216pub struct ClosedError;
220
221impl Proxy {
222 #[inline]
223 fn new(tx: mpsc::SyncSender<ProxyAction>, waker: EventLoopProxy) -> Self {
224 Proxy { tx, waker }
225 }
226
227 pub fn close(&self, id: WindowId) -> std::result::Result<(), ClosedError> {
231 self.tx
232 .send(ProxyAction::Close(id))
233 .map_err(|_| ClosedError)?;
234 self.waker.wake_up();
235 Ok(())
236 }
237
238 pub fn close_all(&self) -> std::result::Result<(), ClosedError> {
242 self.tx
243 .send(ProxyAction::CloseAll)
244 .map_err(|_| ClosedError)?;
245 self.waker.wake_up();
246 Ok(())
247 }
248
249 pub fn push<M: std::fmt::Debug + Send + 'static>(
257 &mut self,
258 msg: M,
259 ) -> std::result::Result<(), ClosedError> {
260 self.tx
261 .send(ProxyAction::Message(kas::messages::SendErased::new(msg)))
262 .map_err(|_| ClosedError)?;
263 self.waker.wake_up();
264 Ok(())
265 }
266}