1#![warn(missing_docs)]
5use crate::EventResult;
11use crate::winitwindowadapter::WindowVisibility;
12use crate::{SharedBackendData, SlintEvent};
13use corelib::platform::PlatformError;
14use corelib::window::*;
15use i_slint_core as corelib;
16
17#[allow(unused_imports)]
18use std::cell::{RefCell, RefMut};
19use std::rc::Rc;
20use winit::event::WindowEvent;
21use winit::event_loop::{ActiveEventLoop, ControlFlow};
22
23pub enum CustomEvent {
26 #[cfg(target_arch = "wasm32")]
29 WakeEventLoopWorkaround,
30 UserEvent(Box<dyn FnOnce() + Send>),
32 UserEventWithEventLoop(Box<dyn FnOnce(&ActiveEventLoop) + Send>),
34 Exit(usize),
36 #[cfg(enable_accesskit)]
37 Accesskit(accesskit_winit::Event),
38 #[cfg(muda)]
39 Muda(muda::MenuEvent),
40}
41
42impl std::fmt::Debug for CustomEvent {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 #[cfg(target_arch = "wasm32")]
46 Self::WakeEventLoopWorkaround => write!(f, "WakeEventLoopWorkaround"),
47 Self::UserEvent(_) => write!(f, "UserEvent"),
48 Self::UserEventWithEventLoop(_) => write!(f, "UserEventWithEventLoop"),
49 Self::Exit(_) => write!(f, "Exit"),
50 #[cfg(enable_accesskit)]
51 Self::Accesskit(a) => write!(f, "AccessKit({a:?})"),
52 #[cfg(muda)]
53 Self::Muda(e) => write!(f, "Muda({e:?})"),
54 }
55 }
56}
57
58pub struct EventLoopState {
59 shared_backend_data: Rc<SharedBackendData>,
60
61 loop_error: Option<PlatformError>,
62
63 pumping_events_instantly: bool,
65
66 custom_application_handler: Option<Box<dyn crate::CustomApplicationHandler>>,
67}
68
69impl EventLoopState {
70 pub fn new(
71 shared_backend_data: Rc<SharedBackendData>,
72 custom_application_handler: Option<Box<dyn crate::CustomApplicationHandler>>,
73 ) -> Self {
74 Self {
75 shared_backend_data,
76 loop_error: Default::default(),
77 pumping_events_instantly: Default::default(),
78 custom_application_handler,
79 }
80 }
81
82 fn suspend_all_hidden_windows(&self) {
85 let windows_to_suspend = self
86 .shared_backend_data
87 .active_windows
88 .borrow()
89 .values()
90 .filter_map(|w| w.upgrade())
91 .filter(|w| matches!(w.visibility(), WindowVisibility::Hidden))
92 .collect::<Vec<_>>();
93 for window in windows_to_suspend.into_iter() {
94 let _ = window.suspend();
95 }
96 }
97}
98
99impl winit::application::ApplicationHandler<SlintEvent> for EventLoopState {
100 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
101 if matches!(
102 self.custom_application_handler
103 .as_mut()
104 .map_or(EventResult::Propagate, |handler| { handler.resumed(event_loop) }),
105 EventResult::PreventDefault
106 ) {
107 return;
108 }
109 if let Err(err) = self.shared_backend_data.create_inactive_windows(event_loop) {
110 self.loop_error = Some(err);
111 event_loop.exit();
112 }
113 }
114
115 fn window_event(
116 &mut self,
117 event_loop: &ActiveEventLoop,
118 window_id: winit::window::WindowId,
119 event: WindowEvent,
120 ) {
121 let Some(window) = self.shared_backend_data.window_by_id(window_id) else {
122 if let Some(handler) = self.custom_application_handler.as_mut() {
123 handler.window_event(event_loop, window_id, None, None, &event);
124 }
125 return;
126 };
127
128 let Some(winit_window) = window.winit_window() else {
129 return;
130 };
131
132 if matches!(
133 self.custom_application_handler.as_mut().map_or(EventResult::Propagate, |handler| {
134 handler.window_event(
135 event_loop,
136 window_id,
137 Some(&*winit_window),
138 Some(window.window()),
139 &event,
140 )
141 }),
142 EventResult::PreventDefault
143 ) {
144 return;
145 }
146
147 if let Err(err) = window.dispatch_winit_window_event(event_loop, &winit_window, event) {
148 self.loop_error = Some(err);
149 event_loop.exit();
150 }
151 }
152
153 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: SlintEvent) {
154 match event.0 {
155 CustomEvent::UserEvent(user_callback) => user_callback(),
156 CustomEvent::UserEventWithEventLoop(user_callback) => user_callback(event_loop),
157 CustomEvent::Exit(generation) => {
158 if self
159 .shared_backend_data
160 .event_loop_generation
161 .load(std::sync::atomic::Ordering::Relaxed)
162 == generation
163 {
164 self.suspend_all_hidden_windows();
165 event_loop.exit()
166 }
167 }
169 #[cfg(enable_accesskit)]
170 CustomEvent::Accesskit(accesskit_winit::Event { window_id, window_event }) => {
171 if let Some(window) = self.shared_backend_data.window_by_id(window_id) {
172 let deferred_action = window
173 .accesskit_adapter()
174 .expect("internal error: accesskit adapter must exist when window exists")
175 .borrow_mut()
176 .process_accesskit_event(window_event);
177 if let Some(deferred_action) = deferred_action {
179 deferred_action.invoke(window.window());
180 }
181 }
182 }
183 #[cfg(target_arch = "wasm32")]
184 CustomEvent::WakeEventLoopWorkaround => {
185 event_loop.set_control_flow(ControlFlow::Poll);
186 }
187 #[cfg(muda)]
188 CustomEvent::Muda(event) => {
189 if let Some((window, eid, muda_type)) =
190 event.id().0.split_once('|').and_then(|(w, e)| {
191 let (e, muda_type) = e.split_once('|')?;
192 Some((
193 self.shared_backend_data.window_by_id(
194 winit::window::WindowId::from(w.parse::<u64>().ok()?),
195 )?,
196 e.parse::<usize>().ok()?,
197 muda_type.parse::<crate::muda::MudaType>().ok()?,
198 ))
199 })
200 {
201 window.muda_event(eid, muda_type);
202 };
203 }
204 }
205 }
206
207 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) {
208 if matches!(
209 self.custom_application_handler.as_mut().map_or(EventResult::Propagate, |handler| {
210 handler.new_events(event_loop, cause)
211 }),
212 EventResult::PreventDefault
213 ) {
214 return;
215 }
216
217 event_loop.set_control_flow(ControlFlow::Wait);
218
219 self.shared_backend_data.context().update_timers_and_animations();
220 }
221
222 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
223 self.shared_backend_data.flush_pending_mouse_move();
224
225 if matches!(
226 self.custom_application_handler
227 .as_mut()
228 .map_or(EventResult::Propagate, |handler| { handler.about_to_wait(event_loop) }),
229 EventResult::PreventDefault
230 ) {
231 return;
232 }
233
234 if let Err(err) = self.shared_backend_data.create_inactive_windows(event_loop) {
235 self.loop_error = Some(err);
236 }
237
238 if !event_loop.exiting() {
239 for w in self
240 .shared_backend_data
241 .active_windows
242 .borrow()
243 .values()
244 .filter_map(|w| w.upgrade())
245 {
246 if w.window().has_active_animations() {
247 w.request_redraw();
248 }
249 }
250 }
251
252 if event_loop.control_flow() == ControlFlow::Wait
253 && let Some(next_timer) =
254 self.shared_backend_data.context().duration_until_next_timer_update()
255 {
256 event_loop.set_control_flow(ControlFlow::wait_duration(next_timer));
257 }
258
259 if self.pumping_events_instantly {
260 event_loop.set_control_flow(ControlFlow::Poll);
261 }
262 }
263
264 fn device_event(
265 &mut self,
266 event_loop: &ActiveEventLoop,
267 device_id: winit::event::DeviceId,
268 event: winit::event::DeviceEvent,
269 ) {
270 if let Some(handler) = self.custom_application_handler.as_mut() {
271 handler.device_event(event_loop, device_id, event);
272 }
273 }
274
275 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
276 if let Some(handler) = self.custom_application_handler.as_mut() {
277 handler.suspended(event_loop);
278 }
279 }
280
281 fn exiting(&mut self, event_loop: &ActiveEventLoop) {
282 if let Some(handler) = self.custom_application_handler.as_mut() {
283 handler.exiting(event_loop);
284 }
285 }
286
287 fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
288 if let Some(handler) = self.custom_application_handler.as_mut() {
289 handler.memory_warning(event_loop);
290 }
291 }
292}
293
294impl EventLoopState {
295 #[allow(unused_mut)] pub fn run(mut self) -> Result<Self, corelib::platform::PlatformError> {
299 let not_running_loop_instance = self
300 .shared_backend_data
301 .not_running_event_loop
302 .take()
303 .ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
304 let mut winit_loop = not_running_loop_instance;
305
306 cfg_if::cfg_if! {
307 if #[cfg(any(target_arch = "wasm32", ios_and_friends))] {
308 winit_loop
309 .run_app(&mut self)
310 .map_err(|e| format!("Error running winit event loop: {e}"))?;
311 Ok(Self::new(self.shared_backend_data.clone(), None))
313 } else {
314 use winit::platform::run_on_demand::EventLoopExtRunOnDemand as _;
315 winit_loop
316 .run_app_on_demand(&mut self)
317 .map_err(|e| format!("Error running winit event loop: {e}"))?;
318
319 self.shared_backend_data.not_running_event_loop.replace(Some(winit_loop));
322
323 if let Some(error) = self.loop_error {
324 return Err(error);
325 }
326 Ok(self)
327 }
328 }
329 }
330
331 #[cfg(all(not(target_arch = "wasm32"), not(ios_and_friends)))]
334 pub fn pump_events(
335 mut self,
336 timeout: Option<std::time::Duration>,
337 ) -> Result<(Self, winit::platform::pump_events::PumpStatus), corelib::platform::PlatformError>
338 {
339 use winit::platform::pump_events::EventLoopExtPumpEvents;
340
341 let not_running_loop_instance = self
342 .shared_backend_data
343 .not_running_event_loop
344 .take()
345 .ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
346 let mut winit_loop = not_running_loop_instance;
347
348 self.pumping_events_instantly = timeout.is_some_and(|duration| duration.is_zero());
349
350 let result = winit_loop.pump_app_events(timeout, &mut self);
351
352 self.pumping_events_instantly = false;
353
354 self.shared_backend_data.not_running_event_loop.replace(Some(winit_loop));
357
358 if let Some(error) = self.loop_error {
359 return Err(error);
360 }
361 Ok((self, result))
362 }
363
364 #[cfg(target_arch = "wasm32")]
365 pub fn spawn(self) -> Result<(), corelib::platform::PlatformError> {
366 use winit::platform::web::EventLoopExtWebSys;
367 let not_running_loop_instance = self
368 .shared_backend_data
369 .not_running_event_loop
370 .take()
371 .ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
372
373 not_running_loop_instance.spawn_app(self);
374
375 Ok(())
376 }
377}