zng_app/
running.rs

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
35/// Represents a running app controlled by an external event loop.
36pub(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    // cleans on drop
52    _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    /// Notify an event directly to the app extensions.
143    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    /// Process a View Process event.
167    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                // TODO
335            }
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            // native dialog responses
430            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            // custom
438            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            // config events
444            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            // `device_events`
483            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            // Others
527            Event::Inited(zng_view_api::Inited { .. }) | Event::Suspended | Event::Disconnected(_) | Event::FrameRendered(_) => {
528                unreachable!()
529            } // handled before coalesce.
530
531            _ => {}
532        }
533    }
534
535    /// Process a [`Event::FrameRendered`] event.
536    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        // view.on_frame_rendered(window_id); // already called in push_coalesce
540        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                    // update ViewProcess immediately.
574                    {
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                    // notify immediately.
595                    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                    // update ViewProcess immediately.
613                    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        // clear timers.
715        let updated_timers = self.loop_timer.awake();
716        if updated_timers {
717            // tick timers and collect not elapsed timers.
718            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; // reuse capacity
729
730        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    /// Does updates, collects pending update generated events and layout + render.
762    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    // apply the current pending update generated events.
835    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    // apply pending layout & render if the view-process is not already rendering.
888    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
945/// Arguments for [`on_app_start`] handlers.
946///
947/// Empty in this release. The handler is called in the new app context so you can use `APP` or
948/// any other app service to access the new app.
949pub struct AppStartArgs {
950    _private: (),
951}
952
953/// Register a `handler` to run when an `APP` starts running in the process.
954///
955/// The `handler` is called in the new app context, just before the "run" future executes, all app service are already available in it.
956///
957/// In `"multi_app"` builds the handler can be called more them once.
958pub 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/// App main loop timer.
967#[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    /// Returns `true` if the `deadline` has elapsed, `false` if the `deadline` was
982    /// registered for future waking.
983    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    /// Register the future `deadline`.
993    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    /// Get next recv deadline.
1004    pub(crate) fn poll(&mut self) -> Option<Deadline> {
1005        self.deadline
1006    }
1007
1008    /// Maybe awake timer.
1009    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    /// Awake timestamp.
1021    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    /// Returns `false` if the loop should break.
1047    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    /// Register a request for process exit with code `0` in the next update.
1092    ///
1093    /// The [`EXIT_REQUESTED_EVENT`] will notify, and if propagation is not cancelled the app process will exit.
1094    ///
1095    /// Returns a response variable that is updated once with the unit value [`ExitCancelled`]
1096    /// if the exit operation is cancelled.
1097    ///
1098    /// See also the [`EXIT_CMD`].
1099    pub fn exit(&self) -> ResponseVar<ExitCancelled> {
1100        APP_PROCESS_SV.write().exit()
1101    }
1102
1103    /// Gets a variable that tracks if the app is suspended by the operating system.
1104    ///
1105    /// Suspended apps cannot create graphics contexts and are likely to be killed if the user does not
1106    /// return. Operations that persist data should flush on suspension.
1107    ///
1108    /// App suspension is controlled by the view-process, the [`VIEW_PROCESS_SUSPENDED_EVENT`] notifies
1109    /// on suspension and the [`VIEW_PROCESS_INITED_EVENT`] notifies a "respawn" on resume.
1110    pub fn is_suspended(&self) -> Var<bool> {
1111        APP_PROCESS_SV.read().is_suspended.read_only()
1112    }
1113}
1114
1115/// App time control.
1116///
1117/// The manual time methods are only recommended for headless apps.
1118impl APP {
1119    /// Gets a variable that configures if [`INSTANT.now`] is the same exact value during each update, info, layout or render pass.
1120    ///
1121    /// Time is paused by default, setting this to `false` will cause [`INSTANT.now`] to read the system time for every call.
1122    ///
1123    /// [`INSTANT.now`]: crate::INSTANT::now
1124    pub fn pause_time_for_update(&self) -> Var<bool> {
1125        APP_PROCESS_SV.read().pause_time_for_updates.clone()
1126    }
1127
1128    /// Pause the [`INSTANT.now`] value, after this call it must be updated manually using
1129    /// [`advance_manual_time`] or [`set_manual_time`]. To resume normal time use [`end_manual_time`].
1130    ///
1131    /// [`INSTANT.now`]: crate::INSTANT::now
1132    /// [`advance_manual_time`]: Self::advance_manual_time
1133    /// [`set_manual_time`]: Self::set_manual_time
1134    /// [`end_manual_time`]: Self::end_manual_time
1135    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    /// Adds the `advance` to the current manual time.
1142    ///
1143    /// Note that you must ensure an update reaches the code that controls manual time, otherwise
1144    /// the app loop may end-up stuck on idle or awaiting a timer that never elapses.
1145    ///
1146    /// # Panics
1147    ///
1148    /// Panics if called before [`start_manual_time`].
1149    ///
1150    /// [`start_manual_time`]: Self::start_manual_time
1151    pub fn advance_manual_time(&self, advance: Duration) {
1152        INSTANT_APP.advance_now(advance);
1153        UPDATES.update(None);
1154    }
1155
1156    /// Set the current [`INSTANT.now`].
1157    ///
1158    /// # Panics
1159    ///
1160    /// Panics if called before [`start_manual_time`].
1161    ///
1162    /// [`INSTANT.now`]: crate::INSTANT::now
1163    /// [`start_manual_time`]: Self::start_manual_time
1164    pub fn set_manual_time(&self, now: DInstant) {
1165        INSTANT_APP.set_now(now);
1166        UPDATES.update(None);
1167    }
1168
1169    /// Resumes normal time.
1170    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    /// Represents the app process [`exit`] request.
1181    ///
1182    /// [`exit`]: APP::exit
1183    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/// Cancellation message of an [exit request].
1192///
1193/// [exit request]: APP::exit
1194#[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    /// Pre-init intrinsic services and commands, must be called before extensions init.
1212    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    /// Returns if exit was requested and not cancelled.
1249    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/// When compiled with `"deadlock_detection"` spawns a thread that monitors for `parking_lot` deadlocks.
1302///
1303/// Note that this method is already called on app scope spawn.
1304/// You can call it before `zng::env::init!` to detect deadlocks in other processes too.
1305#[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                    // test runner captures output and ignores panics in background threads, so
1350                    // we write directly to stderr and exit the process.
1351                    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/// When compiled with `"deadlock_detection"` spawns a thread that monitors for `parking_lot` deadlocks.
1360///
1361/// Note that this method is already called on app scope spawn.
1362/// You can call it before `zng::env::init!` to detect deadlocks in other processes too.
1363#[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/// App events.
1415#[derive(Debug)]
1416#[allow(clippy::large_enum_variant)] // Event is the most used variant
1417pub(crate) enum AppEvent {
1418    /// Event from the View Process.
1419    ViewEvent(zng_view_api::Event),
1420    /// Notify [`Events`](crate::var::Events).
1421    Event(crate::event::EventUpdateMsg),
1422    /// Do an update cycle.
1423    Update(UpdateOp, Option<WidgetId>),
1424    /// Resume a panic in the app main thread.
1425    ResumeUnwind(PanicPayload),
1426    /// Check for pending updates.
1427    CheckUpdate,
1428}
1429
1430/// A sender that can awake apps and insert events into the main loop.
1431///
1432/// A Clone of the sender is available in [`UPDATES.sender`].
1433///
1434/// [`UPDATES.sender`]: crate::update::UPDATES::sender
1435#[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)] // error does not move far up the stack
1444    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    /// Causes an update cycle to happen in the app.
1454    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    /// [`EventSender`](crate::event::EventSender) util.
1460    pub(crate) fn send_event(&self, event: crate::event::EventUpdateMsg) -> Result<(), ChannelError> {
1461        self.send_app_event(AppEvent::Event(event))
1462    }
1463
1464    /// Resume a panic in the app main loop thread.
1465    pub fn send_resume_unwind(&self, payload: PanicPayload) -> Result<(), ChannelError> {
1466        self.send_app_event(AppEvent::ResumeUnwind(payload))
1467    }
1468
1469    /// [`UPDATES`] util.
1470    pub(crate) fn send_check_update(&self) -> Result<(), ChannelError> {
1471        self.send_app_event(AppEvent::CheckUpdate)
1472    }
1473
1474    /// Create an [`Waker`] that causes a [`send_update`](Self::send_update).
1475    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    /// Arguments for [`EXIT_REQUESTED_EVENT`].
1494    ///
1495    /// Requesting `propagation().stop()` on this event cancels the exit.
1496    pub struct ExitRequestedArgs {
1497
1498        ..
1499
1500        /// Broadcast to all.
1501        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
1502            list.search_all()
1503        }
1504    }
1505}
1506
1507event! {
1508    /// Cancellable event raised when app process exit is requested.
1509    ///
1510    /// App exit can be requested using the [`APP`] service or the [`EXIT_CMD`], some extensions
1511    /// also request exit if some conditions are met, for example, `WindowManager` requests it after the last window
1512    /// is closed.
1513    ///
1514    /// Requesting `propagation().stop()` on this event cancels the exit.
1515    pub static EXIT_REQUESTED_EVENT: ExitRequestedArgs;
1516}