1use std::{
2 collections::HashMap,
3 fmt, mem,
4 path::PathBuf,
5 sync::Arc,
6 task::Waker,
7 time::{Duration, Instant},
8};
9
10use crate::{Deadline, view_process::raw_device_events::INPUT_DEVICES};
11use parking_lot::Mutex;
12use zng_app_context::{AppScope, app_local};
13use zng_task::DEADLINE_APP;
14use zng_time::{INSTANT_APP, InstantMode};
15use zng_txt::Txt;
16use zng_var::{ArcVar, ReadOnlyArcVar, ResponderVar, ResponseVar, VARS, VARS_APP, Var as _, response_var};
17use zng_view_api::raw_input::InputDeviceEvent;
18
19use crate::{
20 APP, AppControlFlow, AppEventObserver, AppExtension, AppExtensionsInfo, DInstant, INSTANT,
21 event::{AnyEventArgs, CommandHandle, CommandInfoExt, CommandNameExt, EVENTS, EventPropagationHandle, command, event},
22 event_args,
23 shortcut::CommandShortcutExt,
24 shortcut::shortcut,
25 timer::TimersService,
26 update::{
27 ContextUpdates, EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdateOp, UpdateTrace, UpdatesTrace, WidgetUpdates,
28 },
29 view_process::{raw_device_events::InputDeviceId, *},
30 widget::WidgetId,
31 window::WindowId,
32};
33
34pub(crate) struct RunningApp<E: AppExtension> {
36 extensions: (AppIntrinsic, E),
37
38 receiver: flume::Receiver<AppEvent>,
39
40 loop_timer: LoopTimer,
41 loop_monitor: LoopMonitor,
42
43 pending_view_events: Vec<zng_view_api::Event>,
44 pending_view_frame_events: Vec<zng_view_api::window::EventFrameRendered>,
45 pending: ContextUpdates,
46
47 exited: bool,
48
49 _scope: AppScope,
51}
52impl<E: AppExtension> RunningApp<E> {
53 pub(crate) fn start(
54 scope: AppScope,
55 mut extensions: E,
56 is_headed: bool,
57 with_renderer: bool,
58 view_process_exe: Option<PathBuf>,
59 view_process_env: HashMap<Txt, Txt>,
60 ) -> Self {
61 let _s = tracing::debug_span!("APP::start").entered();
62
63 let (sender, receiver) = AppEventSender::new();
64
65 UPDATES.init(sender);
66
67 fn app_waker() {
68 UPDATES.update(None);
69 }
70 VARS_APP.init_app_waker(app_waker);
71 VARS_APP.init_modify_trace(UpdatesTrace::log_var);
72 DEADLINE_APP.init_deadline_service(crate::timer::deadline_service);
73 zng_var::types::TRANSITIONABLE_APP.init_rgba_lerp(zng_color::lerp_rgba);
74
75 let mut info = AppExtensionsInfo::start();
76 {
77 let _t = INSTANT_APP.pause_for_update();
78 extensions.register(&mut info);
79 }
80 let device_events = extensions.enable_device_events();
81
82 {
83 let mut sv = APP_PROCESS_SV.write();
84 sv.set_extensions(info, device_events);
85 }
86
87 if with_renderer && view_process_exe.is_none() {
88 zng_env::assert_inited();
89 }
90
91 #[cfg(not(target_arch = "wasm32"))]
92 let view_process_exe = view_process_exe.unwrap_or_else(|| std::env::current_exe().expect("current_exe"));
93 #[cfg(target_arch = "wasm32")]
94 let view_process_exe = std::path::PathBuf::from("<wasm>");
95
96 let process = AppIntrinsic::pre_init(is_headed, with_renderer, view_process_exe, view_process_env, device_events);
97
98 {
99 let _s = tracing::debug_span!("extensions.init").entered();
100 extensions.init();
101 }
102
103 let args = AppStartArgs { _private: () };
104 for h in zng_unique_id::hot_static_ref!(ON_APP_START).lock().iter_mut() {
105 h(&args)
106 }
107
108 RunningApp {
109 extensions: (process, extensions),
110
111 receiver,
112
113 loop_timer: LoopTimer::default(),
114 loop_monitor: LoopMonitor::default(),
115
116 pending_view_events: Vec::with_capacity(100),
117 pending_view_frame_events: Vec::with_capacity(5),
118 pending: ContextUpdates {
119 events: Vec::with_capacity(100),
120 update: false,
121 info: false,
122 layout: false,
123 render: false,
124 update_widgets: WidgetUpdates::default(),
125 info_widgets: InfoUpdates::default(),
126 layout_widgets: LayoutUpdates::default(),
127 render_widgets: RenderUpdates::default(),
128 render_update_widgets: RenderUpdates::default(),
129 },
130 exited: false,
131
132 _scope: scope,
133 }
134 }
135
136 pub fn has_exited(&self) -> bool {
137 self.exited
138 }
139
140 pub fn notify_event<O: AppEventObserver>(&mut self, mut update: EventUpdate, observer: &mut O) {
142 let _scope = tracing::trace_span!("notify_event", event = update.event().name()).entered();
143
144 let _t = INSTANT_APP.pause_for_update();
145
146 update.event().on_update(&mut update);
147
148 self.extensions.event_preview(&mut update);
149 observer.event_preview(&mut update);
150 update.call_pre_actions();
151
152 self.extensions.event_ui(&mut update);
153 observer.event_ui(&mut update);
154
155 self.extensions.event(&mut update);
156 observer.event(&mut update);
157 update.call_pos_actions();
158 }
159
160 fn input_device_id(&mut self, id: zng_view_api::raw_input::InputDeviceId) -> InputDeviceId {
161 VIEW_PROCESS.input_device_id(id)
162 }
163
164 fn on_view_event<O: AppEventObserver>(&mut self, ev: zng_view_api::Event, observer: &mut O) {
166 use crate::view_process::raw_device_events::*;
167 use crate::view_process::raw_events::*;
168 use zng_view_api::Event;
169
170 fn window_id(id: zng_view_api::window::WindowId) -> WindowId {
171 WindowId::from_raw(id.get())
172 }
173
174 #[allow(deprecated)] match ev {
176 Event::MouseMoved {
177 window: w_id,
178 device: d_id,
179 coalesced_pos,
180 position,
181 } => {
182 let args = RawMouseMovedArgs::now(window_id(w_id), self.input_device_id(d_id), coalesced_pos, position);
183 self.notify_event(RAW_MOUSE_MOVED_EVENT.new_update(args), observer);
184 }
185 Event::MouseEntered {
186 window: w_id,
187 device: d_id,
188 } => {
189 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
190 self.notify_event(RAW_MOUSE_ENTERED_EVENT.new_update(args), observer);
191 }
192 Event::MouseLeft {
193 window: w_id,
194 device: d_id,
195 } => {
196 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
197 self.notify_event(RAW_MOUSE_LEFT_EVENT.new_update(args), observer);
198 }
199 Event::WindowChanged(c) => {
200 let monitor_id = c.monitor.map(|id| VIEW_PROCESS.monitor_id(id));
201 let args = RawWindowChangedArgs::now(
202 window_id(c.window),
203 c.state,
204 c.position,
205 monitor_id,
206 c.size,
207 c.safe_padding,
208 c.cause,
209 c.frame_wait_id,
210 );
211 self.notify_event(RAW_WINDOW_CHANGED_EVENT.new_update(args), observer);
212 }
213 Event::DragHovered { window, data, allowed } => {
214 let args = RawDragHoveredArgs::now(window_id(window), data, allowed);
215 self.notify_event(RAW_DRAG_HOVERED_EVENT.new_update(args), observer);
216 }
217 Event::DragMoved {
218 window,
219 coalesced_pos,
220 position,
221 } => {
222 let args = RawDragMovedArgs::now(window_id(window), coalesced_pos, position);
223 self.notify_event(RAW_DRAG_MOVED_EVENT.new_update(args), observer);
224 }
225 Event::DragDropped {
226 window,
227 data,
228 allowed,
229 drop_id,
230 } => {
231 let args = RawDragDroppedArgs::now(window_id(window), data, allowed, drop_id);
232 self.notify_event(RAW_DRAG_DROPPED_EVENT.new_update(args), observer);
233 }
234 Event::DragCancelled { window } => {
235 let args = RawDragCancelledArgs::now(window_id(window));
236 self.notify_event(RAW_DRAG_CANCELLED_EVENT.new_update(args), observer);
237 }
238 Event::AppDragEnded { window, drag, applied } => {
239 let args = RawAppDragEndedArgs::now(window_id(window), drag, applied);
240 self.notify_event(RAW_APP_DRAG_ENDED_EVENT.new_update(args), observer);
241 }
242 Event::FocusChanged { prev, new } => {
243 let args = RawWindowFocusArgs::now(prev.map(window_id), new.map(window_id));
244 self.notify_event(RAW_WINDOW_FOCUS_EVENT.new_update(args), observer);
245 }
246 Event::KeyboardInput {
247 window: w_id,
248 device: d_id,
249 key_code,
250 state,
251 key,
252 key_location,
253 key_modified,
254 text,
255 } => {
256 let args = RawKeyInputArgs::now(
257 window_id(w_id),
258 self.input_device_id(d_id),
259 key_code,
260 key_location,
261 state,
262 key,
263 key_modified,
264 text,
265 );
266 self.notify_event(RAW_KEY_INPUT_EVENT.new_update(args), observer);
267 }
268 Event::Ime { window: w_id, ime } => {
269 let args = RawImeArgs::now(window_id(w_id), ime);
270 self.notify_event(RAW_IME_EVENT.new_update(args), observer);
271 }
272
273 Event::MouseWheel {
274 window: w_id,
275 device: d_id,
276 delta,
277 phase,
278 } => {
279 let args = RawMouseWheelArgs::now(window_id(w_id), self.input_device_id(d_id), delta, phase);
280 self.notify_event(RAW_MOUSE_WHEEL_EVENT.new_update(args), observer);
281 }
282 Event::MouseInput {
283 window: w_id,
284 device: d_id,
285 state,
286 button,
287 } => {
288 let args = RawMouseInputArgs::now(window_id(w_id), self.input_device_id(d_id), state, button);
289 self.notify_event(RAW_MOUSE_INPUT_EVENT.new_update(args), observer);
290 }
291 Event::TouchpadPressure {
292 window: w_id,
293 device: d_id,
294 pressure,
295 stage,
296 } => {
297 let args = RawTouchpadPressureArgs::now(window_id(w_id), self.input_device_id(d_id), pressure, stage);
298 self.notify_event(RAW_TOUCHPAD_PRESSURE_EVENT.new_update(args), observer);
299 }
300 Event::AxisMotion {
301 window: w_id,
302 device: d_id,
303 axis,
304 value,
305 } => {
306 let args = RawAxisMotionArgs::now(window_id(w_id), self.input_device_id(d_id), axis, value);
307 self.notify_event(RAW_AXIS_MOTION_EVENT.new_update(args), observer);
308 }
309 Event::Touch {
310 window: w_id,
311 device: d_id,
312 touches,
313 } => {
314 let args = RawTouchArgs::now(window_id(w_id), self.input_device_id(d_id), touches);
315 self.notify_event(RAW_TOUCH_EVENT.new_update(args), observer);
316 }
317 Event::ScaleFactorChanged {
318 monitor: id,
319 windows,
320 scale_factor,
321 } => {
322 let monitor_id = VIEW_PROCESS.monitor_id(id);
323 let windows: Vec<_> = windows.into_iter().map(window_id).collect();
324 let args = RawScaleFactorChangedArgs::now(monitor_id, windows, scale_factor);
325 self.notify_event(RAW_SCALE_FACTOR_CHANGED_EVENT.new_update(args), observer);
326 }
327 Event::MonitorsChanged(monitors) => {
328 let monitors: Vec<_> = monitors.into_iter().map(|(id, info)| (VIEW_PROCESS.monitor_id(id), info)).collect();
329 let args = RawMonitorsChangedArgs::now(monitors);
330 self.notify_event(RAW_MONITORS_CHANGED_EVENT.new_update(args), observer);
331 }
332 Event::AudioDevicesChanged(_audio_devices) => {
333 }
335 Event::WindowCloseRequested(w_id) => {
336 let args = RawWindowCloseRequestedArgs::now(window_id(w_id));
337 self.notify_event(RAW_WINDOW_CLOSE_REQUESTED_EVENT.new_update(args), observer);
338 }
339 Event::WindowOpened(w_id, data) => {
340 let w_id = window_id(w_id);
341 let (window, data) = VIEW_PROCESS.on_window_opened(w_id, data);
342 let args = RawWindowOpenArgs::now(w_id, window, data);
343 self.notify_event(RAW_WINDOW_OPEN_EVENT.new_update(args), observer);
344 }
345 Event::HeadlessOpened(w_id, data) => {
346 let w_id = window_id(w_id);
347 let (surface, data) = VIEW_PROCESS.on_headless_opened(w_id, data);
348 let args = RawHeadlessOpenArgs::now(w_id, surface, data);
349 self.notify_event(RAW_HEADLESS_OPEN_EVENT.new_update(args), observer);
350 }
351 Event::WindowOrHeadlessOpenError { id: w_id, error } => {
352 let w_id = window_id(w_id);
353 let args = RawWindowOrHeadlessOpenErrorArgs::now(w_id, error);
354 self.notify_event(RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.new_update(args), observer);
355 }
356 Event::WindowClosed(w_id) => {
357 let args = RawWindowCloseArgs::now(window_id(w_id));
358 self.notify_event(RAW_WINDOW_CLOSE_EVENT.new_update(args), observer);
359 }
360 Event::ImageMetadataLoaded {
361 image: id,
362 size,
363 ppi,
364 is_mask,
365 } => {
366 if let Some(img) = VIEW_PROCESS.on_image_metadata_loaded(id, size, ppi, is_mask) {
367 let args = RawImageArgs::now(img);
368 self.notify_event(RAW_IMAGE_METADATA_LOADED_EVENT.new_update(args), observer);
369 }
370 }
371 Event::ImagePartiallyLoaded {
372 image: id,
373 partial_size,
374 ppi,
375 is_opaque,
376 is_mask,
377 partial_pixels: partial_bgra8,
378 } => {
379 if let Some(img) = VIEW_PROCESS.on_image_partially_loaded(id, partial_size, ppi, is_opaque, is_mask, partial_bgra8) {
380 let args = RawImageArgs::now(img);
381 self.notify_event(RAW_IMAGE_PARTIALLY_LOADED_EVENT.new_update(args), observer);
382 }
383 }
384 Event::ImageLoaded(image) => {
385 if let Some(img) = VIEW_PROCESS.on_image_loaded(image) {
386 let args = RawImageArgs::now(img);
387 self.notify_event(RAW_IMAGE_LOADED_EVENT.new_update(args), observer);
388 }
389 }
390 Event::ImageLoadError { image: id, error } => {
391 if let Some(img) = VIEW_PROCESS.on_image_error(id, error) {
392 let args = RawImageArgs::now(img);
393 self.notify_event(RAW_IMAGE_LOAD_ERROR_EVENT.new_update(args), observer);
394 }
395 }
396 Event::ImageEncoded { image: id, format, data } => VIEW_PROCESS.on_image_encoded(id, format, data),
397 Event::ImageEncodeError { image: id, format, error } => {
398 VIEW_PROCESS.on_image_encode_error(id, format, error);
399 }
400 Event::FrameImageReady {
401 window: w_id,
402 frame: frame_id,
403 image: image_id,
404 selection,
405 } => {
406 if let Some(img) = VIEW_PROCESS.on_frame_image_ready(image_id) {
407 let args = RawFrameImageReadyArgs::now(img, window_id(w_id), frame_id, selection);
408 self.notify_event(RAW_FRAME_IMAGE_READY_EVENT.new_update(args), observer);
409 }
410 }
411
412 Event::AccessInit { window: w_id } => {
413 self.notify_event(crate::access::on_access_init(window_id(w_id)), observer);
414 }
415 Event::AccessCommand {
416 window: win_id,
417 target: wgt_id,
418 command,
419 } => {
420 if let Some(update) = crate::access::on_access_command(window_id(win_id), WidgetId::from_raw(wgt_id.0), command) {
421 self.notify_event(update, observer);
422 }
423 }
424 Event::AccessDeinit { window: w_id } => {
425 self.notify_event(crate::access::on_access_deinit(window_id(w_id)), observer);
426 }
427
428 Event::MsgDialogResponse(id, response) => {
430 VIEW_PROCESS.on_message_dlg_response(id, response);
431 }
432 Event::FileDialogResponse(id, response) => {
433 VIEW_PROCESS.on_file_dlg_response(id, response);
434 }
435
436 Event::ExtensionEvent(id, payload) => {
438 let args = RawExtensionEventArgs::now(id, payload);
439 self.notify_event(RAW_EXTENSION_EVENT.new_update(args), observer);
440 }
441
442 Event::FontsChanged => {
444 let args = RawFontChangedArgs::now();
445 self.notify_event(RAW_FONT_CHANGED_EVENT.new_update(args), observer);
446 }
447 Event::FontAaChanged(aa) => {
448 let args = RawFontAaChangedArgs::now(aa);
449 self.notify_event(RAW_FONT_AA_CHANGED_EVENT.new_update(args), observer);
450 }
451 Event::MultiClickConfigChanged(cfg) => {
452 let args = RawMultiClickConfigChangedArgs::now(cfg);
453 self.notify_event(RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT.new_update(args), observer);
454 }
455 Event::AnimationsConfigChanged(cfg) => {
456 VARS_APP.set_sys_animations_enabled(cfg.enabled);
457 let args = RawAnimationsConfigChangedArgs::now(cfg);
458 self.notify_event(RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.new_update(args), observer);
459 }
460 Event::KeyRepeatConfigChanged(cfg) => {
461 let args = RawKeyRepeatConfigChangedArgs::now(cfg);
462 self.notify_event(RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.new_update(args), observer);
463 }
464 Event::TouchConfigChanged(cfg) => {
465 let args = RawTouchConfigChangedArgs::now(cfg);
466 self.notify_event(RAW_TOUCH_CONFIG_CHANGED_EVENT.new_update(args), observer);
467 }
468 Event::LocaleChanged(cfg) => {
469 let args = RawLocaleChangedArgs::now(cfg);
470 self.notify_event(RAW_LOCALE_CONFIG_CHANGED_EVENT.new_update(args), observer);
471 }
472 Event::ColorsConfigChanged(cfg) => {
473 let args = RawColorsConfigChangedArgs::now(cfg);
474 self.notify_event(RAW_COLORS_CONFIG_CHANGED_EVENT.new_update(args), observer);
475 }
476 Event::ChromeConfigChanged(cfg) => {
477 let args = RawChromeConfigChangedArgs::now(cfg);
478 self.notify_event(RAW_CHROME_CONFIG_CHANGED_EVENT.new_update(args), observer);
479 }
480
481 Event::InputDevicesChanged(devices) => {
483 let devices: HashMap<_, _> = devices.into_iter().map(|(d_id, info)| (self.input_device_id(d_id), info)).collect();
484 INPUT_DEVICES.update(devices.clone());
485 let args = InputDevicesChangedArgs::now(devices);
486 self.notify_event(INPUT_DEVICES_CHANGED_EVENT.new_update(args), observer);
487 }
488 Event::InputDeviceEvent { device, event } => {
489 let d_id = self.input_device_id(device);
490 match event {
491 InputDeviceEvent::PointerMotion { delta } => {
492 let args = PointerMotionArgs::now(d_id, delta);
493 self.notify_event(POINTER_MOTION_EVENT.new_update(args), observer);
494 }
495 InputDeviceEvent::ScrollMotion { delta } => {
496 let args = ScrollMotionArgs::now(d_id, delta);
497 self.notify_event(SCROLL_MOTION_EVENT.new_update(args), observer);
498 }
499 InputDeviceEvent::AxisMotion { axis, value } => {
500 let args = AxisMotionArgs::now(d_id, axis, value);
501 self.notify_event(AXIS_MOTION_EVENT.new_update(args), observer);
502 }
503 InputDeviceEvent::Button { button, state } => {
504 let args = ButtonArgs::now(d_id, button, state);
505 self.notify_event(BUTTON_EVENT.new_update(args), observer);
506 }
507 InputDeviceEvent::Key { key_code, state } => {
508 let args = KeyArgs::now(d_id, key_code, state);
509 self.notify_event(KEY_EVENT.new_update(args), observer);
510 }
511 _ => {}
512 }
513 }
514
515 Event::DeviceAdded(d_id) => {
516 let args = DeviceArgs::now(self.input_device_id(d_id));
517 self.notify_event(DEVICE_ADDED_EVENT.new_update(args), observer);
518 }
519 Event::DeviceRemoved(d_id) => {
520 let args = DeviceArgs::now(self.input_device_id(d_id));
521 self.notify_event(DEVICE_REMOVED_EVENT.new_update(args), observer);
522 }
523 Event::DeviceMouseMotion { device: d_id, delta } => {
524 let args = MouseMotionArgs::now(self.input_device_id(d_id), delta);
525 self.notify_event(MOUSE_MOTION_EVENT.new_update(args), observer);
526 }
527 Event::DeviceMouseWheel { device: d_id, delta } => {
528 let args = MouseWheelArgs::now(self.input_device_id(d_id), delta);
529 self.notify_event(MOUSE_WHEEL_EVENT.new_update(args), observer);
530 }
531 Event::DeviceMotion { device: d_id, axis, value } => {
532 let args = MotionArgs::now(self.input_device_id(d_id), axis, value);
533 self.notify_event(MOTION_EVENT.new_update(args), observer);
534 }
535 Event::DeviceButton {
536 device: d_id,
537 button,
538 state,
539 } => {
540 let args = ButtonArgs::now(self.input_device_id(d_id), button, state);
541 self.notify_event(BUTTON_EVENT.new_update(args), observer);
542 }
543 Event::DeviceKey {
544 device: d_id,
545 key_code,
546 state,
547 } => {
548 let args = KeyArgs::now(self.input_device_id(d_id), key_code, state);
549 self.notify_event(KEY_EVENT.new_update(args), observer);
550 }
551
552 Event::LowMemory => {
553 LOW_MEMORY_EVENT.notify(LowMemoryArgs::now());
554 }
555
556 Event::RecoveredFromComponentPanic { component, recover, panic } => {
557 tracing::error!(
558 "view-process recovered from internal component panic\n component: {component}\n recover: {recover}\n```panic\n{panic}\n```"
559 );
560 }
561
562 Event::Inited(zng_view_api::Inited { .. }) | Event::Suspended | Event::Disconnected(_) | Event::FrameRendered(_) => {
564 unreachable!()
565 } _ => {}
568 }
569 }
570
571 fn on_view_rendered_event<O: AppEventObserver>(&mut self, ev: zng_view_api::window::EventFrameRendered, observer: &mut O) {
573 debug_assert!(ev.window != zng_view_api::window::WindowId::INVALID);
574 let window_id = WindowId::from_raw(ev.window.get());
575 let image = ev.frame_image.map(|img| VIEW_PROCESS.on_frame_image(img));
577 let args = crate::view_process::raw_events::RawFrameRenderedArgs::now(window_id, ev.frame, image);
578 self.notify_event(crate::view_process::raw_events::RAW_FRAME_RENDERED_EVENT.new_update(args), observer);
579 }
580
581 pub(crate) fn run_headed(mut self) {
582 let mut observer = ();
583 #[cfg(feature = "dyn_app_extension")]
584 let mut observer = observer.as_dyn();
585
586 self.apply_updates(&mut observer);
587 self.apply_update_events(&mut observer);
588 let mut wait = false;
589 loop {
590 wait = match self.poll_impl(wait, &mut observer) {
591 AppControlFlow::Poll => false,
592 AppControlFlow::Wait => true,
593 AppControlFlow::Exit => break,
594 };
595 }
596 }
597
598 fn push_coalesce<O: AppEventObserver>(&mut self, ev: AppEvent, observer: &mut O) {
599 match ev {
600 AppEvent::ViewEvent(ev) => match ev {
601 zng_view_api::Event::FrameRendered(ev) => {
602 if ev.window == zng_view_api::window::WindowId::INVALID {
603 tracing::error!("ignored rendered event for invalid window id, {ev:?}");
604 return;
605 }
606
607 let window = WindowId::from_raw(ev.window.get());
608
609 {
611 if VIEW_PROCESS.is_available() {
612 VIEW_PROCESS.on_frame_rendered(window);
613 }
614 }
615
616 #[cfg(debug_assertions)]
617 if self.pending_view_frame_events.iter().any(|e| e.window == ev.window) {
618 tracing::warn!("window `{window:?}` probably sent a frame request without awaiting renderer idle");
619 }
620
621 self.pending_view_frame_events.push(ev);
622 }
623 zng_view_api::Event::Inited(zng_view_api::Inited {
624 generation,
625 is_respawn,
626 available_monitors,
627 available_input_devices,
628 multi_click_config,
629 key_repeat_config,
630 touch_config,
631 font_aa,
632 animations_config,
633 locale_config,
634 colors_config,
635 chrome_config,
636 extensions,
637 ..
638 }) => {
639 if is_respawn {
641 VIEW_PROCESS.on_respawned(generation);
642 APP_PROCESS_SV.read().is_suspended.set(false);
643 }
644
645 VIEW_PROCESS.handle_inited(generation, extensions.clone());
646
647 let monitors: Vec<_> = available_monitors
648 .into_iter()
649 .map(|(id, info)| (VIEW_PROCESS.monitor_id(id), info))
650 .collect();
651
652 VARS.animations_enabled().set(animations_config.enabled);
653
654 let args = crate::view_process::ViewProcessInitedArgs::now(
655 generation,
656 is_respawn,
657 monitors,
658 multi_click_config,
659 key_repeat_config,
660 touch_config,
661 font_aa,
662 animations_config,
663 locale_config,
664 colors_config,
665 chrome_config,
666 extensions,
667 );
668 self.notify_event(VIEW_PROCESS_INITED_EVENT.new_update(args), observer);
669
670 let devices: HashMap<_, _> = available_input_devices
671 .into_iter()
672 .map(|(d_id, info)| (self.input_device_id(d_id), info))
673 .collect();
674 INPUT_DEVICES.update(devices);
675 }
676 zng_view_api::Event::Suspended => {
677 VIEW_PROCESS.handle_suspended();
678 let args = crate::view_process::ViewProcessSuspendedArgs::now();
679 self.notify_event(VIEW_PROCESS_SUSPENDED_EVENT.new_update(args), observer);
680 APP_PROCESS_SV.read().is_suspended.set(true);
681 }
682 zng_view_api::Event::Disconnected(vp_gen) => {
683 VIEW_PROCESS.handle_disconnect(vp_gen);
685 }
686 ev => {
687 if let Some(last) = self.pending_view_events.last_mut() {
688 match last.coalesce(ev) {
689 Ok(()) => {}
690 Err(ev) => self.pending_view_events.push(ev),
691 }
692 } else {
693 self.pending_view_events.push(ev);
694 }
695 }
696 },
697 AppEvent::Event(ev) => EVENTS.notify(ev.get()),
698 AppEvent::Update(op, target) => {
699 UPDATES.update_op(op, target);
700 }
701 AppEvent::CheckUpdate => {}
702 AppEvent::ResumeUnwind(p) => std::panic::resume_unwind(p),
703 }
704 }
705
706 fn has_pending_updates(&mut self) -> bool {
707 !self.pending_view_events.is_empty() || self.pending.has_updates() || UPDATES.has_pending_updates() || !self.receiver.is_empty()
708 }
709
710 pub(crate) fn poll<O: AppEventObserver>(&mut self, wait_app_event: bool, observer: &mut O) -> AppControlFlow {
711 #[cfg(feature = "dyn_app_extension")]
712 let mut observer = observer.as_dyn();
713 #[cfg(feature = "dyn_app_extension")]
714 let observer = &mut observer;
715 self.poll_impl(wait_app_event, observer)
716 }
717 fn poll_impl<O: AppEventObserver>(&mut self, wait_app_event: bool, observer: &mut O) -> AppControlFlow {
718 let mut disconnected = false;
719
720 if self.exited {
721 return AppControlFlow::Exit;
722 }
723
724 if wait_app_event {
725 let idle = tracing::debug_span!("<idle>", ended_by = tracing::field::Empty).entered();
726
727 let timer = if self.view_is_busy() { None } else { self.loop_timer.poll() };
728 if let Some(time) = timer {
729 match self.receiver.recv_deadline_sp(time) {
730 Ok(ev) => {
731 idle.record("ended_by", "event");
732 drop(idle);
733 self.push_coalesce(ev, observer)
734 }
735 Err(e) => match e {
736 flume::RecvTimeoutError::Timeout => {
737 idle.record("ended_by", "timeout");
738 }
739 flume::RecvTimeoutError::Disconnected => {
740 idle.record("ended_by", "disconnected");
741 disconnected = true
742 }
743 },
744 }
745 } else {
746 match self.receiver.recv() {
747 Ok(ev) => {
748 idle.record("ended_by", "event");
749 drop(idle);
750 self.push_coalesce(ev, observer)
751 }
752 Err(e) => match e {
753 flume::RecvError::Disconnected => {
754 idle.record("ended_by", "disconnected");
755 disconnected = true
756 }
757 },
758 }
759 }
760 }
761 loop {
762 match self.receiver.try_recv() {
763 Ok(ev) => self.push_coalesce(ev, observer),
764 Err(e) => match e {
765 flume::TryRecvError::Empty => break,
766 flume::TryRecvError::Disconnected => {
767 disconnected = true;
768 break;
769 }
770 },
771 }
772 }
773 if disconnected {
774 panic!("app events channel disconnected");
775 }
776
777 if self.view_is_busy() {
778 return AppControlFlow::Wait;
779 }
780
781 UPDATES.on_app_awake();
782
783 let updated_timers = self.loop_timer.awake();
785 if updated_timers {
786 UPDATES.update_timers(&mut self.loop_timer);
788 self.apply_updates(observer);
789 }
790
791 let mut events = mem::take(&mut self.pending_view_events);
792 for ev in events.drain(..) {
793 self.on_view_event(ev, observer);
794 self.apply_updates(observer);
795 }
796 debug_assert!(self.pending_view_events.is_empty());
797 self.pending_view_events = events; let mut events = mem::take(&mut self.pending_view_frame_events);
800 for ev in events.drain(..) {
801 self.on_view_rendered_event(ev, observer);
802 }
803 self.pending_view_frame_events = events;
804
805 if self.has_pending_updates() {
806 self.apply_updates(observer);
807 self.apply_update_events(observer);
808 }
809
810 if self.view_is_busy() {
811 return AppControlFlow::Wait;
812 }
813
814 self.finish_frame(observer);
815
816 UPDATES.next_deadline(&mut self.loop_timer);
817
818 if self.extensions.0.exit() {
819 UPDATES.on_app_sleep();
820 self.exited = true;
821 AppControlFlow::Exit
822 } else if self.has_pending_updates() || UPDATES.has_pending_layout_or_render() {
823 AppControlFlow::Poll
824 } else {
825 UPDATES.on_app_sleep();
826 AppControlFlow::Wait
827 }
828 }
829
830 fn apply_updates<O: AppEventObserver>(&mut self, observer: &mut O) {
832 let _s = tracing::debug_span!("apply_updates").entered();
833
834 let mut run = true;
835 while run {
836 run = self.loop_monitor.update(|| {
837 let mut any = false;
838
839 self.pending |= UPDATES.apply_info();
840 if mem::take(&mut self.pending.info) {
841 any = true;
842 let _s = tracing::debug_span!("info").entered();
843
844 let mut info_widgets = mem::take(&mut self.pending.info_widgets);
845
846 let _t = INSTANT_APP.pause_for_update();
847
848 {
849 let _s = tracing::debug_span!("ext.info").entered();
850 self.extensions.info(&mut info_widgets);
851 }
852 {
853 let _s = tracing::debug_span!("obs.info").entered();
854 observer.info(&mut info_widgets);
855 }
856 }
857
858 self.pending |= UPDATES.apply_updates();
859 TimersService::notify();
860 if mem::take(&mut self.pending.update) {
861 any = true;
862 let _s = tracing::debug_span!("update").entered();
863
864 let mut update_widgets = mem::take(&mut self.pending.update_widgets);
865
866 let _t = INSTANT_APP.pause_for_update();
867
868 {
869 let _s = tracing::debug_span!("ext.update_preview").entered();
870 self.extensions.update_preview();
871 }
872 {
873 let _s = tracing::debug_span!("obs.update_preview").entered();
874 observer.update_preview();
875 }
876 UPDATES.on_pre_updates();
877
878 {
879 let _s = tracing::debug_span!("ext.update_ui").entered();
880 self.extensions.update_ui(&mut update_widgets);
881 }
882 {
883 let _s = tracing::debug_span!("obs.update_ui").entered();
884 observer.update_ui(&mut update_widgets);
885 }
886
887 {
888 let _s = tracing::debug_span!("ext.update").entered();
889 self.extensions.update();
890 }
891 {
892 let _s = tracing::debug_span!("obs.update").entered();
893 observer.update();
894 }
895 UPDATES.on_updates();
896 }
897
898 any
899 });
900 }
901 }
902
903 fn apply_update_events<O: AppEventObserver>(&mut self, observer: &mut O) {
905 let _s = tracing::debug_span!("apply_update_events").entered();
906
907 loop {
908 let events: Vec<_> = self.pending.events.drain(..).collect();
909 if events.is_empty() {
910 break;
911 }
912 for mut update in events {
913 let _s = tracing::debug_span!("update_event", ?update).entered();
914
915 self.loop_monitor.maybe_trace(|| {
916 let _t = INSTANT_APP.pause_for_update();
917
918 {
919 let _s = tracing::debug_span!("ext.event_preview").entered();
920 self.extensions.event_preview(&mut update);
921 }
922 {
923 let _s = tracing::debug_span!("obs.event_preview").entered();
924 observer.event_preview(&mut update);
925 }
926 update.call_pre_actions();
927
928 {
929 let _s = tracing::debug_span!("ext.event_ui").entered();
930 self.extensions.event_ui(&mut update);
931 }
932 {
933 let _s = tracing::debug_span!("obs.event_ui").entered();
934 observer.event_ui(&mut update);
935 }
936 {
937 let _s = tracing::debug_span!("ext.event").entered();
938 self.extensions.event(&mut update);
939 }
940 {
941 let _s = tracing::debug_span!("obs.event").entered();
942 observer.event(&mut update);
943 }
944 update.call_pos_actions();
945 });
946
947 self.apply_updates(observer);
948 }
949 }
950 }
951
952 fn view_is_busy(&mut self) -> bool {
953 VIEW_PROCESS.is_available() && VIEW_PROCESS.pending_frames() > 0
954 }
955
956 fn finish_frame<O: AppEventObserver>(&mut self, observer: &mut O) {
958 debug_assert!(!self.view_is_busy());
959
960 self.pending |= UPDATES.apply_layout_render();
961
962 while mem::take(&mut self.pending.layout) {
963 let _s = tracing::debug_span!("apply_layout").entered();
964
965 let mut layout_widgets = mem::take(&mut self.pending.layout_widgets);
966
967 self.loop_monitor.maybe_trace(|| {
968 let _t = INSTANT_APP.pause_for_update();
969
970 {
971 let _s = tracing::debug_span!("ext.layout").entered();
972 self.extensions.layout(&mut layout_widgets);
973 }
974 {
975 let _s = tracing::debug_span!("obs.layout").entered();
976 observer.layout(&mut layout_widgets);
977 }
978 });
979
980 self.apply_updates(observer);
981 self.pending |= UPDATES.apply_layout_render();
982 }
983
984 if mem::take(&mut self.pending.render) {
985 let _s = tracing::debug_span!("apply_render").entered();
986
987 let mut render_widgets = mem::take(&mut self.pending.render_widgets);
988 let mut render_update_widgets = mem::take(&mut self.pending.render_update_widgets);
989
990 let _t = INSTANT_APP.pause_for_update();
991
992 {
993 let _s = tracing::debug_span!("ext.render").entered();
994 self.extensions.render(&mut render_widgets, &mut render_update_widgets);
995 }
996 {
997 let _s = tracing::debug_span!("obs.render").entered();
998 observer.render(&mut render_widgets, &mut render_update_widgets);
999 }
1000 }
1001
1002 self.loop_monitor.finish_frame();
1003 }
1004}
1005impl<E: AppExtension> Drop for RunningApp<E> {
1006 fn drop(&mut self) {
1007 let _s = tracing::debug_span!("ext.deinit").entered();
1008 self.extensions.deinit();
1009 VIEW_PROCESS.exit();
1010 }
1011}
1012
1013pub struct AppStartArgs {
1018 _private: (),
1019}
1020
1021pub fn on_app_start(handler: impl FnMut(&AppStartArgs) + Send + 'static) {
1027 zng_unique_id::hot_static_ref!(ON_APP_START).lock().push(Box::new(handler))
1028}
1029zng_unique_id::hot_static! {
1030 static ON_APP_START: Mutex<Vec<AppStartHandler>> = Mutex::new(vec![]);
1031}
1032type AppStartHandler = Box<dyn FnMut(&AppStartArgs) + Send + 'static>;
1033
1034#[derive(Debug)]
1036pub(crate) struct LoopTimer {
1037 now: DInstant,
1038 deadline: Option<Deadline>,
1039}
1040impl Default for LoopTimer {
1041 fn default() -> Self {
1042 Self {
1043 now: INSTANT.now(),
1044 deadline: None,
1045 }
1046 }
1047}
1048impl LoopTimer {
1049 pub fn elapsed(&mut self, deadline: Deadline) -> bool {
1052 if deadline.0 <= self.now {
1053 true
1054 } else {
1055 self.register(deadline);
1056 false
1057 }
1058 }
1059
1060 pub fn register(&mut self, deadline: Deadline) {
1062 if let Some(d) = &mut self.deadline {
1063 if deadline < *d {
1064 *d = deadline;
1065 }
1066 } else {
1067 self.deadline = Some(deadline)
1068 }
1069 }
1070
1071 pub(crate) fn poll(&mut self) -> Option<Deadline> {
1073 self.deadline
1074 }
1075
1076 pub(crate) fn awake(&mut self) -> bool {
1078 self.now = INSTANT.now();
1079 if let Some(d) = self.deadline {
1080 if d.0 <= self.now {
1081 self.deadline = None;
1082 return true;
1083 }
1084 }
1085 false
1086 }
1087
1088 pub fn now(&self) -> DInstant {
1090 self.now
1091 }
1092}
1093impl zng_var::animation::AnimationTimer for LoopTimer {
1094 fn elapsed(&mut self, deadline: Deadline) -> bool {
1095 self.elapsed(deadline)
1096 }
1097
1098 fn register(&mut self, deadline: Deadline) {
1099 self.register(deadline)
1100 }
1101
1102 fn now(&self) -> DInstant {
1103 self.now()
1104 }
1105}
1106
1107#[derive(Default)]
1108struct LoopMonitor {
1109 update_count: u16,
1110 skipped: bool,
1111 trace: Vec<UpdateTrace>,
1112}
1113impl LoopMonitor {
1114 pub fn update(&mut self, update_once: impl FnOnce() -> bool) -> bool {
1116 self.update_count += 1;
1117
1118 if self.update_count < 500 {
1119 update_once()
1120 } else if self.update_count < 1000 {
1121 UpdatesTrace::collect_trace(&mut self.trace, update_once)
1122 } else if self.update_count == 1000 {
1123 self.skipped = true;
1124 let trace = UpdatesTrace::format_trace(mem::take(&mut self.trace));
1125 tracing::error!(
1126 "updated 1000 times without rendering, probably stuck in an infinite loop\n\
1127 will start skipping updates to render and poll system events\n\
1128 top 20 most frequent update requests (in 500 cycles):\n\
1129 {trace}\n\
1130 you can use `UpdatesTraceUiNodeExt` and `updates_trace_event` to refine the trace"
1131 );
1132 false
1133 } else if self.update_count == 1500 {
1134 self.update_count = 1001;
1135 false
1136 } else {
1137 update_once()
1138 }
1139 }
1140
1141 pub fn maybe_trace(&mut self, notify_once: impl FnOnce()) {
1142 if (500..1000).contains(&self.update_count) {
1143 UpdatesTrace::collect_trace(&mut self.trace, notify_once);
1144 } else {
1145 notify_once();
1146 }
1147 }
1148
1149 pub fn finish_frame(&mut self) {
1150 if !self.skipped {
1151 self.skipped = false;
1152 self.update_count = 0;
1153 self.trace = vec![];
1154 }
1155 }
1156}
1157
1158impl APP {
1159 pub fn exit(&self) -> ResponseVar<ExitCancelled> {
1168 APP_PROCESS_SV.write().exit()
1169 }
1170
1171 pub fn is_suspended(&self) -> ReadOnlyArcVar<bool> {
1179 APP_PROCESS_SV.read().is_suspended.read_only()
1180 }
1181}
1182
1183impl APP {
1187 pub fn pause_time_for_update(&self) -> ArcVar<bool> {
1193 APP_PROCESS_SV.read().pause_time_for_updates.clone()
1194 }
1195
1196 pub fn start_manual_time(&self) {
1204 INSTANT_APP.set_mode(InstantMode::Manual);
1205 INSTANT_APP.set_now(INSTANT.now());
1206 UPDATES.update(None);
1207 }
1208
1209 pub fn advance_manual_time(&self, advance: Duration) {
1220 INSTANT_APP.advance_now(advance);
1221 UPDATES.update(None);
1222 }
1223
1224 pub fn set_manual_time(&self, now: DInstant) {
1233 INSTANT_APP.set_now(now);
1234 UPDATES.update(None);
1235 }
1236
1237 pub fn end_manual_time(&self) {
1239 INSTANT_APP.set_mode(match APP.pause_time_for_update().get() {
1240 true => InstantMode::UpdatePaused,
1241 false => InstantMode::Now,
1242 });
1243 UPDATES.update(None);
1244 }
1245}
1246
1247command! {
1248 pub static EXIT_CMD = {
1252 l10n!: true,
1253 name: "Exit",
1254 info: "Close all windows and exit",
1255 shortcut: shortcut!(Exit),
1256 };
1257}
1258
1259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1263pub struct ExitCancelled;
1264impl fmt::Display for ExitCancelled {
1265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1266 write!(f, "exit request cancelled")
1267 }
1268}
1269
1270struct AppIntrinsic {
1271 exit_handle: CommandHandle,
1272 pending_exit: Option<PendingExit>,
1273}
1274struct PendingExit {
1275 handle: EventPropagationHandle,
1276 response: ResponderVar<ExitCancelled>,
1277}
1278impl AppIntrinsic {
1279 pub(super) fn pre_init(
1281 is_headed: bool,
1282 with_renderer: bool,
1283 view_process_exe: PathBuf,
1284 view_process_env: HashMap<Txt, Txt>,
1285 device_events: bool,
1286 ) -> Self {
1287 APP_PROCESS_SV
1288 .read()
1289 .pause_time_for_updates
1290 .hook(|a| {
1291 if !matches!(INSTANT.mode(), zng_time::InstantMode::Manual) {
1292 if *a.value() {
1293 INSTANT_APP.set_mode(InstantMode::UpdatePaused);
1294 } else {
1295 INSTANT_APP.set_mode(InstantMode::Now);
1296 }
1297 }
1298 true
1299 })
1300 .perm();
1301
1302 if is_headed {
1303 debug_assert!(with_renderer);
1304
1305 let view_evs_sender = UPDATES.sender();
1306 VIEW_PROCESS.start(view_process_exe, view_process_env, device_events, false, move |ev| {
1307 let _ = view_evs_sender.send_view_event(ev);
1308 });
1309 } else if with_renderer {
1310 let view_evs_sender = UPDATES.sender();
1311 VIEW_PROCESS.start(view_process_exe, view_process_env, false, true, move |ev| {
1312 let _ = view_evs_sender.send_view_event(ev);
1313 });
1314 }
1315
1316 AppIntrinsic {
1317 exit_handle: EXIT_CMD.subscribe(true),
1318 pending_exit: None,
1319 }
1320 }
1321
1322 pub(super) fn exit(&mut self) -> bool {
1324 if let Some(pending) = self.pending_exit.take() {
1325 if pending.handle.is_stopped() {
1326 pending.response.respond(ExitCancelled);
1327 false
1328 } else {
1329 true
1330 }
1331 } else {
1332 false
1333 }
1334 }
1335}
1336impl AppExtension for AppIntrinsic {
1337 fn event_preview(&mut self, update: &mut EventUpdate) {
1338 if let Some(args) = EXIT_CMD.on(update) {
1339 args.handle_enabled(&self.exit_handle, |_| {
1340 APP.exit();
1341 });
1342 }
1343 }
1344
1345 fn update(&mut self) {
1346 if let Some(response) = APP_PROCESS_SV.write().take_requests() {
1347 let args = ExitRequestedArgs::now();
1348 self.pending_exit = Some(PendingExit {
1349 handle: args.propagation().clone(),
1350 response,
1351 });
1352 EXIT_REQUESTED_EVENT.notify(args);
1353 }
1354 }
1355}
1356
1357pub(crate) fn assert_not_view_process() {
1358 if zng_view_api::ViewConfig::from_env().is_some() {
1359 panic!("cannot start App in view-process");
1360 }
1361}
1362
1363#[cfg(feature = "deadlock_detection")]
1364pub(crate) fn check_deadlock() {
1365 use parking_lot::deadlock;
1366 use std::{
1367 sync::atomic::{self, AtomicBool},
1368 thread,
1369 time::*,
1370 };
1371
1372 static CHECK_RUNNING: AtomicBool = AtomicBool::new(false);
1373
1374 if CHECK_RUNNING.swap(true, atomic::Ordering::SeqCst) {
1375 return;
1376 }
1377
1378 thread::spawn(|| {
1379 loop {
1380 thread::sleep(Duration::from_secs(10));
1381
1382 let deadlocks = deadlock::check_deadlock();
1383 if deadlocks.is_empty() {
1384 continue;
1385 }
1386
1387 use std::fmt::Write;
1388 let mut msg = String::new();
1389
1390 let _ = writeln!(&mut msg, "{} deadlocks detected", deadlocks.len());
1391 for (i, threads) in deadlocks.iter().enumerate() {
1392 let _ = writeln!(&mut msg, "Deadlock #{}, {} threads", i, threads.len());
1393 for t in threads {
1394 let _ = writeln!(&mut msg, "Thread Id {:#?}", t.thread_id());
1395 let _ = writeln!(&mut msg, "{:#?}", t.backtrace());
1396 }
1397 }
1398
1399 #[cfg(not(feature = "test_util"))]
1400 eprint!("{msg}");
1401
1402 #[cfg(feature = "test_util")]
1403 {
1404 use std::io::Write;
1407 let _ = write!(&mut std::io::stderr(), "{msg}");
1408 zng_env::exit(-1);
1409 }
1410 }
1411 });
1412}
1413#[cfg(not(feature = "deadlock_detection"))]
1414pub(crate) fn check_deadlock() {}
1415
1416app_local! {
1417 pub(super) static APP_PROCESS_SV: AppProcessService = AppProcessService {
1418 exit_requests: None,
1419 extensions: None,
1420 device_events: false,
1421 pause_time_for_updates: zng_var::var(true),
1422 is_suspended: zng_var::var(false),
1423 };
1424}
1425
1426pub(super) struct AppProcessService {
1427 exit_requests: Option<ResponderVar<ExitCancelled>>,
1428 extensions: Option<Arc<AppExtensionsInfo>>,
1429 pub(super) device_events: bool,
1430 pause_time_for_updates: ArcVar<bool>,
1431 is_suspended: ArcVar<bool>,
1432}
1433impl AppProcessService {
1434 pub(super) fn take_requests(&mut self) -> Option<ResponderVar<ExitCancelled>> {
1435 self.exit_requests.take()
1436 }
1437
1438 fn exit(&mut self) -> ResponseVar<ExitCancelled> {
1439 if let Some(r) = &self.exit_requests {
1440 r.response_var()
1441 } else {
1442 let (responder, response) = response_var();
1443 self.exit_requests = Some(responder);
1444 UPDATES.update(None);
1445 response
1446 }
1447 }
1448
1449 pub(super) fn extensions(&self) -> Arc<AppExtensionsInfo> {
1450 self.extensions
1451 .clone()
1452 .unwrap_or_else(|| Arc::new(AppExtensionsInfo { infos: vec![] }))
1453 }
1454
1455 pub(super) fn set_extensions(&mut self, info: AppExtensionsInfo, device_events: bool) {
1456 self.extensions = Some(Arc::new(info));
1457 self.device_events = device_events;
1458 }
1459}
1460
1461#[derive(Debug)]
1463#[allow(clippy::large_enum_variant)] pub(crate) enum AppEvent {
1465 ViewEvent(zng_view_api::Event),
1467 Event(crate::event::EventUpdateMsg),
1469 Update(UpdateOp, Option<WidgetId>),
1471 ResumeUnwind(PanicPayload),
1473 CheckUpdate,
1475}
1476
1477#[derive(Clone)]
1483pub struct AppEventSender(flume::Sender<AppEvent>);
1484impl AppEventSender {
1485 pub(crate) fn new() -> (Self, flume::Receiver<AppEvent>) {
1486 let (sender, receiver) = flume::unbounded();
1487 (Self(sender), receiver)
1488 }
1489
1490 #[allow(clippy::result_large_err)] fn send_app_event(&self, event: AppEvent) -> Result<(), AppChannelError> {
1492 self.0.send(event).map_err(|_| AppChannelError::Disconnected)
1493 }
1494
1495 #[allow(clippy::result_large_err)]
1496 fn send_view_event(&self, event: zng_view_api::Event) -> Result<(), AppChannelError> {
1497 self.0.send(AppEvent::ViewEvent(event)).map_err(|_| AppChannelError::Disconnected)
1498 }
1499
1500 pub fn send_update(&self, op: UpdateOp, target: impl Into<Option<WidgetId>>) -> Result<(), AppChannelError> {
1502 UpdatesTrace::log_update();
1503 self.send_app_event(AppEvent::Update(op, target.into()))
1504 .map_err(|_| AppChannelError::Disconnected)
1505 }
1506
1507 pub(crate) fn send_event(&self, event: crate::event::EventUpdateMsg) -> Result<(), AppChannelError> {
1509 self.send_app_event(AppEvent::Event(event))
1510 .map_err(|_| AppChannelError::Disconnected)
1511 }
1512
1513 pub fn send_resume_unwind(&self, payload: PanicPayload) -> Result<(), AppChannelError> {
1515 self.send_app_event(AppEvent::ResumeUnwind(payload))
1516 .map_err(|_| AppChannelError::Disconnected)
1517 }
1518
1519 pub(crate) fn send_check_update(&self) -> Result<(), AppChannelError> {
1521 self.send_app_event(AppEvent::CheckUpdate)
1522 .map_err(|_| AppChannelError::Disconnected)
1523 }
1524
1525 pub fn waker(&self, target: impl Into<Option<WidgetId>>) -> Waker {
1527 Arc::new(AppWaker(self.0.clone(), target.into())).into()
1528 }
1529
1530 pub fn ext_channel<T>(&self) -> (AppExtSender<T>, AppExtReceiver<T>) {
1532 let (sender, receiver) = flume::unbounded();
1533
1534 (
1535 AppExtSender {
1536 update: self.clone(),
1537 sender,
1538 },
1539 AppExtReceiver { receiver },
1540 )
1541 }
1542
1543 pub fn ext_channel_bounded<T>(&self, cap: usize) -> (AppExtSender<T>, AppExtReceiver<T>) {
1545 let (sender, receiver) = flume::bounded(cap);
1546
1547 (
1548 AppExtSender {
1549 update: self.clone(),
1550 sender,
1551 },
1552 AppExtReceiver { receiver },
1553 )
1554 }
1555}
1556
1557struct AppWaker(flume::Sender<AppEvent>, Option<WidgetId>);
1558impl std::task::Wake for AppWaker {
1559 fn wake(self: std::sync::Arc<Self>) {
1560 self.wake_by_ref()
1561 }
1562 fn wake_by_ref(self: &Arc<Self>) {
1563 let _ = self.0.send(AppEvent::Update(UpdateOp::Update, self.1));
1564 }
1565}
1566
1567type PanicPayload = Box<dyn std::any::Any + Send + 'static>;
1568
1569pub struct AppExtSender<T> {
1573 update: AppEventSender,
1574 sender: flume::Sender<T>,
1575}
1576impl<T> Clone for AppExtSender<T> {
1577 fn clone(&self) -> Self {
1578 Self {
1579 update: self.update.clone(),
1580 sender: self.sender.clone(),
1581 }
1582 }
1583}
1584impl<T: Send> AppExtSender<T> {
1585 pub fn send(&self, msg: T) -> Result<(), AppChannelError> {
1587 match self.update.send_update(UpdateOp::Update, None) {
1588 Ok(()) => self.sender.send(msg).map_err(|_| AppChannelError::Disconnected),
1589 Err(_) => Err(AppChannelError::Disconnected),
1590 }
1591 }
1592
1593 pub fn send_timeout(&self, msg: T, dur: Duration) -> Result<(), AppChannelError> {
1595 match self.update.send_update(UpdateOp::Update, None) {
1596 Ok(()) => self.sender.send_timeout(msg, dur).map_err(|e| match e {
1597 flume::SendTimeoutError::Timeout(_) => AppChannelError::Timeout,
1598 flume::SendTimeoutError::Disconnected(_) => AppChannelError::Disconnected,
1599 }),
1600 Err(_) => Err(AppChannelError::Disconnected),
1601 }
1602 }
1603
1604 pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), AppChannelError> {
1606 match self.update.send_update(UpdateOp::Update, None) {
1607 Ok(()) => self.sender.send_deadline(msg, deadline).map_err(|e| match e {
1608 flume::SendTimeoutError::Timeout(_) => AppChannelError::Timeout,
1609 flume::SendTimeoutError::Disconnected(_) => AppChannelError::Disconnected,
1610 }),
1611 Err(_) => Err(AppChannelError::Disconnected),
1612 }
1613 }
1614}
1615
1616pub struct AppExtReceiver<T> {
1620 receiver: flume::Receiver<T>,
1621}
1622impl<T> Clone for AppExtReceiver<T> {
1623 fn clone(&self) -> Self {
1624 Self {
1625 receiver: self.receiver.clone(),
1626 }
1627 }
1628}
1629impl<T> AppExtReceiver<T> {
1630 pub fn try_recv(&self) -> Result<T, Option<AppChannelError>> {
1635 self.receiver.try_recv().map_err(|e| match e {
1636 flume::TryRecvError::Empty => None,
1637 flume::TryRecvError::Disconnected => Some(AppChannelError::Disconnected),
1638 })
1639 }
1640}
1641
1642#[derive(Debug, Clone)]
1644#[non_exhaustive]
1645pub enum AppChannelError {
1646 Disconnected,
1648 Timeout,
1650}
1651impl fmt::Display for AppChannelError {
1652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1653 match self {
1654 AppChannelError::Disconnected => write!(f, "cannot receive because the sender disconnected"),
1655 AppChannelError::Timeout => write!(f, "deadline elapsed before message could be send/received"),
1656 }
1657 }
1658}
1659impl std::error::Error for AppChannelError {}
1660impl From<flume::RecvTimeoutError> for AppChannelError {
1661 fn from(value: flume::RecvTimeoutError) -> Self {
1662 match value {
1663 flume::RecvTimeoutError::Timeout => AppChannelError::Timeout,
1664 flume::RecvTimeoutError::Disconnected => AppChannelError::Disconnected,
1665 }
1666 }
1667}
1668
1669event_args! {
1670 pub struct ExitRequestedArgs {
1674
1675 ..
1676
1677 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
1679 list.search_all()
1680 }
1681 }
1682}
1683
1684event! {
1685 pub static EXIT_REQUESTED_EVENT: ExitRequestedArgs;
1693}
1694
1695trait ReceiverExt<T> {
1697 fn recv_deadline_sp(&self, deadline: Deadline) -> Result<T, flume::RecvTimeoutError>;
1699}
1700
1701const WORST_SLEEP_ERR: Duration = Duration::from_millis(if cfg!(windows) { 20 } else { 10 });
1702const WORST_SPIN_ERR: Duration = Duration::from_millis(if cfg!(windows) { 2 } else { 1 });
1703
1704impl<T> ReceiverExt<T> for flume::Receiver<T> {
1705 fn recv_deadline_sp(&self, deadline: Deadline) -> Result<T, flume::RecvTimeoutError> {
1706 loop {
1707 if let Some(d) = deadline.0.checked_duration_since(INSTANT.now()) {
1708 if matches!(INSTANT.mode(), zng_time::InstantMode::Manual) {
1709 match self.recv_timeout(d.checked_sub(WORST_SLEEP_ERR).unwrap_or_default()) {
1712 Err(flume::RecvTimeoutError::Timeout) => continue, interrupt => return interrupt,
1714 }
1715 } else if d > WORST_SLEEP_ERR {
1716 #[cfg(not(target_arch = "wasm32"))]
1718 match self.recv_deadline(deadline.0.checked_sub(WORST_SLEEP_ERR).unwrap().into()) {
1719 Err(flume::RecvTimeoutError::Timeout) => continue, interrupt => return interrupt,
1721 }
1722
1723 #[cfg(target_arch = "wasm32")] match self.recv_timeout(d.checked_sub(WORST_SLEEP_ERR).unwrap_or_default()) {
1725 Err(flume::RecvTimeoutError::Timeout) => continue, interrupt => return interrupt,
1727 }
1728 } else if d > WORST_SPIN_ERR {
1729 let spin_deadline = Deadline(deadline.0.checked_sub(WORST_SPIN_ERR).unwrap());
1730
1731 while !spin_deadline.has_elapsed() {
1733 match self.try_recv() {
1734 Err(flume::TryRecvError::Empty) => std::thread::yield_now(),
1735 Err(flume::TryRecvError::Disconnected) => return Err(flume::RecvTimeoutError::Disconnected),
1736 Ok(msg) => return Ok(msg),
1737 }
1738 }
1739 continue; } else {
1741 while !deadline.has_elapsed() {
1743 std::thread::yield_now();
1744 }
1745 return Err(flume::RecvTimeoutError::Timeout);
1746 }
1747 } else {
1748 return Err(flume::RecvTimeoutError::Timeout);
1749 }
1750 }
1751 }
1752}