1use crate::app::BrepApp;
30use eframe::UserEvent;
31use std::cell::RefCell;
32use std::rc::Rc;
33use std::sync::{Arc, Mutex};
34use std::time::{Duration, Instant};
35use winit::application::ApplicationHandler;
36use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy};
37
38pub type Waker = Arc<dyn Fn() + Send + Sync>;
40
41const WAKE: u64 = u64::MAX;
45
46const SERVICE_PACE: Duration = Duration::from_millis(16);
52
53#[derive(Clone, Default)]
57pub struct Slot(Rc<RefCell<Option<(Rc<RefCell<BrepApp>>, egui::Context)>>>);
58
59impl Slot {
60 pub fn install(&self, app: BrepApp, ctx: &egui::Context) -> Shell {
63 let app = Rc::new(RefCell::new(app));
64 *self.0.borrow_mut() = Some((app.clone(), ctx.clone()));
65 Shell(app)
66 }
67
68 fn get(&self) -> Option<(Rc<RefCell<BrepApp>>, egui::Context)> {
69 self.0.borrow().clone()
70 }
71}
72
73pub struct Shell(Rc<RefCell<BrepApp>>);
75
76impl eframe::App for Shell {
77 fn logic(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
78 eframe::App::logic(&mut *self.0.borrow_mut(), ctx, frame)
79 }
80 fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
81 eframe::App::ui(&mut *self.0.borrow_mut(), ui, frame)
82 }
83 fn save(&mut self, storage: &mut dyn eframe::Storage) {
84 eframe::App::save(&mut *self.0.borrow_mut(), storage)
85 }
86 fn on_exit(&mut self) {
87 eframe::App::on_exit(&mut *self.0.borrow_mut())
88 }
89 fn auto_save_interval(&self) -> Duration {
90 eframe::App::auto_save_interval(&*self.0.borrow())
91 }
92 fn clear_color(&self, visuals: &egui::Visuals) -> [f32; 4] {
93 eframe::App::clear_color(&*self.0.borrow(), visuals)
94 }
95 fn persist_egui_memory(&self) -> bool {
96 eframe::App::persist_egui_memory(&*self.0.borrow())
97 }
98 fn raw_input_hook(&mut self, ctx: &egui::Context, raw_input: &mut egui::RawInput) {
99 eframe::App::raw_input_hook(&mut *self.0.borrow_mut(), ctx, raw_input)
100 }
101}
102
103pub fn waker(proxy: EventLoopProxy<UserEvent>) -> Waker {
106 let proxy = Mutex::new(proxy);
107 Arc::new(move || {
108 let event = UserEvent::RequestRepaint { viewport_id: egui::ViewportId::ROOT, when: Instant::now(), cumulative_pass_nr: WAKE };
109 let _ = proxy.lock().unwrap_or_else(|p| p.into_inner()).send_event(event);
110 })
111}
112
113fn is_wake(event: &UserEvent) -> bool {
114 matches!(event, UserEvent::RequestRepaint { cumulative_pass_nr: WAKE, .. })
115}
116
117pub struct DesktopLoop<H> {
119 inner: H,
120 slot: Slot,
121 busy: bool,
123 paced: Option<Instant>,
125 polled: bool,
127 redrawn: bool,
129}
130
131impl<H: ApplicationHandler<UserEvent>> DesktopLoop<H> {
132 pub fn new(inner: H, slot: Slot) -> Self {
133 DesktopLoop { inner, slot, busy: false, paced: None, polled: false, redrawn: false }
134 }
135
136 fn unstick_poll(&mut self, event_loop: &ActiveEventLoop) {
140 if event_loop.control_flow() == ControlFlow::Poll {
141 if self.polled && !self.redrawn {
142 event_loop.set_control_flow(ControlFlow::Wait);
143 self.polled = false;
144 } else {
145 self.polled = true;
146 }
147 } else {
148 self.polled = false;
149 }
150 self.redrawn = false;
151 }
152
153 fn service(&mut self, event_loop: &ActiveEventLoop) {
156 #[cfg(feature = "automation")]
157 self.step();
158 #[cfg(not(feature = "automation"))]
159 let _ = &self.slot;
160 let ours = self.paced.take().filter(|at| event_loop.control_flow() == ControlFlow::WaitUntil(*at));
163 if self.busy {
164 let next = Instant::now() + SERVICE_PACE;
165 match event_loop.control_flow() {
166 ControlFlow::Poll => {}
167 ControlFlow::WaitUntil(at) if at <= next && ours.is_none() => {}
169 _ => {
170 event_loop.set_control_flow(ControlFlow::WaitUntil(next));
171 self.paced = Some(next);
172 }
173 }
174 } else if ours.is_some() {
175 event_loop.set_control_flow(ControlFlow::Wait);
178 }
179 }
180
181 #[cfg(feature = "automation")]
182 fn step(&mut self) {
183 let Some((app, ctx)) = self.slot.get() else { return };
184 let Ok(mut app) = app.try_borrow_mut() else { return };
186 if !self.busy && !app.automation().has_frameless_work() {
187 return;
188 }
189 self.busy = app.service_automation(&ctx);
190 }
191}
192
193impl<H: ApplicationHandler<UserEvent>> ApplicationHandler<UserEvent> for DesktopLoop<H> {
194 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) {
195 self.inner.new_events(event_loop, cause);
196 }
197
198 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
199 self.inner.resumed(event_loop);
200 }
201
202 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) {
203 if !is_wake(&event) {
206 self.inner.user_event(event_loop, event);
207 }
208 }
209
210 fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: winit::window::WindowId, event: winit::event::WindowEvent) {
211 self.redrawn |= matches!(event, winit::event::WindowEvent::RedrawRequested);
212 self.inner.window_event(event_loop, window_id, event);
213 }
214
215 fn device_event(&mut self, event_loop: &ActiveEventLoop, device_id: winit::event::DeviceId, event: winit::event::DeviceEvent) {
216 self.inner.device_event(event_loop, device_id, event);
217 }
218
219 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
223 self.inner.about_to_wait(event_loop);
224 self.unstick_poll(event_loop);
225 if !event_loop.exiting() {
226 self.service(event_loop);
227 }
228 }
229
230 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
231 self.inner.suspended(event_loop);
232 }
233
234 fn exiting(&mut self, event_loop: &ActiveEventLoop) {
235 self.inner.exiting(event_loop);
236 }
237
238 fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
239 self.inner.memory_warning(event_loop);
240 }
241}
242
243pub type Create<'a> = Box<dyn 'a + FnOnce(&eframe::CreationContext<'_>, Waker) -> Result<BrepApp, String>>;
246
247pub fn run(app_name: &str, options: eframe::NativeOptions, create: Create<'_>) -> Result<(), String> {
249 let event_loop = EventLoop::<UserEvent>::with_user_event().build().map_err(|e| format!("event loop: {e}"))?;
250 run_on(event_loop, app_name, options, create, |eframe| eframe)
251}
252
253pub fn run_on<'a, H: ApplicationHandler<UserEvent>>(
257 event_loop: EventLoop<UserEvent>,
258 app_name: &str,
259 options: eframe::NativeOptions,
260 create: Create<'a>,
261 wrap: impl FnOnce(eframe::EframeWinitApplication<'a>) -> H,
262) -> Result<(), String> {
263 let slot = Slot::default();
264 let failure: Rc<RefCell<Option<String>>> = Rc::default();
265 let waker = waker(event_loop.create_proxy());
266 let (installer, failed) = (slot.clone(), failure.clone());
267 let creator: eframe::AppCreator<'a> = Box::new(move |cc| match create(cc, waker) {
268 Ok(app) => Ok(Box::new(installer.install(app, &cc.egui_ctx)) as Box<dyn eframe::App>),
269 Err(error) => {
270 *failed.borrow_mut() = Some(error.clone());
271 Err(error.into())
272 }
273 });
274 let eframe = eframe::create_native(app_name, options, creator, &event_loop);
275 let mut handler = DesktopLoop::new(wrap(eframe), slot);
276 event_loop.run_app(&mut handler).map_err(|e| format!("event loop: {e}"))?;
277 let failed = failure.borrow_mut().take();
278 match failed {
279 Some(error) => Err(error),
280 None => Ok(()),
281 }
282}