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