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;
11use parking_lot::Mutex;
12use zng_app_context::{AppScope, app_local};
13use zng_task::DEADLINE_APP;
14use zng_task::channel::{self, ChannelError};
15use zng_time::{INSTANT_APP, InstantMode};
16use zng_txt::Txt;
17use zng_var::{ResponderVar, ResponseVar, VARS_APP, Var, response_var};
18use zng_view_api::{DeviceEventsFilter, raw_input::InputDeviceEvent};
19
20use crate::{
21 APP, AppControlFlow, AppEventObserver, AppExtension, AppExtensionsInfo, DInstant, INSTANT,
22 event::{AnyEventArgs, CommandHandle, CommandInfoExt, CommandNameExt, EVENTS, EventPropagationHandle, command, event},
23 event_args,
24 shortcut::CommandShortcutExt,
25 shortcut::shortcut,
26 timer::TimersService,
27 update::{
28 ContextUpdates, EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdateOp, UpdateTrace, UpdatesTrace, WidgetUpdates,
29 },
30 view_process::{raw_device_events::InputDeviceId, *},
31 widget::WidgetId,
32 window::WindowId,
33};
34
35pub(crate) struct RunningApp<E: AppExtension> {
37 extensions: (AppIntrinsic, E),
38
39 receiver: channel::Receiver<AppEvent>,
40
41 loop_timer: LoopTimer,
42 loop_monitor: LoopMonitor,
43 last_wait_event: Instant,
44
45 pending_view_events: Vec<zng_view_api::Event>,
46 pending_view_frame_events: Vec<zng_view_api::window::EventFrameRendered>,
47 pending: ContextUpdates,
48
49 exited: bool,
50
51 _scope: AppScope,
53}
54impl<E: AppExtension> RunningApp<E> {
55 pub(crate) fn start(
56 scope: AppScope,
57 mut extensions: E,
58 is_headed: bool,
59 with_renderer: bool,
60 view_process_exe: Option<PathBuf>,
61 view_process_env: HashMap<Txt, Txt>,
62 ) -> Self {
63 let _s = tracing::debug_span!("APP::start").entered();
64
65 let (sender, receiver) = AppEventSender::new();
66
67 UPDATES.init(sender);
68
69 fn app_waker() {
70 UPDATES.update(None);
71 }
72 VARS_APP.init_app_waker(app_waker);
73 VARS_APP.init_modify_trace(UpdatesTrace::log_var);
74 DEADLINE_APP.init_deadline_service(crate::timer::deadline_service);
75 zng_var::animation::TRANSITIONABLE_APP.init_rgba_lerp(zng_color::lerp_rgba);
76
77 let mut info = AppExtensionsInfo::start();
78 {
79 let _t = INSTANT_APP.pause_for_update();
80 extensions.register(&mut info);
81 }
82
83 {
84 let mut sv = APP_PROCESS_SV.write();
85 sv.set_extensions(info);
86 }
87
88 if with_renderer && view_process_exe.is_none() {
89 zng_env::assert_inited();
90 }
91
92 #[cfg(not(target_arch = "wasm32"))]
93 let view_process_exe = view_process_exe.unwrap_or_else(|| std::env::current_exe().expect("current_exe"));
94 #[cfg(target_arch = "wasm32")]
95 let view_process_exe = std::path::PathBuf::from("<wasm>");
96
97 let process = AppIntrinsic::pre_init(is_headed, with_renderer, view_process_exe, view_process_env);
98
99 {
100 let _s = tracing::debug_span!("extensions.init").entered();
101 extensions.init();
102 }
103
104 let args = AppStartArgs { _private: () };
105 for h in zng_unique_id::hot_static_ref!(ON_APP_START).lock().iter_mut() {
106 h(&args)
107 }
108
109 RunningApp {
110 extensions: (process, extensions),
111
112 receiver,
113
114 loop_timer: LoopTimer::default(),
115 loop_monitor: LoopMonitor::default(),
116 last_wait_event: Instant::now(),
117
118 pending_view_events: Vec::with_capacity(100),
119 pending_view_frame_events: Vec::with_capacity(5),
120 pending: ContextUpdates {
121 events: Vec::with_capacity(100),
122 update: false,
123 info: false,
124 layout: false,
125 render: false,
126 update_widgets: WidgetUpdates::default(),
127 info_widgets: InfoUpdates::default(),
128 layout_widgets: LayoutUpdates::default(),
129 render_widgets: RenderUpdates::default(),
130 render_update_widgets: RenderUpdates::default(),
131 },
132 exited: false,
133
134 _scope: scope,
135 }
136 }
137
138 pub fn has_exited(&self) -> bool {
139 self.exited
140 }
141
142 pub fn notify_event<O: AppEventObserver>(&mut self, mut update: EventUpdate, observer: &mut O) {
144 let _scope = tracing::trace_span!("notify_event", event = update.event().name()).entered();
145
146 let _t = INSTANT_APP.pause_for_update();
147
148 update.event().on_update(&mut update);
149
150 self.extensions.event_preview(&mut update);
151 observer.event_preview(&mut update);
152 update.call_pre_actions();
153
154 self.extensions.event_ui(&mut update);
155 observer.event_ui(&mut update);
156
157 self.extensions.event(&mut update);
158 observer.event(&mut update);
159 update.call_pos_actions();
160 }
161
162 fn input_device_id(&mut self, id: zng_view_api::raw_input::InputDeviceId) -> InputDeviceId {
163 VIEW_PROCESS.input_device_id(id)
164 }
165
166 fn on_view_event<O: AppEventObserver>(&mut self, ev: zng_view_api::Event, observer: &mut O) {
168 use crate::view_process::raw_device_events::*;
169 use crate::view_process::raw_events::*;
170 use zng_view_api::Event;
171
172 fn window_id(id: zng_view_api::window::WindowId) -> WindowId {
173 WindowId::from_raw(id.get())
174 }
175
176 match ev {
177 Event::MouseMoved {
178 window: w_id,
179 device: d_id,
180 coalesced_pos,
181 position,
182 } => {
183 let args = RawMouseMovedArgs::now(window_id(w_id), self.input_device_id(d_id), coalesced_pos, position);
184 self.notify_event(RAW_MOUSE_MOVED_EVENT.new_update(args), observer);
185 }
186 Event::MouseEntered {
187 window: w_id,
188 device: d_id,
189 } => {
190 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
191 self.notify_event(RAW_MOUSE_ENTERED_EVENT.new_update(args), observer);
192 }
193 Event::MouseLeft {
194 window: w_id,
195 device: d_id,
196 } => {
197 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
198 self.notify_event(RAW_MOUSE_LEFT_EVENT.new_update(args), observer);
199 }
200 Event::WindowChanged(c) => {
201 let monitor_id = c.monitor.map(|id| VIEW_PROCESS.monitor_id(id));
202 let args = RawWindowChangedArgs::now(
203 window_id(c.window),
204 c.state,
205 c.position,
206 monitor_id,
207 c.size,
208 c.safe_padding,
209 c.cause,
210 c.frame_wait_id,
211 );
212 self.notify_event(RAW_WINDOW_CHANGED_EVENT.new_update(args), observer);
213 }
214 Event::DragHovered { window, data, allowed } => {
215 let args = RawDragHoveredArgs::now(window_id(window), data, allowed);
216 self.notify_event(RAW_DRAG_HOVERED_EVENT.new_update(args), observer);
217 }
218 Event::DragMoved {
219 window,
220 coalesced_pos,
221 position,
222 } => {
223 let args = RawDragMovedArgs::now(window_id(window), coalesced_pos, position);
224 self.notify_event(RAW_DRAG_MOVED_EVENT.new_update(args), observer);
225 }
226 Event::DragDropped {
227 window,
228 data,
229 allowed,
230 drop_id,
231 } => {
232 let args = RawDragDroppedArgs::now(window_id(window), data, allowed, drop_id);
233 self.notify_event(RAW_DRAG_DROPPED_EVENT.new_update(args), observer);
234 }
235 Event::DragCancelled { window } => {
236 let args = RawDragCancelledArgs::now(window_id(window));
237 self.notify_event(RAW_DRAG_CANCELLED_EVENT.new_update(args), observer);
238 }
239 Event::AppDragEnded { window, drag, applied } => {
240 let args = RawAppDragEndedArgs::now(window_id(window), drag, applied);
241 self.notify_event(RAW_APP_DRAG_ENDED_EVENT.new_update(args), observer);
242 }
243 Event::FocusChanged { prev, new } => {
244 let args = RawWindowFocusArgs::now(prev.map(window_id), new.map(window_id));
245 self.notify_event(RAW_WINDOW_FOCUS_EVENT.new_update(args), observer);
246 }
247 Event::KeyboardInput {
248 window: w_id,
249 device: d_id,
250 key_code,
251 state,
252 key,
253 key_location,
254 key_modified,
255 text,
256 } => {
257 let args = RawKeyInputArgs::now(
258 window_id(w_id),
259 self.input_device_id(d_id),
260 key_code,
261 key_location,
262 state,
263 key,
264 key_modified,
265 text,
266 );
267 self.notify_event(RAW_KEY_INPUT_EVENT.new_update(args), observer);
268 }
269 Event::Ime { window: w_id, ime } => {
270 let args = RawImeArgs::now(window_id(w_id), ime);
271 self.notify_event(RAW_IME_EVENT.new_update(args), observer);
272 }
273
274 Event::MouseWheel {
275 window: w_id,
276 device: d_id,
277 delta,
278 phase,
279 } => {
280 let args = RawMouseWheelArgs::now(window_id(w_id), self.input_device_id(d_id), delta, phase);
281 self.notify_event(RAW_MOUSE_WHEEL_EVENT.new_update(args), observer);
282 }
283 Event::MouseInput {
284 window: w_id,
285 device: d_id,
286 state,
287 button,
288 } => {
289 let args = RawMouseInputArgs::now(window_id(w_id), self.input_device_id(d_id), state, button);
290 self.notify_event(RAW_MOUSE_INPUT_EVENT.new_update(args), observer);
291 }
292 Event::TouchpadPressure {
293 window: w_id,
294 device: d_id,
295 pressure,
296 stage,
297 } => {
298 let args = RawTouchpadPressureArgs::now(window_id(w_id), self.input_device_id(d_id), pressure, stage);
299 self.notify_event(RAW_TOUCHPAD_PRESSURE_EVENT.new_update(args), observer);
300 }
301 Event::AxisMotion {
302 window: w_id,
303 device: d_id,
304 axis,
305 value,
306 } => {
307 let args = RawAxisMotionArgs::now(window_id(w_id), self.input_device_id(d_id), axis, value);
308 self.notify_event(RAW_AXIS_MOTION_EVENT.new_update(args), observer);
309 }
310 Event::Touch {
311 window: w_id,
312 device: d_id,
313 touches,
314 } => {
315 let args = RawTouchArgs::now(window_id(w_id), self.input_device_id(d_id), touches);
316 self.notify_event(RAW_TOUCH_EVENT.new_update(args), observer);
317 }
318 Event::ScaleFactorChanged {
319 monitor: id,
320 windows,
321 scale_factor,
322 } => {
323 let monitor_id = VIEW_PROCESS.monitor_id(id);
324 let windows: Vec<_> = windows.into_iter().map(window_id).collect();
325 let args = RawScaleFactorChangedArgs::now(monitor_id, windows, scale_factor);
326 self.notify_event(RAW_SCALE_FACTOR_CHANGED_EVENT.new_update(args), observer);
327 }
328 Event::MonitorsChanged(monitors) => {
329 let monitors: Vec<_> = monitors.into_iter().map(|(id, info)| (VIEW_PROCESS.monitor_id(id), info)).collect();
330 let args = RawMonitorsChangedArgs::now(monitors);
331 self.notify_event(RAW_MONITORS_CHANGED_EVENT.new_update(args), observer);
332 }
333 Event::AudioDevicesChanged(_audio_devices) => {
334 }
336 Event::WindowCloseRequested(w_id) => {
337 let args = RawWindowCloseRequestedArgs::now(window_id(w_id));
338 self.notify_event(RAW_WINDOW_CLOSE_REQUESTED_EVENT.new_update(args), observer);
339 }
340 Event::WindowOpened(w_id, data) => {
341 let w_id = window_id(w_id);
342 let (window, data) = VIEW_PROCESS.on_window_opened(w_id, data);
343 let args = RawWindowOpenArgs::now(w_id, window, data);
344 self.notify_event(RAW_WINDOW_OPEN_EVENT.new_update(args), observer);
345 }
346 Event::HeadlessOpened(w_id, data) => {
347 let w_id = window_id(w_id);
348 let (surface, data) = VIEW_PROCESS.on_headless_opened(w_id, data);
349 let args = RawHeadlessOpenArgs::now(w_id, surface, data);
350 self.notify_event(RAW_HEADLESS_OPEN_EVENT.new_update(args), observer);
351 }
352 Event::WindowOrHeadlessOpenError { id: w_id, error } => {
353 let w_id = window_id(w_id);
354 let args = RawWindowOrHeadlessOpenErrorArgs::now(w_id, error);
355 self.notify_event(RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.new_update(args), observer);
356 }
357 Event::WindowClosed(w_id) => {
358 let args = RawWindowCloseArgs::now(window_id(w_id));
359 self.notify_event(RAW_WINDOW_CLOSE_EVENT.new_update(args), observer);
360 }
361 Event::ImageMetadataLoaded {
362 image: id,
363 size,
364 density,
365 is_mask,
366 } => {
367 if let Some(img) = VIEW_PROCESS.on_image_metadata_loaded(id, size, density, is_mask) {
368 let args = RawImageArgs::now(img);
369 self.notify_event(RAW_IMAGE_METADATA_LOADED_EVENT.new_update(args), observer);
370 }
371 }
372 Event::ImagePartiallyLoaded {
373 image: id,
374 partial_size,
375 density,
376 is_opaque,
377 is_mask,
378 partial_pixels: partial_bgra8,
379 } => {
380 if let Some(img) = VIEW_PROCESS.on_image_partially_loaded(id, partial_size, density, is_opaque, is_mask, partial_bgra8) {
381 let args = RawImageArgs::now(img);
382 self.notify_event(RAW_IMAGE_PARTIALLY_LOADED_EVENT.new_update(args), observer);
383 }
384 }
385 Event::ImageLoaded(image) => {
386 if let Some(img) = VIEW_PROCESS.on_image_loaded(image) {
387 let args = RawImageArgs::now(img);
388 self.notify_event(RAW_IMAGE_LOADED_EVENT.new_update(args), observer);
389 }
390 }
391 Event::ImageLoadError { image: id, error } => {
392 if let Some(img) = VIEW_PROCESS.on_image_error(id, error) {
393 let args = RawImageArgs::now(img);
394 self.notify_event(RAW_IMAGE_LOAD_ERROR_EVENT.new_update(args), observer);
395 }
396 }
397 Event::ImageEncoded { image: id, format, data } => VIEW_PROCESS.on_image_encoded(id, format, data),
398 Event::ImageEncodeError { image: id, format, error } => {
399 VIEW_PROCESS.on_image_encode_error(id, format, error);
400 }
401 Event::FrameImageReady {
402 window: w_id,
403 frame: frame_id,
404 image: image_id,
405 selection,
406 } => {
407 if let Some(img) = VIEW_PROCESS.on_frame_image_ready(image_id) {
408 let args = RawFrameImageReadyArgs::now(img, window_id(w_id), frame_id, selection);
409 self.notify_event(RAW_FRAME_IMAGE_READY_EVENT.new_update(args), observer);
410 }
411 }
412
413 Event::AccessInit { window: w_id } => {
414 self.notify_event(crate::access::on_access_init(window_id(w_id)), observer);
415 }
416 Event::AccessCommand {
417 window: win_id,
418 target: wgt_id,
419 command,
420 } => {
421 if let Some(update) = crate::access::on_access_command(window_id(win_id), WidgetId::from_raw(wgt_id.0), command) {
422 self.notify_event(update, observer);
423 }
424 }
425 Event::AccessDeinit { window: w_id } => {
426 self.notify_event(crate::access::on_access_deinit(window_id(w_id)), observer);
427 }
428
429 Event::MsgDialogResponse(id, response) => {
431 VIEW_PROCESS.on_message_dlg_response(id, response);
432 }
433 Event::FileDialogResponse(id, response) => {
434 VIEW_PROCESS.on_file_dlg_response(id, response);
435 }
436
437 Event::ExtensionEvent(id, payload) => {
439 let args = RawExtensionEventArgs::now(id, payload);
440 self.notify_event(RAW_EXTENSION_EVENT.new_update(args), observer);
441 }
442
443 Event::FontsChanged => {
445 let args = RawFontChangedArgs::now();
446 self.notify_event(RAW_FONT_CHANGED_EVENT.new_update(args), observer);
447 }
448 Event::FontAaChanged(aa) => {
449 let args = RawFontAaChangedArgs::now(aa);
450 self.notify_event(RAW_FONT_AA_CHANGED_EVENT.new_update(args), observer);
451 }
452 Event::MultiClickConfigChanged(cfg) => {
453 let args = RawMultiClickConfigChangedArgs::now(cfg);
454 self.notify_event(RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT.new_update(args), observer);
455 }
456 Event::AnimationsConfigChanged(cfg) => {
457 VARS_APP.set_sys_animations_enabled(cfg.enabled);
458 let args = RawAnimationsConfigChangedArgs::now(cfg);
459 self.notify_event(RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.new_update(args), observer);
460 }
461 Event::KeyRepeatConfigChanged(cfg) => {
462 let args = RawKeyRepeatConfigChangedArgs::now(cfg);
463 self.notify_event(RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.new_update(args), observer);
464 }
465 Event::TouchConfigChanged(cfg) => {
466 let args = RawTouchConfigChangedArgs::now(cfg);
467 self.notify_event(RAW_TOUCH_CONFIG_CHANGED_EVENT.new_update(args), observer);
468 }
469 Event::LocaleChanged(cfg) => {
470 let args = RawLocaleChangedArgs::now(cfg);
471 self.notify_event(RAW_LOCALE_CONFIG_CHANGED_EVENT.new_update(args), observer);
472 }
473 Event::ColorsConfigChanged(cfg) => {
474 let args = RawColorsConfigChangedArgs::now(cfg);
475 self.notify_event(RAW_COLORS_CONFIG_CHANGED_EVENT.new_update(args), observer);
476 }
477 Event::ChromeConfigChanged(cfg) => {
478 let args = RawChromeConfigChangedArgs::now(cfg);
479 self.notify_event(RAW_CHROME_CONFIG_CHANGED_EVENT.new_update(args), observer);
480 }
481
482 Event::InputDevicesChanged(devices) => {
484 let devices: HashMap<_, _> = devices.into_iter().map(|(d_id, info)| (self.input_device_id(d_id), info)).collect();
485 INPUT_DEVICES.update(devices.clone());
486 let args = InputDevicesChangedArgs::now(devices);
487 self.notify_event(INPUT_DEVICES_CHANGED_EVENT.new_update(args), observer);
488 }
489 Event::InputDeviceEvent { device, event } => {
490 let d_id = self.input_device_id(device);
491 match event {
492 InputDeviceEvent::PointerMotion { delta } => {
493 let args = PointerMotionArgs::now(d_id, delta);
494 self.notify_event(POINTER_MOTION_EVENT.new_update(args), observer);
495 }
496 InputDeviceEvent::ScrollMotion { delta } => {
497 let args = ScrollMotionArgs::now(d_id, delta);
498 self.notify_event(SCROLL_MOTION_EVENT.new_update(args), observer);
499 }
500 InputDeviceEvent::AxisMotion { axis, value } => {
501 let args = AxisMotionArgs::now(d_id, axis, value);
502 self.notify_event(AXIS_MOTION_EVENT.new_update(args), observer);
503 }
504 InputDeviceEvent::Button { button, state } => {
505 let args = ButtonArgs::now(d_id, button, state);
506 self.notify_event(BUTTON_EVENT.new_update(args), observer);
507 }
508 InputDeviceEvent::Key { key_code, state } => {
509 let args = KeyArgs::now(d_id, key_code, state);
510 self.notify_event(KEY_EVENT.new_update(args), observer);
511 }
512 _ => {}
513 }
514 }
515
516 Event::LowMemory => {
517 LOW_MEMORY_EVENT.notify(LowMemoryArgs::now());
518 }
519
520 Event::RecoveredFromComponentPanic { component, recover, panic } => {
521 tracing::error!(
522 "view-process recovered from internal component panic\n component: {component}\n recover: {recover}\n```panic\n{panic}\n```"
523 );
524 }
525
526 Event::Inited(zng_view_api::Inited { .. }) | Event::Suspended | Event::Disconnected(_) | Event::FrameRendered(_) => {
528 unreachable!()
529 } _ => {}
532 }
533 }
534
535 fn on_view_rendered_event<O: AppEventObserver>(&mut self, ev: zng_view_api::window::EventFrameRendered, observer: &mut O) {
537 debug_assert!(ev.window != zng_view_api::window::WindowId::INVALID);
538 let window_id = WindowId::from_raw(ev.window.get());
539 let image = ev.frame_image.map(|img| VIEW_PROCESS.on_frame_image(img));
541 let args = crate::view_process::raw_events::RawFrameRenderedArgs::now(window_id, ev.frame, image);
542 self.notify_event(crate::view_process::raw_events::RAW_FRAME_RENDERED_EVENT.new_update(args), observer);
543 }
544
545 pub(crate) fn run_headed(mut self) {
546 let mut observer = ();
547 #[cfg(feature = "dyn_app_extension")]
548 let mut observer = observer.as_dyn();
549
550 self.apply_updates(&mut observer);
551 self.apply_update_events(&mut observer);
552 let mut wait = false;
553 loop {
554 wait = match self.poll_impl(wait, &mut observer) {
555 AppControlFlow::Poll => false,
556 AppControlFlow::Wait => true,
557 AppControlFlow::Exit => break,
558 };
559 }
560 }
561
562 fn push_coalesce<O: AppEventObserver>(&mut self, ev: AppEvent, observer: &mut O) {
563 match ev {
564 AppEvent::ViewEvent(ev) => match ev {
565 zng_view_api::Event::FrameRendered(ev) => {
566 if ev.window == zng_view_api::window::WindowId::INVALID {
567 tracing::error!("ignored rendered event for invalid window id, {ev:?}");
568 return;
569 }
570
571 let window = WindowId::from_raw(ev.window.get());
572
573 {
575 if VIEW_PROCESS.is_available() {
576 VIEW_PROCESS.on_frame_rendered(window);
577 }
578 }
579
580 #[cfg(debug_assertions)]
581 if self.pending_view_frame_events.iter().any(|e| e.window == ev.window) {
582 tracing::warn!("window `{window:?}` probably sent a frame request without awaiting renderer idle");
583 }
584
585 self.pending_view_frame_events.push(ev);
586 }
587 zng_view_api::Event::Pong(count) => VIEW_PROCESS.on_pong(count),
588 zng_view_api::Event::Inited(zng_view_api::Inited {
589 generation,
590 is_respawn,
591 extensions,
592 ..
593 }) => {
594 if is_respawn {
596 VIEW_PROCESS.on_respawned(generation);
597 APP_PROCESS_SV.read().is_suspended.set(false);
598 }
599
600 VIEW_PROCESS.handle_inited(generation, extensions.clone());
601
602 let args = crate::view_process::ViewProcessInitedArgs::now(generation, is_respawn, extensions);
603 self.notify_event(VIEW_PROCESS_INITED_EVENT.new_update(args), observer);
604 }
605 zng_view_api::Event::Suspended => {
606 VIEW_PROCESS.handle_suspended();
607 let args = crate::view_process::ViewProcessSuspendedArgs::now();
608 self.notify_event(VIEW_PROCESS_SUSPENDED_EVENT.new_update(args), observer);
609 APP_PROCESS_SV.read().is_suspended.set(true);
610 }
611 zng_view_api::Event::Disconnected(vp_gen) => {
612 VIEW_PROCESS.handle_disconnect(vp_gen);
614 }
615 ev => {
616 if let Some(last) = self.pending_view_events.last_mut() {
617 match last.coalesce(ev) {
618 Ok(()) => {}
619 Err(ev) => self.pending_view_events.push(ev),
620 }
621 } else {
622 self.pending_view_events.push(ev);
623 }
624 }
625 },
626 AppEvent::Event(ev) => EVENTS.notify(ev.get()),
627 AppEvent::Update(op, target) => {
628 UPDATES.update_op(op, target);
629 }
630 AppEvent::CheckUpdate => {}
631 AppEvent::ResumeUnwind(p) => std::panic::resume_unwind(p),
632 }
633 }
634
635 fn has_pending_updates(&mut self) -> bool {
636 !self.pending_view_events.is_empty() || self.pending.has_updates() || UPDATES.has_pending_updates() || !self.receiver.is_empty()
637 }
638
639 pub(crate) fn poll<O: AppEventObserver>(&mut self, wait_app_event: bool, observer: &mut O) -> AppControlFlow {
640 #[cfg(feature = "dyn_app_extension")]
641 let mut observer = observer.as_dyn();
642 #[cfg(feature = "dyn_app_extension")]
643 let observer = &mut observer;
644 self.poll_impl(wait_app_event, observer)
645 }
646 fn poll_impl<O: AppEventObserver>(&mut self, wait_app_event: bool, observer: &mut O) -> AppControlFlow {
647 let mut disconnected = false;
648
649 if self.exited {
650 return AppControlFlow::Exit;
651 }
652
653 if wait_app_event {
654 let idle = tracing::debug_span!("<idle>", ended_by = tracing::field::Empty).entered();
655
656 const PING_TIMER: Duration = Duration::from_secs(2);
657
658 let ping_timer = Deadline::timeout(PING_TIMER);
659 let timer = if self.view_is_busy() {
660 None
661 } else {
662 self.loop_timer.poll().map(|t| t.min(ping_timer))
663 };
664 match self.receiver.recv_deadline_blocking(timer.unwrap_or(ping_timer)) {
665 Ok(ev) => {
666 idle.record("ended_by", "event");
667 drop(idle);
668 self.last_wait_event = Instant::now();
669 self.push_coalesce(ev, observer)
670 }
671 Err(e) => match e {
672 ChannelError::Timeout => {
673 if timer.is_none() {
674 idle.record("ended_by", "timeout (ping)");
675 } else {
676 idle.record("ended_by", "timeout");
677 }
678 if self.last_wait_event.elapsed() >= PING_TIMER && !VIEW_PROCESS.is_same_process() && VIEW_PROCESS.is_connected() {
679 VIEW_PROCESS.ping();
680 }
681 }
682 ChannelError::Disconnected { .. } => {
683 idle.record("ended_by", "disconnected");
684 disconnected = true
685 }
686 },
687 }
688 }
689 loop {
690 match self.receiver.try_recv() {
691 Ok(ev) => match ev {
692 Some(ev) => self.push_coalesce(ev, observer),
693 None => break,
694 },
695 Err(e) => match e {
696 ChannelError::Disconnected { .. } => {
697 disconnected = true;
698 break;
699 }
700 _ => unreachable!(),
701 },
702 }
703 }
704 if disconnected {
705 panic!("app events channel disconnected");
706 }
707
708 if self.view_is_busy() {
709 return AppControlFlow::Wait;
710 }
711
712 UPDATES.on_app_awake();
713
714 let updated_timers = self.loop_timer.awake();
716 if updated_timers {
717 UPDATES.update_timers(&mut self.loop_timer);
719 self.apply_updates(observer);
720 }
721
722 let mut events = mem::take(&mut self.pending_view_events);
723 for ev in events.drain(..) {
724 self.on_view_event(ev, observer);
725 self.apply_updates(observer);
726 }
727 debug_assert!(self.pending_view_events.is_empty());
728 self.pending_view_events = events; let mut events = mem::take(&mut self.pending_view_frame_events);
731 for ev in events.drain(..) {
732 self.on_view_rendered_event(ev, observer);
733 }
734 self.pending_view_frame_events = events;
735
736 if self.has_pending_updates() {
737 self.apply_updates(observer);
738 self.apply_update_events(observer);
739 }
740
741 if self.view_is_busy() {
742 return AppControlFlow::Wait;
743 }
744
745 self.finish_frame(observer);
746
747 UPDATES.next_deadline(&mut self.loop_timer);
748
749 if self.extensions.0.exit() {
750 UPDATES.on_app_sleep();
751 self.exited = true;
752 AppControlFlow::Exit
753 } else if self.has_pending_updates() || UPDATES.has_pending_layout_or_render() {
754 AppControlFlow::Poll
755 } else {
756 UPDATES.on_app_sleep();
757 AppControlFlow::Wait
758 }
759 }
760
761 fn apply_updates<O: AppEventObserver>(&mut self, observer: &mut O) {
763 let _s = tracing::debug_span!("apply_updates").entered();
764
765 let mut run = true;
766 while run {
767 run = self.loop_monitor.update(|| {
768 let mut any = false;
769
770 self.pending |= UPDATES.apply_info();
771 if mem::take(&mut self.pending.info) {
772 any = true;
773 let _s = tracing::debug_span!("info").entered();
774
775 let mut info_widgets = mem::take(&mut self.pending.info_widgets);
776
777 let _t = INSTANT_APP.pause_for_update();
778
779 {
780 let _s = tracing::debug_span!("ext.info").entered();
781 self.extensions.info(&mut info_widgets);
782 }
783 {
784 let _s = tracing::debug_span!("obs.info").entered();
785 observer.info(&mut info_widgets);
786 }
787 }
788
789 self.pending |= UPDATES.apply_updates();
790 TimersService::notify();
791 if mem::take(&mut self.pending.update) {
792 any = true;
793 let _s = tracing::debug_span!("update").entered();
794
795 let mut update_widgets = mem::take(&mut self.pending.update_widgets);
796
797 let _t = INSTANT_APP.pause_for_update();
798
799 {
800 let _s = tracing::debug_span!("ext.update_preview").entered();
801 self.extensions.update_preview();
802 }
803 {
804 let _s = tracing::debug_span!("obs.update_preview").entered();
805 observer.update_preview();
806 }
807 UPDATES.on_pre_updates();
808
809 {
810 let _s = tracing::debug_span!("ext.update_ui").entered();
811 self.extensions.update_ui(&mut update_widgets);
812 }
813 {
814 let _s = tracing::debug_span!("obs.update_ui").entered();
815 observer.update_ui(&mut update_widgets);
816 }
817
818 {
819 let _s = tracing::debug_span!("ext.update").entered();
820 self.extensions.update();
821 }
822 {
823 let _s = tracing::debug_span!("obs.update").entered();
824 observer.update();
825 }
826 UPDATES.on_updates();
827 }
828
829 any
830 });
831 }
832 }
833
834 fn apply_update_events<O: AppEventObserver>(&mut self, observer: &mut O) {
836 let _s = tracing::debug_span!("apply_update_events").entered();
837
838 loop {
839 let events: Vec<_> = self.pending.events.drain(..).collect();
840 if events.is_empty() {
841 break;
842 }
843 for mut update in events {
844 let _s = tracing::debug_span!("update_event", ?update).entered();
845
846 self.loop_monitor.maybe_trace(|| {
847 let _t = INSTANT_APP.pause_for_update();
848
849 {
850 let _s = tracing::debug_span!("ext.event_preview").entered();
851 self.extensions.event_preview(&mut update);
852 }
853 {
854 let _s = tracing::debug_span!("obs.event_preview").entered();
855 observer.event_preview(&mut update);
856 }
857 update.call_pre_actions();
858
859 {
860 let _s = tracing::debug_span!("ext.event_ui").entered();
861 self.extensions.event_ui(&mut update);
862 }
863 {
864 let _s = tracing::debug_span!("obs.event_ui").entered();
865 observer.event_ui(&mut update);
866 }
867 {
868 let _s = tracing::debug_span!("ext.event").entered();
869 self.extensions.event(&mut update);
870 }
871 {
872 let _s = tracing::debug_span!("obs.event").entered();
873 observer.event(&mut update);
874 }
875 update.call_pos_actions();
876 });
877
878 self.apply_updates(observer);
879 }
880 }
881 }
882
883 fn view_is_busy(&mut self) -> bool {
884 VIEW_PROCESS.is_available() && VIEW_PROCESS.pending_frames() > 0
885 }
886
887 fn finish_frame<O: AppEventObserver>(&mut self, observer: &mut O) {
889 debug_assert!(!self.view_is_busy());
890
891 self.pending |= UPDATES.apply_layout_render();
892
893 while mem::take(&mut self.pending.layout) {
894 let _s = tracing::debug_span!("apply_layout").entered();
895
896 let mut layout_widgets = mem::take(&mut self.pending.layout_widgets);
897
898 self.loop_monitor.maybe_trace(|| {
899 let _t = INSTANT_APP.pause_for_update();
900
901 {
902 let _s = tracing::debug_span!("ext.layout").entered();
903 self.extensions.layout(&mut layout_widgets);
904 }
905 {
906 let _s = tracing::debug_span!("obs.layout").entered();
907 observer.layout(&mut layout_widgets);
908 }
909 });
910
911 self.apply_updates(observer);
912 self.apply_update_events(observer);
913 self.pending |= UPDATES.apply_layout_render();
914 }
915
916 if mem::take(&mut self.pending.render) {
917 let _s = tracing::debug_span!("apply_render").entered();
918
919 let mut render_widgets = mem::take(&mut self.pending.render_widgets);
920 let mut render_update_widgets = mem::take(&mut self.pending.render_update_widgets);
921
922 let _t = INSTANT_APP.pause_for_update();
923
924 {
925 let _s = tracing::debug_span!("ext.render").entered();
926 self.extensions.render(&mut render_widgets, &mut render_update_widgets);
927 }
928 {
929 let _s = tracing::debug_span!("obs.render").entered();
930 observer.render(&mut render_widgets, &mut render_update_widgets);
931 }
932 }
933
934 self.loop_monitor.finish_frame();
935 }
936}
937impl<E: AppExtension> Drop for RunningApp<E> {
938 fn drop(&mut self) {
939 let _s = tracing::debug_span!("ext.deinit").entered();
940 self.extensions.deinit();
941 VIEW_PROCESS.exit();
942 }
943}
944
945pub struct AppStartArgs {
950 _private: (),
951}
952
953pub fn on_app_start(handler: impl FnMut(&AppStartArgs) + Send + 'static) {
959 zng_unique_id::hot_static_ref!(ON_APP_START).lock().push(Box::new(handler))
960}
961zng_unique_id::hot_static! {
962 static ON_APP_START: Mutex<Vec<AppStartHandler>> = Mutex::new(vec![]);
963}
964type AppStartHandler = Box<dyn FnMut(&AppStartArgs) + Send + 'static>;
965
966#[derive(Debug)]
968pub(crate) struct LoopTimer {
969 now: DInstant,
970 deadline: Option<Deadline>,
971}
972impl Default for LoopTimer {
973 fn default() -> Self {
974 Self {
975 now: INSTANT.now(),
976 deadline: None,
977 }
978 }
979}
980impl LoopTimer {
981 pub fn elapsed(&mut self, deadline: Deadline) -> bool {
984 if deadline.0 <= self.now {
985 true
986 } else {
987 self.register(deadline);
988 false
989 }
990 }
991
992 pub fn register(&mut self, deadline: Deadline) {
994 if let Some(d) = &mut self.deadline {
995 if deadline < *d {
996 *d = deadline;
997 }
998 } else {
999 self.deadline = Some(deadline)
1000 }
1001 }
1002
1003 pub(crate) fn poll(&mut self) -> Option<Deadline> {
1005 self.deadline
1006 }
1007
1008 pub(crate) fn awake(&mut self) -> bool {
1010 self.now = INSTANT.now();
1011 if let Some(d) = self.deadline
1012 && d.0 <= self.now
1013 {
1014 self.deadline = None;
1015 return true;
1016 }
1017 false
1018 }
1019
1020 pub fn now(&self) -> DInstant {
1022 self.now
1023 }
1024}
1025impl zng_var::animation::AnimationTimer for LoopTimer {
1026 fn elapsed(&mut self, deadline: Deadline) -> bool {
1027 self.elapsed(deadline)
1028 }
1029
1030 fn register(&mut self, deadline: Deadline) {
1031 self.register(deadline)
1032 }
1033
1034 fn now(&self) -> DInstant {
1035 self.now()
1036 }
1037}
1038
1039#[derive(Default)]
1040struct LoopMonitor {
1041 update_count: u16,
1042 skipped: bool,
1043 trace: Vec<UpdateTrace>,
1044}
1045impl LoopMonitor {
1046 pub fn update(&mut self, update_once: impl FnOnce() -> bool) -> bool {
1048 self.update_count += 1;
1049
1050 if self.update_count < 500 {
1051 update_once()
1052 } else if self.update_count < 1000 {
1053 UpdatesTrace::collect_trace(&mut self.trace, update_once)
1054 } else if self.update_count == 1000 {
1055 self.skipped = true;
1056 let trace = UpdatesTrace::format_trace(mem::take(&mut self.trace));
1057 tracing::error!(
1058 "updated 1000 times without rendering, probably stuck in an infinite loop\n\
1059 will start skipping updates to render and poll system events\n\
1060 top 20 most frequent update requests (in 500 cycles):\n\
1061 {trace}\n\
1062 you can use `UpdatesTraceUiNodeExt` and `updates_trace_event` to refine the trace"
1063 );
1064 false
1065 } else if self.update_count == 1500 {
1066 self.update_count = 1001;
1067 false
1068 } else {
1069 update_once()
1070 }
1071 }
1072
1073 pub fn maybe_trace(&mut self, notify_once: impl FnOnce()) {
1074 if (500..1000).contains(&self.update_count) {
1075 UpdatesTrace::collect_trace(&mut self.trace, notify_once);
1076 } else {
1077 notify_once();
1078 }
1079 }
1080
1081 pub fn finish_frame(&mut self) {
1082 if !self.skipped {
1083 self.skipped = false;
1084 self.update_count = 0;
1085 self.trace = vec![];
1086 }
1087 }
1088}
1089
1090impl APP {
1091 pub fn exit(&self) -> ResponseVar<ExitCancelled> {
1100 APP_PROCESS_SV.write().exit()
1101 }
1102
1103 pub fn is_suspended(&self) -> Var<bool> {
1111 APP_PROCESS_SV.read().is_suspended.read_only()
1112 }
1113}
1114
1115impl APP {
1119 pub fn pause_time_for_update(&self) -> Var<bool> {
1125 APP_PROCESS_SV.read().pause_time_for_updates.clone()
1126 }
1127
1128 pub fn start_manual_time(&self) {
1136 INSTANT_APP.set_mode(InstantMode::Manual);
1137 INSTANT_APP.set_now(INSTANT.now());
1138 UPDATES.update(None);
1139 }
1140
1141 pub fn advance_manual_time(&self, advance: Duration) {
1152 INSTANT_APP.advance_now(advance);
1153 UPDATES.update(None);
1154 }
1155
1156 pub fn set_manual_time(&self, now: DInstant) {
1165 INSTANT_APP.set_now(now);
1166 UPDATES.update(None);
1167 }
1168
1169 pub fn end_manual_time(&self) {
1171 INSTANT_APP.set_mode(match APP.pause_time_for_update().get() {
1172 true => InstantMode::UpdatePaused,
1173 false => InstantMode::Now,
1174 });
1175 UPDATES.update(None);
1176 }
1177}
1178
1179command! {
1180 pub static EXIT_CMD = {
1184 l10n!: true,
1185 name: "Exit",
1186 info: "Close all windows and exit",
1187 shortcut: shortcut!(Exit),
1188 };
1189}
1190
1191#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1195pub struct ExitCancelled;
1196impl fmt::Display for ExitCancelled {
1197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1198 write!(f, "exit request cancelled")
1199 }
1200}
1201
1202struct AppIntrinsic {
1203 exit_handle: CommandHandle,
1204 pending_exit: Option<PendingExit>,
1205}
1206struct PendingExit {
1207 handle: EventPropagationHandle,
1208 response: ResponderVar<ExitCancelled>,
1209}
1210impl AppIntrinsic {
1211 pub(super) fn pre_init(is_headed: bool, with_renderer: bool, view_process_exe: PathBuf, view_process_env: HashMap<Txt, Txt>) -> Self {
1213 APP_PROCESS_SV
1214 .read()
1215 .pause_time_for_updates
1216 .hook(|a| {
1217 if !matches!(INSTANT.mode(), zng_time::InstantMode::Manual) {
1218 if *a.value() {
1219 INSTANT_APP.set_mode(InstantMode::UpdatePaused);
1220 } else {
1221 INSTANT_APP.set_mode(InstantMode::Now);
1222 }
1223 }
1224 true
1225 })
1226 .perm();
1227
1228 if is_headed {
1229 debug_assert!(with_renderer);
1230
1231 let view_evs_sender = UPDATES.sender();
1232 VIEW_PROCESS.start(view_process_exe, view_process_env, false, move |ev| {
1233 let _ = view_evs_sender.send_view_event(ev);
1234 });
1235 } else if with_renderer {
1236 let view_evs_sender = UPDATES.sender();
1237 VIEW_PROCESS.start(view_process_exe, view_process_env, true, move |ev| {
1238 let _ = view_evs_sender.send_view_event(ev);
1239 });
1240 }
1241
1242 AppIntrinsic {
1243 exit_handle: EXIT_CMD.subscribe(true),
1244 pending_exit: None,
1245 }
1246 }
1247
1248 pub(super) fn exit(&mut self) -> bool {
1250 if let Some(pending) = self.pending_exit.take() {
1251 if pending.handle.is_stopped() {
1252 pending.response.respond(ExitCancelled);
1253 false
1254 } else {
1255 true
1256 }
1257 } else {
1258 false
1259 }
1260 }
1261}
1262impl AppExtension for AppIntrinsic {
1263 fn event_preview(&mut self, update: &mut EventUpdate) {
1264 if VIEW_PROCESS_INITED_EVENT.has(update) {
1265 let filter = APP_PROCESS_SV.read().device_events_filter.get();
1266 if !filter.is_empty()
1267 && let Err(e) = VIEW_PROCESS.set_device_events_filter(filter)
1268 {
1269 tracing::error!("cannot set device events on the view-process, {e}");
1270 }
1271 } else if let Some(args) = EXIT_CMD.on(update) {
1272 args.handle_enabled(&self.exit_handle, |_| {
1273 APP.exit();
1274 });
1275 }
1276 }
1277
1278 fn update(&mut self) {
1279 let mut sv = APP_PROCESS_SV.write();
1280 if let Some(filter) = sv.device_events_filter.get_new()
1281 && let Err(e) = VIEW_PROCESS.set_device_events_filter(filter)
1282 {
1283 tracing::error!("cannot set device events on the view-process, {e}");
1284 }
1285 if let Some(response) = sv.take_requests() {
1286 let args = ExitRequestedArgs::now();
1287 self.pending_exit = Some(PendingExit {
1288 handle: args.propagation().clone(),
1289 response,
1290 });
1291 EXIT_REQUESTED_EVENT.notify(args);
1292 }
1293 }
1294}
1295
1296pub(crate) fn assert_not_view_process() {
1297 if zng_view_api::ViewConfig::from_env().is_some() {
1298 panic!("cannot start App in view-process");
1299 }
1300}
1301#[cfg(feature = "deadlock_detection")]
1306pub fn spawn_deadlock_detection() {
1307 use parking_lot::deadlock;
1308 use std::{
1309 sync::atomic::{self, AtomicBool},
1310 thread,
1311 time::*,
1312 };
1313
1314 static CHECK_RUNNING: AtomicBool = AtomicBool::new(false);
1315
1316 if CHECK_RUNNING.swap(true, atomic::Ordering::SeqCst) {
1317 return;
1318 }
1319
1320 thread::Builder::new()
1321 .name("deadlock_detection".into())
1322 .stack_size(256 * 1024)
1323 .spawn(|| {
1324 loop {
1325 thread::sleep(Duration::from_secs(10));
1326
1327 let deadlocks = deadlock::check_deadlock();
1328 if deadlocks.is_empty() {
1329 continue;
1330 }
1331
1332 use std::fmt::Write;
1333 let mut msg = String::new();
1334
1335 let _ = writeln!(&mut msg, "{} deadlocks detected", deadlocks.len());
1336 for (i, threads) in deadlocks.iter().enumerate() {
1337 let _ = writeln!(&mut msg, "Deadlock #{}, {} threads", i, threads.len());
1338 for t in threads {
1339 let _ = writeln!(&mut msg, "Thread Id {:#?}", t.thread_id());
1340 let _ = writeln!(&mut msg, "{:#?}", t.backtrace());
1341 }
1342 }
1343
1344 #[cfg(not(feature = "test_util"))]
1345 eprint!("{msg}");
1346
1347 #[cfg(feature = "test_util")]
1348 {
1349 use std::io::Write;
1352 let _ = write!(&mut std::io::stderr(), "{msg}");
1353 zng_env::exit(-1);
1354 }
1355 }
1356 })
1357 .expect("failed to spawn thread");
1358}
1359#[cfg(not(feature = "deadlock_detection"))]
1364pub fn spawn_deadlock_detection() {}
1365
1366app_local! {
1367 pub(super) static APP_PROCESS_SV: AppProcessService = AppProcessService {
1368 exit_requests: None,
1369 extensions: None,
1370 device_events_filter: zng_var::var(Default::default()),
1371 pause_time_for_updates: zng_var::var(true),
1372 is_suspended: zng_var::var(false),
1373 };
1374}
1375
1376pub(super) struct AppProcessService {
1377 exit_requests: Option<ResponderVar<ExitCancelled>>,
1378 extensions: Option<Arc<AppExtensionsInfo>>,
1379 pub(crate) device_events_filter: Var<DeviceEventsFilter>,
1380 pause_time_for_updates: Var<bool>,
1381 is_suspended: Var<bool>,
1382}
1383impl AppProcessService {
1384 pub(super) fn take_requests(&mut self) -> Option<ResponderVar<ExitCancelled>> {
1385 self.exit_requests.take()
1386 }
1387
1388 fn exit(&mut self) -> ResponseVar<ExitCancelled> {
1389 if let Some(r) = &self.exit_requests {
1390 r.response_var()
1391 } else {
1392 let (responder, response) = response_var();
1393 self.exit_requests = Some(responder);
1394 UPDATES.update(None);
1395 response
1396 }
1397 }
1398
1399 pub(super) fn extensions(&self) -> Arc<AppExtensionsInfo> {
1400 self.extensions
1401 .clone()
1402 .unwrap_or_else(|| Arc::new(AppExtensionsInfo { infos: vec![] }))
1403 }
1404
1405 pub(super) fn set_extensions(&mut self, info: AppExtensionsInfo) {
1406 self.extensions = Some(Arc::new(info));
1407 }
1408
1409 pub(super) fn is_running(&self) -> bool {
1410 self.extensions.is_some()
1411 }
1412}
1413
1414#[derive(Debug)]
1416#[allow(clippy::large_enum_variant)] pub(crate) enum AppEvent {
1418 ViewEvent(zng_view_api::Event),
1420 Event(crate::event::EventUpdateMsg),
1422 Update(UpdateOp, Option<WidgetId>),
1424 ResumeUnwind(PanicPayload),
1426 CheckUpdate,
1428}
1429
1430#[derive(Clone)]
1436pub struct AppEventSender(channel::Sender<AppEvent>);
1437impl AppEventSender {
1438 pub(crate) fn new() -> (Self, channel::Receiver<AppEvent>) {
1439 let (sender, receiver) = channel::unbounded();
1440 (Self(sender), receiver)
1441 }
1442
1443 #[allow(clippy::result_large_err)] fn send_app_event(&self, event: AppEvent) -> Result<(), ChannelError> {
1445 self.0.send_blocking(event)
1446 }
1447
1448 #[allow(clippy::result_large_err)]
1449 fn send_view_event(&self, event: zng_view_api::Event) -> Result<(), ChannelError> {
1450 self.0.send_blocking(AppEvent::ViewEvent(event))
1451 }
1452
1453 pub fn send_update(&self, op: UpdateOp, target: impl Into<Option<WidgetId>>) -> Result<(), ChannelError> {
1455 UpdatesTrace::log_update();
1456 self.send_app_event(AppEvent::Update(op, target.into()))
1457 }
1458
1459 pub(crate) fn send_event(&self, event: crate::event::EventUpdateMsg) -> Result<(), ChannelError> {
1461 self.send_app_event(AppEvent::Event(event))
1462 }
1463
1464 pub fn send_resume_unwind(&self, payload: PanicPayload) -> Result<(), ChannelError> {
1466 self.send_app_event(AppEvent::ResumeUnwind(payload))
1467 }
1468
1469 pub(crate) fn send_check_update(&self) -> Result<(), ChannelError> {
1471 self.send_app_event(AppEvent::CheckUpdate)
1472 }
1473
1474 pub fn waker(&self, target: impl Into<Option<WidgetId>>) -> Waker {
1476 Arc::new(AppWaker(self.0.clone(), target.into())).into()
1477 }
1478}
1479
1480struct AppWaker(channel::Sender<AppEvent>, Option<WidgetId>);
1481impl std::task::Wake for AppWaker {
1482 fn wake(self: std::sync::Arc<Self>) {
1483 self.wake_by_ref()
1484 }
1485 fn wake_by_ref(self: &Arc<Self>) {
1486 let _ = self.0.send_blocking(AppEvent::Update(UpdateOp::Update, self.1));
1487 }
1488}
1489
1490type PanicPayload = Box<dyn std::any::Any + Send + 'static>;
1491
1492event_args! {
1493 pub struct ExitRequestedArgs {
1497
1498 ..
1499
1500 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
1502 list.search_all()
1503 }
1504 }
1505}
1506
1507event! {
1508 pub static EXIT_REQUESTED_EVENT: ExitRequestedArgs;
1516}