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