[go: up one dir, main page]

zng_app/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//!
4//! App process implementation.
5//!
6//! # Widget Instantiation
7//!
8//! See [`enable_widget_macros!`] if you want to instantiate widgets without depending on the `zng` crate.
9//!
10//! # Crate
11//!
12#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
13#![recursion_limit = "256"]
14// suppress nag about very simple boxed closure signatures.
15#![expect(clippy::type_complexity)]
16#![warn(unused_extern_crates)]
17#![warn(missing_docs)]
18
19use std::{
20    any::{TypeId, type_name},
21    collections::HashMap,
22    fmt, ops,
23    path::PathBuf,
24    sync::Arc,
25};
26
27pub mod access;
28pub mod crash_handler;
29pub mod event;
30pub mod handler;
31pub mod render;
32pub mod shortcut;
33pub mod third_party;
34pub mod timer;
35pub mod trace_recorder;
36pub mod update;
37pub mod view_process;
38pub mod widget;
39pub mod window;
40
41mod tests;
42
43use view_process::VIEW_PROCESS;
44use widget::UiTaskWidget;
45#[doc(hidden)]
46pub use zng_layout as layout;
47use zng_txt::Txt;
48#[doc(hidden)]
49pub use zng_var as var;
50
51pub use zng_time::{DInstant, Deadline, INSTANT, InstantMode};
52
53use update::{EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdatesTrace, WidgetUpdates};
54use window::WindowMode;
55use zng_app_context::{AppId, AppScope, LocalContext};
56use zng_task::UiTask;
57
58pub use zng_unique_id::static_id;
59
60/// Enable widget instantiation in crates that can't depend on the `zng` crate.
61///
62/// This must be called at the top of the crate:
63///
64/// ```
65/// // in lib.rs or main.rs
66/// # use zng_app::*;
67/// enable_widget_macros!();
68/// ```
69#[macro_export]
70macro_rules! enable_widget_macros {
71    () => {
72        #[doc(hidden)]
73        #[allow(unused_extern_crates)]
74        extern crate self as zng;
75
76        #[doc(hidden)]
77        pub use $crate::__proc_macro_util;
78    };
79}
80
81#[doc(hidden)]
82#[allow(unused_extern_crates)]
83extern crate self as zng;
84
85#[doc(hidden)]
86#[allow(unused_extern_crates)]
87extern crate self as zng_app; // for doc-tests
88
89#[doc(hidden)]
90pub mod __proc_macro_util {
91    // * don't add glob re-exports, the types leak in rust-analyzer even if all is doc(hidden).
92    // * don't use macro_rules! macros that use $crate , they will fail with "unresolved import" when used from the re-exports.
93
94    #[doc(hidden)]
95    pub use zng_unique_id::static_id;
96
97    #[doc(hidden)]
98    pub mod widget {
99        #[doc(hidden)]
100        pub mod builder {
101            #[doc(hidden)]
102            pub use crate::widget::builder::{
103                AnyArcWidgetHandler, ArcWidgetHandler, Importance, InputKind, PropertyArgs, PropertyId, PropertyInfo, PropertyInput,
104                PropertyInputTypes, PropertyNewArgs, SourceLocation, UiNodeInWhenExprError, UiNodeListInWhenExprError, WgtInfo, WhenInput,
105                WhenInputMember, WhenInputVar, WidgetHandlerInWhenExprError, WidgetType, getter_var, iter_input_build_actions,
106                nest_group_items, new_dyn_other, new_dyn_ui_node, new_dyn_ui_node_list, new_dyn_var, new_dyn_widget_handler, panic_input,
107                state_var, ui_node_list_to_args, ui_node_to_args, value_to_args, var_to_args, when_condition_expr_var,
108                widget_handler_to_args,
109            };
110        }
111
112        #[doc(hidden)]
113        pub mod base {
114            pub use crate::widget::base::{NonWidgetBase, WidgetBase, WidgetExt, WidgetImpl};
115        }
116
117        #[doc(hidden)]
118        pub mod node {
119            pub use crate::widget::node::{
120                ArcNode, ArcNodeList, BoxedUiNode, BoxedUiNodeList, NilUiNode, UiNode, UiNodeList, UiVec, ui_node_list_default,
121            };
122        }
123
124        #[doc(hidden)]
125        pub mod info {
126            pub use crate::widget::info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure};
127        }
128
129        #[doc(hidden)]
130        pub use crate::widget::{easing_property, widget_new};
131
132        #[doc(hidden)]
133        pub use crate::widget::WIDGET;
134    }
135
136    #[doc(hidden)]
137    pub mod update {
138        pub use crate::update::{EventUpdate, WidgetUpdates};
139    }
140
141    #[doc(hidden)]
142    pub mod layout {
143        #[doc(hidden)]
144        pub mod unit {
145            #[doc(hidden)]
146            pub use crate::layout::unit::{PxSize, TimeUnits};
147        }
148
149        #[doc(hidden)]
150        pub mod context {
151            #[doc(hidden)]
152            pub use crate::layout::context::LAYOUT;
153        }
154    }
155
156    #[doc(hidden)]
157    pub mod render {
158        pub use crate::render::{FrameBuilder, FrameUpdate};
159    }
160
161    #[doc(hidden)]
162    pub mod handler {
163        #[doc(hidden)]
164        pub use crate::handler::hn;
165    }
166
167    #[doc(hidden)]
168    pub mod var {
169        #[doc(hidden)]
170        pub use crate::var::{AnyVar, AnyVarValue, BoxedVar, Var, expr_var};
171
172        #[doc(hidden)]
173        pub mod animation {
174            #[doc(hidden)]
175            pub mod easing {
176                #[doc(hidden)]
177                pub use crate::var::animation::easing::{
178                    back, bounce, circ, cubic, cubic_bezier, ease_in, ease_in_out, ease_out, ease_out_in, elastic, expo, linear, none,
179                    quad, quart, quint, reverse, reverse_out, sine, step_ceil, step_floor,
180                };
181            }
182        }
183    }
184}
185
186/// An app extension.
187///
188/// App extensions setup and update core features such as services and events. App instances
189/// are fully composed of app extensions.
190///
191/// See the `zng::app` module level documentation for more details, including the call order of methods
192/// of this trait.
193pub trait AppExtension: 'static {
194    /// Register info abound this extension on the info list.
195    #[inline(always)]
196    fn register(&self, info: &mut AppExtensionsInfo)
197    where
198        Self: Sized,
199    {
200        info.push::<Self>()
201    }
202
203    /// Initializes this extension.
204    #[inline(always)]
205    fn init(&mut self) {}
206
207    /// If the application should notify raw device events.
208    ///
209    /// Device events are raw events not targeting any window, like a mouse move on any part of the screen.
210    /// They tend to be high-volume events so there is a performance cost to activating this. Note that if
211    /// this is `false` you still get the mouse move over windows of the app.
212    ///
213    /// This is called zero or one times before [`init`](Self::init).
214    ///
215    /// Returns `false` by default.
216    #[inline(always)]
217    fn enable_device_events(&self) -> bool {
218        false
219    }
220
221    /// Called just before [`event_ui`](Self::event_ui) when an event notifies.
222    ///
223    /// Extensions can handle this method to intercept event updates before the UI.
224    ///
225    /// Note that this is not related to the `on_event_preview` properties, all UI events
226    /// happen in `event_ui`.
227    #[inline(always)]
228    fn event_preview(&mut self, update: &mut EventUpdate) {
229        let _ = update;
230    }
231
232    /// Called just before [`event`](Self::event).
233    ///
234    /// Only extensions that generate windows should handle this method. The [`UiNode::event`](crate::widget::node::UiNode::event)
235    /// method is called here.
236    #[inline(always)]
237    fn event_ui(&mut self, update: &mut EventUpdate) {
238        let _ = update;
239    }
240
241    /// Called after [`event_ui`](Self::event_ui).
242    ///
243    /// This is the general extensions event handler, it gives the chance for the UI to signal stop propagation.
244    #[inline(always)]
245    fn event(&mut self, update: &mut EventUpdate) {
246        let _ = update;
247    }
248
249    /// Called when info rebuild is requested for windows and widgets.
250    ///
251    /// The [`UiNode::info`] method is called here.
252    ///
253    /// [`UiNode::info`]: crate::widget::node::UiNode::info
254    #[inline(always)]
255    fn info(&mut self, info_widgets: &mut InfoUpdates) {
256        let _ = info_widgets;
257    }
258
259    /// Called just before [`update_ui`](Self::update_ui).
260    ///
261    /// Extensions can handle this method to react to updates before the UI.
262    ///
263    /// Note that this is not related to the `on_event_preview` properties, all UI events
264    /// happen in `update_ui`.
265    #[inline(always)]
266    fn update_preview(&mut self) {}
267
268    /// Called just before [`update`](Self::update).
269    ///
270    /// Only extensions that manage windows should handle this method.
271    ///
272    /// The [`UiNode::update`] method is called here.
273    ///
274    /// [`UiNode::update`]: crate::widget::node::UiNode::update
275    #[inline(always)]
276    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
277        let _ = update_widgets;
278    }
279
280    /// Called after every [`update_ui`](Self::update_ui) and [`info`](Self::info).
281    ///
282    /// This is the general extensions update, it gives the chance for
283    /// the UI to make service requests.
284    #[inline(always)]
285    fn update(&mut self) {}
286
287    /// Called when layout is requested for windows and widgets.
288    ///
289    /// The [`UiNode::layout`] method is called here.
290    ///
291    /// [`UiNode::layout`]: crate::widget::node::UiNode::layout
292    #[inline(always)]
293    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
294        let _ = layout_widgets;
295    }
296
297    /// Called when render is requested for windows and widgets.
298    ///
299    /// The [`UiNode::render`] and [`UiNode::render_update`] methods are called here.
300    ///
301    /// [`UiNode::render`]: crate::widget::node::UiNode::render
302    /// [`UiNode::render_update`]: crate::widget::node::UiNode::render_update
303    #[inline(always)]
304    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
305        let _ = (render_widgets, render_update_widgets);
306    }
307
308    /// Called when the application is exiting.
309    ///
310    /// Update requests and event notifications generated during this call are ignored,
311    /// the extensions will be dropped after every extension received this call.
312    #[inline(always)]
313    fn deinit(&mut self) {}
314
315    /// Gets the extension boxed.
316    ///
317    /// Boxed app extensions also implement `AppExtension`, this method does not double box.
318    #[inline(always)]
319    fn boxed(self) -> Box<dyn AppExtensionBoxed>
320    where
321        Self: Sized,
322    {
323        Box::new(self)
324    }
325}
326
327/// Boxed version of [`AppExtension`].
328#[doc(hidden)]
329pub trait AppExtensionBoxed: 'static {
330    fn register_boxed(&self, info: &mut AppExtensionsInfo);
331    fn init_boxed(&mut self);
332    fn enable_device_events_boxed(&self) -> bool;
333    fn update_preview_boxed(&mut self);
334    fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates);
335    fn update_boxed(&mut self);
336    fn event_preview_boxed(&mut self, update: &mut EventUpdate);
337    fn event_ui_boxed(&mut self, update: &mut EventUpdate);
338    fn event_boxed(&mut self, update: &mut EventUpdate);
339    fn info_boxed(&mut self, info_widgets: &mut InfoUpdates);
340    fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates);
341    fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
342    fn deinit_boxed(&mut self);
343}
344impl<T: AppExtension> AppExtensionBoxed for T {
345    fn register_boxed(&self, info: &mut AppExtensionsInfo) {
346        self.register(info);
347    }
348
349    fn init_boxed(&mut self) {
350        self.init();
351    }
352
353    fn enable_device_events_boxed(&self) -> bool {
354        self.enable_device_events()
355    }
356
357    fn update_preview_boxed(&mut self) {
358        self.update_preview();
359    }
360
361    fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates) {
362        self.update_ui(updates);
363    }
364
365    fn info_boxed(&mut self, info_widgets: &mut InfoUpdates) {
366        self.info(info_widgets);
367    }
368
369    fn update_boxed(&mut self) {
370        self.update();
371    }
372
373    fn event_preview_boxed(&mut self, update: &mut EventUpdate) {
374        self.event_preview(update);
375    }
376
377    fn event_ui_boxed(&mut self, update: &mut EventUpdate) {
378        self.event_ui(update);
379    }
380
381    fn event_boxed(&mut self, update: &mut EventUpdate) {
382        self.event(update);
383    }
384
385    fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates) {
386        self.layout(layout_widgets);
387    }
388
389    fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
390        self.render(render_widgets, render_update_widgets);
391    }
392
393    fn deinit_boxed(&mut self) {
394        self.deinit();
395    }
396}
397impl AppExtension for Box<dyn AppExtensionBoxed> {
398    fn register(&self, info: &mut AppExtensionsInfo) {
399        self.as_ref().register_boxed(info);
400    }
401
402    fn init(&mut self) {
403        self.as_mut().init_boxed();
404    }
405
406    fn enable_device_events(&self) -> bool {
407        self.as_ref().enable_device_events_boxed()
408    }
409
410    fn update_preview(&mut self) {
411        self.as_mut().update_preview_boxed();
412    }
413
414    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
415        self.as_mut().update_ui_boxed(update_widgets);
416    }
417
418    fn update(&mut self) {
419        self.as_mut().update_boxed();
420    }
421
422    fn event_preview(&mut self, update: &mut EventUpdate) {
423        self.as_mut().event_preview_boxed(update);
424    }
425
426    fn event_ui(&mut self, update: &mut EventUpdate) {
427        self.as_mut().event_ui_boxed(update);
428    }
429
430    fn event(&mut self, update: &mut EventUpdate) {
431        self.as_mut().event_boxed(update);
432    }
433
434    fn info(&mut self, info_widgets: &mut InfoUpdates) {
435        self.as_mut().info_boxed(info_widgets);
436    }
437
438    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
439        self.as_mut().layout_boxed(layout_widgets);
440    }
441
442    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
443        self.as_mut().render_boxed(render_widgets, render_update_widgets);
444    }
445
446    fn deinit(&mut self) {
447        self.as_mut().deinit_boxed();
448    }
449
450    fn boxed(self) -> Box<dyn AppExtensionBoxed>
451    where
452        Self: Sized,
453    {
454        self
455    }
456}
457
458struct TraceAppExt<E: AppExtension>(E);
459impl<E: AppExtension> AppExtension for TraceAppExt<E> {
460    fn register(&self, info: &mut AppExtensionsInfo) {
461        self.0.register(info)
462    }
463
464    fn init(&mut self) {
465        let _span = UpdatesTrace::extension_span::<E>("init");
466        self.0.init();
467    }
468
469    fn enable_device_events(&self) -> bool {
470        self.0.enable_device_events()
471    }
472
473    fn event_preview(&mut self, update: &mut EventUpdate) {
474        let _span = UpdatesTrace::extension_span::<E>("event_preview");
475        self.0.event_preview(update);
476    }
477
478    fn event_ui(&mut self, update: &mut EventUpdate) {
479        let _span = UpdatesTrace::extension_span::<E>("event_ui");
480        self.0.event_ui(update);
481    }
482
483    fn event(&mut self, update: &mut EventUpdate) {
484        let _span = UpdatesTrace::extension_span::<E>("event");
485        self.0.event(update);
486    }
487
488    fn update_preview(&mut self) {
489        let _span = UpdatesTrace::extension_span::<E>("update_preview");
490        self.0.update_preview();
491    }
492
493    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
494        let _span = UpdatesTrace::extension_span::<E>("update_ui");
495        self.0.update_ui(update_widgets);
496    }
497
498    fn update(&mut self) {
499        let _span = UpdatesTrace::extension_span::<E>("update");
500        self.0.update();
501    }
502
503    fn info(&mut self, info_widgets: &mut InfoUpdates) {
504        let _span = UpdatesTrace::extension_span::<E>("info");
505        self.0.info(info_widgets);
506    }
507
508    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
509        let _span = UpdatesTrace::extension_span::<E>("layout");
510        self.0.layout(layout_widgets);
511    }
512
513    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
514        let _span = UpdatesTrace::extension_span::<E>("render");
515        self.0.render(render_widgets, render_update_widgets);
516    }
517
518    fn deinit(&mut self) {
519        let _span = UpdatesTrace::extension_span::<E>("deinit");
520        self.0.deinit();
521    }
522
523    fn boxed(self) -> Box<dyn AppExtensionBoxed>
524    where
525        Self: Sized,
526    {
527        Box::new(self)
528    }
529}
530
531/// Info about an app-extension.
532///
533/// See [`APP::extensions`] for more details.
534#[derive(Clone, Copy)]
535#[non_exhaustive]
536pub struct AppExtensionInfo {
537    /// Extension type ID.
538    pub type_id: TypeId,
539    /// Extension type name.
540    pub type_name: &'static str,
541}
542impl PartialEq for AppExtensionInfo {
543    fn eq(&self, other: &Self) -> bool {
544        self.type_id == other.type_id
545    }
546}
547impl fmt::Debug for AppExtensionInfo {
548    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549        write!(f, "{}", self.type_name)
550    }
551}
552impl Eq for AppExtensionInfo {}
553impl AppExtensionInfo {
554    /// New info for `E`.
555    pub fn new<E: AppExtension>() -> Self {
556        Self {
557            type_id: TypeId::of::<E>(),
558            type_name: type_name::<E>(),
559        }
560    }
561}
562
563/// List of app-extensions that are part of an app.
564#[derive(Clone, PartialEq)]
565pub struct AppExtensionsInfo {
566    infos: Vec<AppExtensionInfo>,
567}
568impl fmt::Debug for AppExtensionsInfo {
569    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570        f.debug_list().entries(&self.infos).finish()
571    }
572}
573impl AppExtensionsInfo {
574    pub(crate) fn start() -> Self {
575        Self { infos: vec![] }
576    }
577
578    /// Push the extension info.
579    pub fn push<E: AppExtension>(&mut self) {
580        let info = AppExtensionInfo::new::<E>();
581        assert!(!self.contains::<E>(), "app-extension `{info:?}` is already in the list");
582        self.infos.push(info);
583    }
584
585    /// Gets if the extension `E` is in the list.
586    pub fn contains<E: AppExtension>(&self) -> bool {
587        self.contains_info(AppExtensionInfo::new::<E>())
588    }
589
590    /// Gets i the extension is in the list.
591    pub fn contains_info(&self, info: AppExtensionInfo) -> bool {
592        self.infos.iter().any(|e| e.type_id == info.type_id)
593    }
594
595    /// Panics if the extension `E` is not present.
596    #[track_caller]
597    pub fn require<E: AppExtension>(&self) {
598        let info = AppExtensionInfo::new::<E>();
599        assert!(self.contains_info(info), "app-extension `{info:?}` is required");
600    }
601}
602impl ops::Deref for AppExtensionsInfo {
603    type Target = [AppExtensionInfo];
604
605    fn deref(&self) -> &Self::Target {
606        &self.infos
607    }
608}
609
610/// Desired next step of app main loop.
611#[derive(Copy, Clone, Debug, PartialEq, Eq)]
612#[must_use = "methods that return `AppControlFlow` expect to be inside a controlled loop"]
613pub enum AppControlFlow {
614    /// Immediately try to receive more app events.
615    Poll,
616    /// Sleep until an app event is received.
617    ///
618    /// Note that a deadline might be set in case a timer is running.
619    Wait,
620    /// Exit the loop and drop the app.
621    Exit,
622}
623impl AppControlFlow {
624    /// Assert that the value is [`AppControlFlow::Wait`].
625    #[track_caller]
626    pub fn assert_wait(self) {
627        assert_eq!(AppControlFlow::Wait, self)
628    }
629
630    /// Assert that the value is [`AppControlFlow::Exit`].
631    #[track_caller]
632    pub fn assert_exit(self) {
633        assert_eq!(AppControlFlow::Exit, self)
634    }
635}
636
637/// A headless app controller.
638///
639/// Headless apps don't cause external side-effects like visible windows and don't listen to system events.
640/// They can be used for creating apps like a command line app that renders widgets, or for creating integration tests.
641///
642/// You can start a headless app using [`AppExtended::run_headless`].
643pub struct HeadlessApp {
644    app: RunningApp<Box<dyn AppExtensionBoxed>>,
645}
646impl HeadlessApp {
647    /// If headless rendering is enabled.
648    ///
649    /// When enabled windows are still not visible but frames will be rendered and the frame
650    /// image can be requested.
651    ///
652    /// Note that [`UiNode::render`] is still called when a renderer is disabled and you can still
653    /// query the latest frame from `WINDOWS.widget_tree`. The only thing that
654    /// is disabled is the actual renderer that converts display lists to pixels.
655    ///
656    /// [`UiNode::render`]: crate::widget::node::UiNode::render
657    pub fn renderer_enabled(&mut self) -> bool {
658        VIEW_PROCESS.is_available()
659    }
660
661    /// Does updates unobserved.
662    ///
663    /// See [`update_observed`] for more details.
664    ///
665    /// [`update_observed`]: HeadlessApp::update
666    pub fn update(&mut self, wait_app_event: bool) -> AppControlFlow {
667        self.update_observed(&mut (), wait_app_event)
668    }
669
670    /// Does updates observing [`update`] only.
671    ///
672    /// See [`update_observed`] for more details.
673    ///
674    /// [`update`]: AppEventObserver::update
675    /// [`update_observed`]: HeadlessApp::update
676    pub fn update_observe(&mut self, on_update: impl FnMut(), wait_app_event: bool) -> AppControlFlow {
677        struct Observer<F>(F);
678        impl<F: FnMut()> AppEventObserver for Observer<F> {
679            fn update(&mut self) {
680                (self.0)()
681            }
682        }
683        let mut observer = Observer(on_update);
684
685        self.update_observed(&mut observer, wait_app_event)
686    }
687
688    /// Does updates observing [`event`] only.
689    ///
690    /// See [`update_observed`] for more details.
691    ///
692    /// [`event`]: AppEventObserver::event
693    /// [`update_observed`]: HeadlessApp::update
694    pub fn update_observe_event(&mut self, on_event: impl FnMut(&mut EventUpdate), wait_app_event: bool) -> AppControlFlow {
695        struct Observer<F>(F);
696        impl<F: FnMut(&mut EventUpdate)> AppEventObserver for Observer<F> {
697            fn event(&mut self, update: &mut EventUpdate) {
698                (self.0)(update);
699            }
700        }
701        let mut observer = Observer(on_event);
702        self.update_observed(&mut observer, wait_app_event)
703    }
704
705    /// Does updates with an [`AppEventObserver`].
706    ///
707    /// If `wait_app_event` is `true` the thread sleeps until at least one app event is received or a timer elapses,
708    /// if it is `false` only responds to app events already in the buffer.
709    pub fn update_observed<O: AppEventObserver>(&mut self, observer: &mut O, mut wait_app_event: bool) -> AppControlFlow {
710        if self.app.has_exited() {
711            return AppControlFlow::Exit;
712        }
713
714        loop {
715            match self.app.poll(wait_app_event, observer) {
716                AppControlFlow::Poll => {
717                    wait_app_event = false;
718                    continue;
719                }
720                flow => return flow,
721            }
722        }
723    }
724
725    /// Execute the async `task` in the UI thread, updating the app until it finishes or the app shuts-down.
726    ///
727    /// Returns the task result if the app has not shut-down.
728    pub fn run_task<R, T>(&mut self, task: impl IntoFuture<IntoFuture = T>) -> Option<R>
729    where
730        R: 'static,
731        T: Future<Output = R> + Send + Sync + 'static,
732    {
733        let mut task = UiTask::new(None, task);
734
735        let mut flow = self.update_observe(
736            || {
737                task.update();
738            },
739            false,
740        );
741
742        if task.update().is_some() {
743            let r = task.into_result().ok();
744            debug_assert!(r.is_some());
745            return r;
746        }
747
748        let mut n = 0;
749        while flow != AppControlFlow::Exit {
750            flow = self.update_observe(
751                || {
752                    task.update();
753                },
754                true,
755            );
756
757            if n == 10_000 {
758                tracing::error!("excessive future awaking, run_task ran 10_000 update cycles without finishing");
759            } else if n == 100_000 {
760                panic!("run_task stuck, ran 100_000 update cycles without finishing");
761            }
762            n += 1;
763
764            match task.into_result() {
765                Ok(r) => return Some(r),
766                Err(t) => task = t,
767            }
768        }
769        task.cancel();
770
771        None
772    }
773
774    /// Requests and wait for app exit.
775    ///
776    /// Forces deinit if exit is cancelled.
777    pub fn exit(mut self) {
778        self.run_task(async move {
779            let req = APP.exit();
780            req.wait_rsp().await;
781        });
782    }
783
784    /// If the app has exited.
785    ///
786    /// Exited apps cannot update anymore. The app should be dropped to unload the app scope.
787    pub fn has_exited(&self) -> bool {
788        self.app.has_exited()
789    }
790}
791
792/// Observer for [`HeadlessApp::update_observed`].
793///
794/// This works like a temporary app extension that runs only for the update call.
795pub trait AppEventObserver {
796    /// Called for each raw event received.
797    fn raw_event(&mut self, ev: &zng_view_api::Event) {
798        let _ = ev;
799    }
800
801    /// Called just after [`AppExtension::event_preview`].
802    fn event_preview(&mut self, update: &mut EventUpdate) {
803        let _ = update;
804    }
805
806    /// Called just after [`AppExtension::event_ui`].
807    fn event_ui(&mut self, update: &mut EventUpdate) {
808        let _ = update;
809    }
810
811    /// Called just after [`AppExtension::event`].
812    fn event(&mut self, update: &mut EventUpdate) {
813        let _ = update;
814    }
815
816    /// Called just after [`AppExtension::update_preview`].
817    fn update_preview(&mut self) {}
818
819    /// Called just after [`AppExtension::update_ui`].
820    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
821        let _ = update_widgets;
822    }
823
824    /// Called just after [`AppExtension::update`].
825    fn update(&mut self) {}
826
827    /// Called just after [`AppExtension::info`].
828    fn info(&mut self, info_widgets: &mut InfoUpdates) {
829        let _ = info_widgets;
830    }
831
832    /// Called just after [`AppExtension::layout`].
833    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
834        let _ = layout_widgets;
835    }
836
837    /// Called just after [`AppExtension::render`].
838    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
839        let _ = (render_widgets, render_update_widgets);
840    }
841
842    /// Cast to dynamically dispatched observer, this can help avoid code bloat.
843    ///
844    /// The app methods that accept observers automatically use this method if the feature `"dyn_app_extension"` is active.
845    fn as_dyn(&mut self) -> DynAppEventObserver<'_>
846    where
847        Self: Sized,
848    {
849        DynAppEventObserver(self)
850    }
851}
852/// Nil observer, does nothing.
853impl AppEventObserver for () {}
854
855#[doc(hidden)]
856pub struct DynAppEventObserver<'a>(&'a mut dyn AppEventObserverDyn);
857
858trait AppEventObserverDyn {
859    fn raw_event_dyn(&mut self, ev: &zng_view_api::Event);
860    fn event_preview_dyn(&mut self, update: &mut EventUpdate);
861    fn event_ui_dyn(&mut self, update: &mut EventUpdate);
862    fn event_dyn(&mut self, update: &mut EventUpdate);
863    fn update_preview_dyn(&mut self);
864    fn update_ui_dyn(&mut self, updates: &mut WidgetUpdates);
865    fn update_dyn(&mut self);
866    fn info_dyn(&mut self, info_widgets: &mut InfoUpdates);
867    fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates);
868    fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
869}
870impl<O: AppEventObserver> AppEventObserverDyn for O {
871    fn raw_event_dyn(&mut self, ev: &zng_view_api::Event) {
872        self.raw_event(ev)
873    }
874
875    fn event_preview_dyn(&mut self, update: &mut EventUpdate) {
876        self.event_preview(update)
877    }
878
879    fn event_ui_dyn(&mut self, update: &mut EventUpdate) {
880        self.event_ui(update)
881    }
882
883    fn event_dyn(&mut self, update: &mut EventUpdate) {
884        self.event(update)
885    }
886
887    fn update_preview_dyn(&mut self) {
888        self.update_preview()
889    }
890
891    fn update_ui_dyn(&mut self, update_widgets: &mut WidgetUpdates) {
892        self.update_ui(update_widgets)
893    }
894
895    fn update_dyn(&mut self) {
896        self.update()
897    }
898
899    fn info_dyn(&mut self, info_widgets: &mut InfoUpdates) {
900        self.info(info_widgets)
901    }
902
903    fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates) {
904        self.layout(layout_widgets)
905    }
906
907    fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
908        self.render(render_widgets, render_update_widgets)
909    }
910}
911impl AppEventObserver for DynAppEventObserver<'_> {
912    fn raw_event(&mut self, ev: &zng_view_api::Event) {
913        self.0.raw_event_dyn(ev)
914    }
915
916    fn event_preview(&mut self, update: &mut EventUpdate) {
917        self.0.event_preview_dyn(update)
918    }
919
920    fn event_ui(&mut self, update: &mut EventUpdate) {
921        self.0.event_ui_dyn(update)
922    }
923
924    fn event(&mut self, update: &mut EventUpdate) {
925        self.0.event_dyn(update)
926    }
927
928    fn update_preview(&mut self) {
929        self.0.update_preview_dyn()
930    }
931
932    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
933        self.0.update_ui_dyn(update_widgets)
934    }
935
936    fn update(&mut self) {
937        self.0.update_dyn()
938    }
939
940    fn info(&mut self, info_widgets: &mut InfoUpdates) {
941        self.0.info_dyn(info_widgets)
942    }
943
944    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
945        self.0.layout_dyn(layout_widgets)
946    }
947
948    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
949        self.0.render_dyn(render_widgets, render_update_widgets)
950    }
951
952    fn as_dyn(&mut self) -> DynAppEventObserver<'_> {
953        DynAppEventObserver(self.0)
954    }
955}
956
957impl AppExtension for () {
958    fn register(&self, _: &mut AppExtensionsInfo) {}
959}
960impl<A: AppExtension, B: AppExtension> AppExtension for (A, B) {
961    fn init(&mut self) {
962        self.0.init();
963        self.1.init();
964    }
965
966    fn register(&self, info: &mut AppExtensionsInfo) {
967        self.0.register(info);
968        self.1.register(info);
969    }
970
971    fn enable_device_events(&self) -> bool {
972        self.0.enable_device_events() || self.1.enable_device_events()
973    }
974
975    fn update_preview(&mut self) {
976        self.0.update_preview();
977        self.1.update_preview();
978    }
979
980    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
981        self.0.update_ui(update_widgets);
982        self.1.update_ui(update_widgets);
983    }
984
985    fn update(&mut self) {
986        self.0.update();
987        self.1.update();
988    }
989
990    fn info(&mut self, info_widgets: &mut InfoUpdates) {
991        self.0.info(info_widgets);
992        self.1.info(info_widgets);
993    }
994
995    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
996        self.0.layout(layout_widgets);
997        self.1.layout(layout_widgets);
998    }
999
1000    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1001        self.0.render(render_widgets, render_update_widgets);
1002        self.1.render(render_widgets, render_update_widgets);
1003    }
1004
1005    fn event_preview(&mut self, update: &mut EventUpdate) {
1006        self.0.event_preview(update);
1007        self.1.event_preview(update);
1008    }
1009
1010    fn event_ui(&mut self, update: &mut EventUpdate) {
1011        self.0.event_ui(update);
1012        self.1.event_ui(update);
1013    }
1014
1015    fn event(&mut self, update: &mut EventUpdate) {
1016        self.0.event(update);
1017        self.1.event(update);
1018    }
1019
1020    fn deinit(&mut self) {
1021        self.1.deinit();
1022        self.0.deinit();
1023    }
1024}
1025
1026#[cfg(feature = "dyn_app_extension")]
1027impl AppExtension for Vec<Box<dyn AppExtensionBoxed>> {
1028    fn init(&mut self) {
1029        for ext in self {
1030            ext.init();
1031        }
1032    }
1033
1034    fn register(&self, info: &mut AppExtensionsInfo) {
1035        for ext in self {
1036            ext.register(info);
1037        }
1038    }
1039
1040    fn enable_device_events(&self) -> bool {
1041        self.iter().any(|e| e.enable_device_events())
1042    }
1043
1044    fn update_preview(&mut self) {
1045        for ext in self {
1046            ext.update_preview();
1047        }
1048    }
1049
1050    fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
1051        for ext in self {
1052            ext.update_ui(update_widgets);
1053        }
1054    }
1055
1056    fn update(&mut self) {
1057        for ext in self {
1058            ext.update();
1059        }
1060    }
1061
1062    fn event_preview(&mut self, update: &mut EventUpdate) {
1063        for ext in self {
1064            ext.event_preview(update);
1065        }
1066    }
1067
1068    fn event_ui(&mut self, update: &mut EventUpdate) {
1069        for ext in self {
1070            ext.event_ui(update);
1071        }
1072    }
1073
1074    fn event(&mut self, update: &mut EventUpdate) {
1075        for ext in self {
1076            ext.event(update);
1077        }
1078    }
1079
1080    fn info(&mut self, info_widgets: &mut InfoUpdates) {
1081        for ext in self {
1082            ext.info(info_widgets);
1083        }
1084    }
1085
1086    fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
1087        for ext in self {
1088            ext.layout(layout_widgets);
1089        }
1090    }
1091
1092    fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1093        for ext in self {
1094            ext.render(render_widgets, render_update_widgets);
1095        }
1096    }
1097
1098    fn deinit(&mut self) {
1099        for ext in self.iter_mut().rev() {
1100            ext.deinit();
1101        }
1102    }
1103}
1104
1105/// Start and manage an app process.
1106pub struct APP;
1107impl APP {
1108    /// If the crate was built with `feature="multi_app"`.
1109    ///
1110    /// If `true` multiple apps can run in the same process, but only one app per thread at a time.
1111    pub fn multi_app_enabled(&self) -> bool {
1112        cfg!(feature = "multi_app")
1113    }
1114
1115    /// If an app is already running in the current thread.
1116    ///
1117    /// Apps are *running* as soon as they start building, and stop running after
1118    /// [`AppExtended::run`] returns or the [`HeadlessApp`] is dropped.
1119    ///
1120    /// You can use [`app_local!`] to create *static* resources that live for the app lifetime.
1121    ///
1122    /// [`app_local!`]: zng_app_context::app_local
1123    pub fn is_running(&self) -> bool {
1124        LocalContext::current_app().is_some()
1125    }
1126
1127    /// Gets the unique ID of the current app.
1128    ///
1129    /// This ID usually does not change as most apps only run once per process, but it can change often during tests.
1130    /// Resources that interact with [`app_local!`] values can use this ID to ensure that they are still operating in the same
1131    /// app.
1132    ///
1133    /// [`app_local!`]: zng_app_context::app_local
1134    pub fn id(&self) -> Option<AppId> {
1135        LocalContext::current_app()
1136    }
1137
1138    #[cfg(not(feature = "multi_app"))]
1139    fn assert_can_run_single() {
1140        use std::sync::atomic::*;
1141        static CAN_RUN: AtomicBool = AtomicBool::new(true);
1142
1143        if !CAN_RUN.swap(false, Ordering::SeqCst) {
1144            panic!("only one app is allowed per process")
1145        }
1146    }
1147
1148    fn assert_can_run() {
1149        #[cfg(not(feature = "multi_app"))]
1150        Self::assert_can_run_single();
1151        if APP.is_running() {
1152            panic!("only one app is allowed per thread")
1153        }
1154    }
1155
1156    /// Returns a [`WindowMode`] value that indicates if the app is headless, headless with renderer or headed.
1157    ///
1158    /// Note that specific windows can be in headless mode even if the app is headed.
1159    pub fn window_mode(&self) -> WindowMode {
1160        if VIEW_PROCESS.is_available() {
1161            if VIEW_PROCESS.is_headless_with_render() {
1162                WindowMode::HeadlessWithRenderer
1163            } else {
1164                WindowMode::Headed
1165            }
1166        } else {
1167            WindowMode::Headless
1168        }
1169    }
1170    /// List of app extensions that are part of the current app.
1171    pub fn extensions(&self) -> Arc<AppExtensionsInfo> {
1172        APP_PROCESS_SV.read().extensions()
1173    }
1174
1175    /// If device events are enabled for the current app.
1176    ///
1177    /// See [`AppExtension::enable_device_events`] for more details.
1178    pub fn device_events(&self) -> bool {
1179        APP_PROCESS_SV.read().device_events
1180    }
1181}
1182
1183impl APP {
1184    /// Starts building an application with no extensions.
1185    #[cfg(feature = "dyn_app_extension")]
1186    pub fn minimal(&self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1187        zng_env::init_process_name("app-process");
1188
1189        #[cfg(debug_assertions)]
1190        print_tracing(tracing::Level::INFO);
1191        assert_not_view_process();
1192        Self::assert_can_run();
1193        check_deadlock();
1194
1195        let _ = INSTANT.now();
1196        let scope = LocalContext::start_app(AppId::new_unique());
1197        AppExtended {
1198            extensions: vec![],
1199            view_process_exe: None,
1200            view_process_env: HashMap::new(),
1201            _cleanup: scope,
1202        }
1203    }
1204
1205    /// Starts building an application with no extensions.
1206    #[cfg(not(feature = "dyn_app_extension"))]
1207    pub fn minimal(&self) -> AppExtended<()> {
1208        #[cfg(debug_assertions)]
1209        print_tracing(tracing::Level::INFO);
1210        assert_not_view_process();
1211        Self::assert_can_run();
1212        check_deadlock();
1213        let scope = LocalContext::start_app(AppId::new_unique());
1214        AppExtended {
1215            extensions: (),
1216            view_process_exe: None,
1217            view_process_env: HashMap::new(),
1218            _cleanup: scope,
1219        }
1220    }
1221}
1222
1223/// Application builder.
1224///
1225/// You can use `APP` to start building the app.
1226pub struct AppExtended<E: AppExtension> {
1227    extensions: E,
1228    view_process_exe: Option<PathBuf>,
1229    view_process_env: HashMap<Txt, Txt>,
1230
1231    // cleanup on drop.
1232    _cleanup: AppScope,
1233}
1234#[cfg(feature = "dyn_app_extension")]
1235impl AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1236    /// Includes an application extension.
1237    pub fn extend<F: AppExtension>(mut self, extension: F) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1238        self.extensions.push(TraceAppExt(extension).boxed());
1239        self
1240    }
1241
1242    /// Deprecated.
1243    #[deprecated = "use `enable_input_device_events`"]
1244    pub fn enable_device_events(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1245        self.enable_input_device_events()
1246    }
1247
1248    /// If the application should notify raw input device events.
1249    ///
1250    /// Input device events are raw events not targeting any window, like a mouse move on any part of the screen.
1251    /// They tend to be high-volume events so there is a performance cost to activating this. Note that if
1252    /// this is `false` you still get the mouse move over windows of the app.
1253    pub fn enable_input_device_events(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1254        struct EnableDeviceEvents;
1255        impl AppExtension for EnableDeviceEvents {
1256            fn enable_device_events(&self) -> bool {
1257                true
1258            }
1259        }
1260        self.extend(EnableDeviceEvents)
1261    }
1262
1263    // TODO(breaking) add this after adding the parameter in the view API
1264    // pub fn enable_audio_device(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1265    //
1266    // }
1267
1268    fn run_dyn(self, start: std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
1269        let app = RunningApp::start(
1270            self._cleanup,
1271            self.extensions,
1272            true,
1273            true,
1274            self.view_process_exe,
1275            self.view_process_env,
1276        );
1277
1278        UPDATES.run(start).perm();
1279
1280        app.run_headed();
1281    }
1282
1283    fn run_headless_dyn(self, with_renderer: bool) -> HeadlessApp {
1284        let app = RunningApp::start(
1285            self._cleanup,
1286            self.extensions.boxed(),
1287            false,
1288            with_renderer,
1289            self.view_process_exe,
1290            self.view_process_env,
1291        );
1292
1293        HeadlessApp { app }
1294    }
1295}
1296
1297// Monomorphize dyn app. Without this the entire RunningApp code is generic that must build on the dependent crates.
1298#[cfg(feature = "dyn_app_extension")]
1299impl<E: AppExtension> AppExtended<E> {
1300    fn cast_app(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1301        let app: Box<dyn std::any::Any> = Box::new(self);
1302        match app.downcast::<AppExtended<Vec<Box<dyn AppExtensionBoxed>>>>() {
1303            Ok(ok) => *ok,
1304            Err(e) => {
1305                let app = *e.downcast::<Self>().unwrap();
1306                AppExtended {
1307                    extensions: vec![app.extensions.boxed()],
1308                    view_process_exe: app.view_process_exe,
1309                    view_process_env: app.view_process_env,
1310                    _cleanup: app._cleanup,
1311                }
1312            }
1313        }
1314    }
1315
1316    fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1317        self.cast_app().run_dyn(Box::pin(start))
1318    }
1319
1320    fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1321        self.cast_app().run_headless_dyn(with_renderer)
1322    }
1323}
1324
1325#[cfg(not(feature = "dyn_app_extension"))]
1326impl<E: AppExtension> AppExtended<E> {
1327    /// Includes an application extension.
1328    pub fn extend<F: AppExtension>(self, extension: F) -> AppExtended<impl AppExtension> {
1329        AppExtended {
1330            _cleanup: self._cleanup,
1331            extensions: (self.extensions, TraceAppExt(extension)),
1332            view_process_exe: self.view_process_exe,
1333            view_process_env: self.view_process_env,
1334        }
1335    }
1336
1337    /// If the application should notify raw device events.
1338    ///
1339    /// Device events are raw events not targeting any window, like a mouse move on any part of the screen.
1340    /// They tend to be high-volume events so there is a performance cost to activating this. Note that if
1341    /// this is `false` you still get the mouse move over windows of the app.
1342    pub fn enable_device_events(self) -> AppExtended<impl AppExtension> {
1343        struct EnableDeviceEvents;
1344        impl AppExtension for EnableDeviceEvents {
1345            fn enable_device_events(&self) -> bool {
1346                true
1347            }
1348        }
1349        self.extend(EnableDeviceEvents)
1350    }
1351
1352    fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1353        let app = RunningApp::start(
1354            self._cleanup,
1355            self.extensions,
1356            true,
1357            true,
1358            self.view_process_exe,
1359            self.view_process_env,
1360        );
1361
1362        UPDATES.run(start).perm();
1363
1364        app.run_headed();
1365    }
1366
1367    fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1368        let app = RunningApp::start(
1369            self._cleanup,
1370            self.extensions.boxed(),
1371            false,
1372            with_renderer,
1373            self.view_process_exe,
1374            self.view_process_env,
1375        );
1376
1377        HeadlessApp { app }
1378    }
1379}
1380impl<E: AppExtension> AppExtended<E> {
1381    /// Set the path to the executable for the *View Process*.
1382    ///
1383    /// By the default the current executable is started again as a *View Process*, you can use
1384    /// two executables instead, by setting this value.
1385    ///
1386    /// Note that the `view_process_exe` must start a view server and both
1387    /// executables must be build using the same exact [`VERSION`].
1388    ///
1389    /// [`VERSION`]: zng_view_api::VERSION  
1390    pub fn view_process_exe(mut self, view_process_exe: impl Into<PathBuf>) -> Self {
1391        self.view_process_exe = Some(view_process_exe.into());
1392        self
1393    }
1394
1395    /// Set an env variable for the view-process.
1396    pub fn view_process_env(mut self, name: impl Into<Txt>, value: impl Into<Txt>) -> Self {
1397        self.view_process_env.insert(name.into(), value.into());
1398        self
1399    }
1400
1401    /// Starts the app, then starts polling `start` to run.
1402    ///
1403    /// This method only returns when the app has exited.
1404    ///
1405    /// The `start` task runs in a [`UiTask`] in the app context, note that it only needs to start the app, usually
1406    /// by opening a window, the app will keep running after `start` is finished.
1407    pub fn run<F: Future<Output = ()> + Send + 'static>(self, start: impl IntoFuture<IntoFuture = F>) {
1408        let start = start.into_future();
1409        #[cfg(feature = "dyn_closure")]
1410        let start = Box::pin(start);
1411        self.run_impl(start)
1412    }
1413
1414    /// Initializes extensions in headless mode and returns an [`HeadlessApp`].
1415    ///
1416    /// If `with_renderer` is `true` spawns a renderer process for headless rendering. See [`HeadlessApp::renderer_enabled`]
1417    /// for more details.
1418    pub fn run_headless(self, with_renderer: bool) -> HeadlessApp {
1419        self.run_headless_impl(with_renderer)
1420    }
1421}
1422
1423// this module is declared here on purpose so that advanced `impl APP` blocks show later in the docs.
1424mod running;
1425pub use running::*;
1426
1427mod private {
1428    // https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
1429    pub trait Sealed {}
1430}
1431
1432/// Enables [`tracing`] events printing if a subscriber is not already set.
1433///
1434/// All non-fatal errors in the Zng project are logged using tracing.
1435///
1436/// In debug builds this function is called automatically with level INFO on app start.
1437///
1438/// In `"wasm32"` builds logs to the browser console.
1439///
1440/// In `"android"` builds logs to logcat.
1441///
1442/// See also [`test_log`] to enable panicking on error log.
1443///
1444/// See also [`print_tracing_filter`] for the filter used by this.
1445///
1446/// [`tracing`]: https://docs.rs/tracing
1447pub fn print_tracing(max: tracing::Level) -> bool {
1448    use tracing_subscriber::prelude::*;
1449
1450    let layers = tracing_subscriber::registry().with(FilterLayer(max));
1451
1452    #[cfg(target_os = "android")]
1453    let layers = layers.with(tracing_android::layer(&zng_env::about().pkg_name).unwrap());
1454
1455    #[cfg(not(target_os = "android"))]
1456    let layers = {
1457        let fmt_layer = tracing_subscriber::fmt::layer().without_time();
1458
1459        #[cfg(target_arch = "wasm32")]
1460        let fmt_layer = fmt_layer.with_ansi(false).with_writer(tracing_web::MakeWebConsoleWriter::new());
1461
1462        layers.with(fmt_layer)
1463    };
1464
1465    layers.try_init().is_ok()
1466}
1467
1468struct FilterLayer(tracing::Level);
1469impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for FilterLayer {
1470    fn enabled(&self, metadata: &tracing::Metadata<'_>, _: tracing_subscriber::layer::Context<'_, S>) -> bool {
1471        print_tracing_filter(&self.0, metadata)
1472    }
1473
1474    fn max_level_hint(&self) -> Option<tracing::metadata::LevelFilter> {
1475        Some(self.0.into())
1476    }
1477
1478    #[cfg(any(test, feature = "test_util"))]
1479    fn on_event(&self, event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
1480        if event.metadata().level() == &tracing::Level::ERROR && APP.is_running() && TEST_LOG.get() {
1481            struct MsgCollector<'a>(&'a mut String);
1482            impl tracing::field::Visit for MsgCollector<'_> {
1483                fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn fmt::Debug) {
1484                    use std::fmt::Write;
1485                    write!(self.0, "\n  {} = {:?}", field.name(), value).unwrap();
1486                }
1487            }
1488
1489            let meta = event.metadata();
1490            let file = meta.file().unwrap_or("");
1491            let line = meta.line().unwrap_or(0);
1492
1493            let mut msg = format!("[{file}:{line}]");
1494            event.record(&mut MsgCollector(&mut msg));
1495
1496            panic!("[LOG-ERROR]{msg}")
1497        }
1498    }
1499}
1500/// Filter used by [`print_tracing`], removes some log noise from dependencies.
1501///
1502/// Use `tracing_subscriber::filter::FilterFn` plug this filter into a tracing setup.
1503pub fn print_tracing_filter(level: &tracing::Level, metadata: &tracing::Metadata) -> bool {
1504    if metadata.level() > level {
1505        return false;
1506    }
1507
1508    if metadata.level() == &tracing::Level::INFO {
1509        // suppress large info about texture cache
1510        if metadata.target() == "zng_webrender::device::gl" {
1511            return false;
1512        }
1513        // suppress config dump
1514        if metadata.target() == "zng_webrender::renderer::init" {
1515            return false;
1516        }
1517    } else if metadata.level() == &tracing::Level::WARN {
1518        // suppress webrender warnings:
1519        //
1520        if metadata.target() == "zng_webrender::device::gl" {
1521            // Suppress "Cropping texture upload Box2D((0, 0), (0, 1)) to None"
1522            // This happens when an empty frame is rendered.
1523            if metadata.line() == Some(4647) {
1524                return false;
1525            }
1526        }
1527
1528        // suppress font-kit warnings:
1529        //
1530        if metadata.target() == "font_kit::loaders::freetype" {
1531            // Suppress "$fn(): found invalid platform ID $n"
1532            // This does not look fully implemented and generates a lot of warns
1533            // with the default Ubuntu font set all with valid platform IDs.
1534            if metadata.line() == Some(734) {
1535                return false;
1536            }
1537        }
1538    }
1539
1540    true
1541}
1542
1543/// Modifies the [`print_tracing`] subscriber to panic for error logs in the current app.
1544#[cfg(any(test, feature = "test_util"))]
1545pub fn test_log() {
1546    TEST_LOG.set(true);
1547}
1548
1549#[cfg(any(test, feature = "test_util"))]
1550zng_app_context::app_local! {
1551    static TEST_LOG: bool = false;
1552}
1553
1554#[doc(hidden)]
1555pub fn name_from_pkg_name(name: &'static str) -> Txt {
1556    let mut n = String::new();
1557    let mut sep = "";
1558    for part in name.split(&['-', '_']) {
1559        n.push_str(sep);
1560        let mut chars = part.char_indices();
1561        let (_, c) = chars.next().unwrap();
1562        c.to_uppercase().for_each(|c| n.push(c));
1563        if let Some((i, _)) = chars.next() {
1564            n.push_str(&part[i..]);
1565        }
1566        sep = " ";
1567    }
1568    n.into()
1569}
1570
1571#[doc(hidden)]
1572pub fn txt_from_pkg_meta(value: &'static str) -> Txt {
1573    value.into()
1574}