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