1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
13#![recursion_limit = "256"]
14#![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 memory_profiler;
32pub mod render;
33pub mod shortcut;
34pub mod third_party;
35pub mod timer;
36pub mod trace_recorder;
37pub mod update;
38pub mod view_process;
39pub mod widget;
40pub mod window;
41
42mod tests;
43
44use view_process::VIEW_PROCESS;
45use widget::UiTaskWidget;
46#[doc(hidden)]
47pub use zng_layout as layout;
48use zng_txt::Txt;
49#[doc(hidden)]
50pub use zng_var as var;
51use zng_var::Var;
52
53pub use zng_time::{DInstant, Deadline, INSTANT, InstantMode};
54
55use update::{EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdatesTrace, WidgetUpdates};
56use window::WindowMode;
57use zng_app_context::{AppId, AppScope, LocalContext};
58use zng_task::UiTask;
59
60pub use zng_unique_id::static_id;
61
62#[macro_export]
72macro_rules! enable_widget_macros {
73 () => {
74 #[doc(hidden)]
75 #[allow(unused_extern_crates)]
76 extern crate self as zng;
77
78 #[doc(hidden)]
79 pub use $crate::__proc_macro_util;
80 };
81}
82
83#[doc(hidden)]
84#[allow(unused_extern_crates)]
85extern crate self as zng;
86
87#[doc(hidden)]
88#[allow(unused_extern_crates)]
89extern crate self as zng_app; #[doc(hidden)]
92pub mod __proc_macro_util {
93 #[doc(hidden)]
97 pub use zng_unique_id::static_id;
98
99 #[doc(hidden)]
100 pub mod widget {
101 #[doc(hidden)]
102 pub mod builder {
103 #[doc(hidden)]
104 pub use crate::widget::builder::{
105 AnyArcHandler, HandlerInWhenExprError, Importance, InputKind, PropertyArgs, PropertyId, PropertyInfo, PropertyInput,
106 PropertyInputTypes, PropertyNewArgs, SourceLocation, UiNodeInWhenExprError, WgtInfo, WhenInput, WhenInputMember,
107 WhenInputVar, WidgetBuilding, WidgetType, handler_to_args, iter_input_attributes, nest_group_items, new_dyn_handler,
108 new_dyn_other, new_dyn_ui_node, new_dyn_var, panic_input, ui_node_to_args, value_to_args, var_getter, var_state,
109 var_to_args,
110 };
111 }
112
113 #[doc(hidden)]
114 pub mod base {
115 pub use crate::widget::base::{NonWidgetBase, WidgetBase, WidgetExt, WidgetImpl};
116 }
117
118 #[doc(hidden)]
119 pub mod node {
120 pub use crate::widget::node::{ArcNode, IntoUiNode, UiNode};
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::{ArcHandler, hn};
164 }
165
166 #[doc(hidden)]
167 pub mod var {
168 #[doc(hidden)]
169 pub use crate::var::{AnyVar, AnyVarValue, 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
185pub trait AppExtension: 'static {
193 #[inline(always)]
195 fn register(&self, info: &mut AppExtensionsInfo)
196 where
197 Self: Sized,
198 {
199 info.push::<Self>()
200 }
201
202 #[inline(always)]
204 fn init(&mut self) {}
205
206 #[inline(always)]
213 fn event_preview(&mut self, update: &mut EventUpdate) {
214 let _ = update;
215 }
216
217 #[inline(always)]
222 fn event_ui(&mut self, update: &mut EventUpdate) {
223 let _ = update;
224 }
225
226 #[inline(always)]
230 fn event(&mut self, update: &mut EventUpdate) {
231 let _ = update;
232 }
233
234 #[inline(always)]
240 fn info(&mut self, info_widgets: &mut InfoUpdates) {
241 let _ = info_widgets;
242 }
243
244 #[inline(always)]
251 fn update_preview(&mut self) {}
252
253 #[inline(always)]
261 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
262 let _ = update_widgets;
263 }
264
265 #[inline(always)]
270 fn update(&mut self) {}
271
272 #[inline(always)]
278 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
279 let _ = layout_widgets;
280 }
281
282 #[inline(always)]
289 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
290 let _ = (render_widgets, render_update_widgets);
291 }
292
293 #[inline(always)]
298 fn deinit(&mut self) {}
299
300 #[inline(always)]
304 fn boxed(self) -> Box<dyn AppExtensionBoxed>
305 where
306 Self: Sized,
307 {
308 Box::new(self)
309 }
310}
311
312#[doc(hidden)]
314pub trait AppExtensionBoxed: 'static {
315 fn register_boxed(&self, info: &mut AppExtensionsInfo);
316 fn init_boxed(&mut self);
317 fn update_preview_boxed(&mut self);
318 fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates);
319 fn update_boxed(&mut self);
320 fn event_preview_boxed(&mut self, update: &mut EventUpdate);
321 fn event_ui_boxed(&mut self, update: &mut EventUpdate);
322 fn event_boxed(&mut self, update: &mut EventUpdate);
323 fn info_boxed(&mut self, info_widgets: &mut InfoUpdates);
324 fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates);
325 fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
326 fn deinit_boxed(&mut self);
327}
328impl<T: AppExtension> AppExtensionBoxed for T {
329 fn register_boxed(&self, info: &mut AppExtensionsInfo) {
330 self.register(info);
331 }
332
333 fn init_boxed(&mut self) {
334 self.init();
335 }
336
337 fn update_preview_boxed(&mut self) {
338 self.update_preview();
339 }
340
341 fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates) {
342 self.update_ui(updates);
343 }
344
345 fn info_boxed(&mut self, info_widgets: &mut InfoUpdates) {
346 self.info(info_widgets);
347 }
348
349 fn update_boxed(&mut self) {
350 self.update();
351 }
352
353 fn event_preview_boxed(&mut self, update: &mut EventUpdate) {
354 self.event_preview(update);
355 }
356
357 fn event_ui_boxed(&mut self, update: &mut EventUpdate) {
358 self.event_ui(update);
359 }
360
361 fn event_boxed(&mut self, update: &mut EventUpdate) {
362 self.event(update);
363 }
364
365 fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates) {
366 self.layout(layout_widgets);
367 }
368
369 fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
370 self.render(render_widgets, render_update_widgets);
371 }
372
373 fn deinit_boxed(&mut self) {
374 self.deinit();
375 }
376}
377impl AppExtension for Box<dyn AppExtensionBoxed> {
378 fn register(&self, info: &mut AppExtensionsInfo) {
379 self.as_ref().register_boxed(info);
380 }
381
382 fn init(&mut self) {
383 self.as_mut().init_boxed();
384 }
385
386 fn update_preview(&mut self) {
387 self.as_mut().update_preview_boxed();
388 }
389
390 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
391 self.as_mut().update_ui_boxed(update_widgets);
392 }
393
394 fn update(&mut self) {
395 self.as_mut().update_boxed();
396 }
397
398 fn event_preview(&mut self, update: &mut EventUpdate) {
399 self.as_mut().event_preview_boxed(update);
400 }
401
402 fn event_ui(&mut self, update: &mut EventUpdate) {
403 self.as_mut().event_ui_boxed(update);
404 }
405
406 fn event(&mut self, update: &mut EventUpdate) {
407 self.as_mut().event_boxed(update);
408 }
409
410 fn info(&mut self, info_widgets: &mut InfoUpdates) {
411 self.as_mut().info_boxed(info_widgets);
412 }
413
414 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
415 self.as_mut().layout_boxed(layout_widgets);
416 }
417
418 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
419 self.as_mut().render_boxed(render_widgets, render_update_widgets);
420 }
421
422 fn deinit(&mut self) {
423 self.as_mut().deinit_boxed();
424 }
425
426 fn boxed(self) -> Box<dyn AppExtensionBoxed>
427 where
428 Self: Sized,
429 {
430 self
431 }
432}
433
434struct TraceAppExt<E: AppExtension>(E);
435impl<E: AppExtension> AppExtension for TraceAppExt<E> {
436 fn register(&self, info: &mut AppExtensionsInfo) {
437 self.0.register(info)
438 }
439
440 fn init(&mut self) {
441 let _span = UpdatesTrace::extension_span::<E>("init");
442 self.0.init();
443 }
444
445 fn event_preview(&mut self, update: &mut EventUpdate) {
446 let _span = UpdatesTrace::extension_span::<E>("event_preview");
447 self.0.event_preview(update);
448 }
449
450 fn event_ui(&mut self, update: &mut EventUpdate) {
451 let _span = UpdatesTrace::extension_span::<E>("event_ui");
452 self.0.event_ui(update);
453 }
454
455 fn event(&mut self, update: &mut EventUpdate) {
456 let _span = UpdatesTrace::extension_span::<E>("event");
457 self.0.event(update);
458 }
459
460 fn update_preview(&mut self) {
461 let _span = UpdatesTrace::extension_span::<E>("update_preview");
462 self.0.update_preview();
463 }
464
465 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
466 let _span = UpdatesTrace::extension_span::<E>("update_ui");
467 self.0.update_ui(update_widgets);
468 }
469
470 fn update(&mut self) {
471 let _span = UpdatesTrace::extension_span::<E>("update");
472 self.0.update();
473 }
474
475 fn info(&mut self, info_widgets: &mut InfoUpdates) {
476 let _span = UpdatesTrace::extension_span::<E>("info");
477 self.0.info(info_widgets);
478 }
479
480 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
481 let _span = UpdatesTrace::extension_span::<E>("layout");
482 self.0.layout(layout_widgets);
483 }
484
485 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
486 let _span = UpdatesTrace::extension_span::<E>("render");
487 self.0.render(render_widgets, render_update_widgets);
488 }
489
490 fn deinit(&mut self) {
491 let _span = UpdatesTrace::extension_span::<E>("deinit");
492 self.0.deinit();
493 }
494
495 fn boxed(self) -> Box<dyn AppExtensionBoxed>
496 where
497 Self: Sized,
498 {
499 Box::new(self)
500 }
501}
502
503#[derive(Clone, Copy)]
507#[non_exhaustive]
508pub struct AppExtensionInfo {
509 pub type_id: TypeId,
511 pub type_name: &'static str,
513}
514impl PartialEq for AppExtensionInfo {
515 fn eq(&self, other: &Self) -> bool {
516 self.type_id == other.type_id
517 }
518}
519impl fmt::Debug for AppExtensionInfo {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521 write!(f, "{}", self.type_name)
522 }
523}
524impl Eq for AppExtensionInfo {}
525impl AppExtensionInfo {
526 pub fn new<E: AppExtension>() -> Self {
528 Self {
529 type_id: TypeId::of::<E>(),
530 type_name: type_name::<E>(),
531 }
532 }
533}
534
535#[derive(Clone, PartialEq)]
537pub struct AppExtensionsInfo {
538 infos: Vec<AppExtensionInfo>,
539}
540impl fmt::Debug for AppExtensionsInfo {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 f.debug_list().entries(&self.infos).finish()
543 }
544}
545impl AppExtensionsInfo {
546 pub(crate) fn start() -> Self {
547 Self { infos: vec![] }
548 }
549
550 pub fn push<E: AppExtension>(&mut self) {
552 let info = AppExtensionInfo::new::<E>();
553 assert!(!self.contains::<E>(), "app-extension `{info:?}` is already in the list");
554 self.infos.push(info);
555 }
556
557 pub fn contains<E: AppExtension>(&self) -> bool {
559 self.contains_info(AppExtensionInfo::new::<E>())
560 }
561
562 pub fn contains_info(&self, info: AppExtensionInfo) -> bool {
564 self.infos.iter().any(|e| e.type_id == info.type_id)
565 }
566
567 #[track_caller]
569 pub fn require<E: AppExtension>(&self) {
570 let info = AppExtensionInfo::new::<E>();
571 if !self.contains_info(info) {
572 let mut note = "";
573 if !APP.is_running() {
574 if APP.is_started() {
575 note = "\nnote: the app is not running yet";
576 } else {
577 note = "\nnote: no app is started in the current thread";
578 }
579 }
580 panic!("app-extension `{info:?}` is required{note}")
581 }
582 }
583}
584impl ops::Deref for AppExtensionsInfo {
585 type Target = [AppExtensionInfo];
586
587 fn deref(&self) -> &Self::Target {
588 &self.infos
589 }
590}
591
592#[derive(Copy, Clone, Debug, PartialEq, Eq)]
594#[must_use = "methods that return `AppControlFlow` expect to be inside a controlled loop"]
595pub enum AppControlFlow {
596 Poll,
598 Wait,
602 Exit,
604}
605impl AppControlFlow {
606 #[track_caller]
608 pub fn assert_wait(self) {
609 assert_eq!(AppControlFlow::Wait, self)
610 }
611
612 #[track_caller]
614 pub fn assert_exit(self) {
615 assert_eq!(AppControlFlow::Exit, self)
616 }
617}
618
619pub struct HeadlessApp {
626 app: RunningApp<Box<dyn AppExtensionBoxed>>,
627}
628impl HeadlessApp {
629 pub fn renderer_enabled(&mut self) -> bool {
640 VIEW_PROCESS.is_available()
641 }
642
643 pub fn update(&mut self, wait_app_event: bool) -> AppControlFlow {
649 self.update_observed(&mut (), wait_app_event)
650 }
651
652 pub fn update_observe(&mut self, on_update: impl FnMut(), wait_app_event: bool) -> AppControlFlow {
659 struct Observer<F>(F);
660 impl<F: FnMut()> AppEventObserver for Observer<F> {
661 fn update(&mut self) {
662 (self.0)()
663 }
664 }
665 let mut observer = Observer(on_update);
666
667 self.update_observed(&mut observer, wait_app_event)
668 }
669
670 pub fn update_observe_event(&mut self, on_event: impl FnMut(&mut EventUpdate), wait_app_event: bool) -> AppControlFlow {
677 struct Observer<F>(F);
678 impl<F: FnMut(&mut EventUpdate)> AppEventObserver for Observer<F> {
679 fn event(&mut self, update: &mut EventUpdate) {
680 (self.0)(update);
681 }
682 }
683 let mut observer = Observer(on_event);
684 self.update_observed(&mut observer, wait_app_event)
685 }
686
687 pub fn update_observed<O: AppEventObserver>(&mut self, observer: &mut O, mut wait_app_event: bool) -> AppControlFlow {
692 if self.app.has_exited() {
693 return AppControlFlow::Exit;
694 }
695
696 loop {
697 match self.app.poll(wait_app_event, observer) {
698 AppControlFlow::Poll => {
699 wait_app_event = false;
700 continue;
701 }
702 flow => return flow,
703 }
704 }
705 }
706
707 pub fn run_task<R, T>(&mut self, task: impl IntoFuture<IntoFuture = T>) -> Option<R>
711 where
712 R: 'static,
713 T: Future<Output = R> + Send + Sync + 'static,
714 {
715 let mut task = UiTask::new(None, task);
716
717 let mut flow = self.update_observe(
718 || {
719 task.update();
720 },
721 false,
722 );
723
724 if task.update().is_some() {
725 let r = task.into_result().ok();
726 debug_assert!(r.is_some());
727 return r;
728 }
729
730 let mut n = 0;
731 while flow != AppControlFlow::Exit {
732 flow = self.update_observe(
733 || {
734 task.update();
735 },
736 true,
737 );
738
739 if n == 10_000 {
740 tracing::error!("excessive future awaking, run_task ran 10_000 update cycles without finishing");
741 } else if n == 100_000 {
742 panic!("run_task stuck, ran 100_000 update cycles without finishing");
743 }
744 n += 1;
745
746 match task.into_result() {
747 Ok(r) => return Some(r),
748 Err(t) => task = t,
749 }
750 }
751 task.cancel();
752
753 None
754 }
755
756 pub fn exit(mut self) {
760 self.run_task(async move {
761 let req = APP.exit();
762 req.wait_rsp().await;
763 });
764 }
765
766 pub fn has_exited(&self) -> bool {
770 self.app.has_exited()
771 }
772}
773
774pub trait AppEventObserver {
778 fn raw_event(&mut self, ev: &zng_view_api::Event) {
780 let _ = ev;
781 }
782
783 fn event_preview(&mut self, update: &mut EventUpdate) {
785 let _ = update;
786 }
787
788 fn event_ui(&mut self, update: &mut EventUpdate) {
790 let _ = update;
791 }
792
793 fn event(&mut self, update: &mut EventUpdate) {
795 let _ = update;
796 }
797
798 fn update_preview(&mut self) {}
800
801 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
803 let _ = update_widgets;
804 }
805
806 fn update(&mut self) {}
808
809 fn info(&mut self, info_widgets: &mut InfoUpdates) {
811 let _ = info_widgets;
812 }
813
814 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
816 let _ = layout_widgets;
817 }
818
819 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
821 let _ = (render_widgets, render_update_widgets);
822 }
823
824 fn as_dyn(&mut self) -> DynAppEventObserver<'_>
828 where
829 Self: Sized,
830 {
831 DynAppEventObserver(self)
832 }
833}
834impl AppEventObserver for () {}
836
837#[doc(hidden)]
838pub struct DynAppEventObserver<'a>(&'a mut dyn AppEventObserverDyn);
839
840trait AppEventObserverDyn {
841 fn raw_event_dyn(&mut self, ev: &zng_view_api::Event);
842 fn event_preview_dyn(&mut self, update: &mut EventUpdate);
843 fn event_ui_dyn(&mut self, update: &mut EventUpdate);
844 fn event_dyn(&mut self, update: &mut EventUpdate);
845 fn update_preview_dyn(&mut self);
846 fn update_ui_dyn(&mut self, updates: &mut WidgetUpdates);
847 fn update_dyn(&mut self);
848 fn info_dyn(&mut self, info_widgets: &mut InfoUpdates);
849 fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates);
850 fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
851}
852impl<O: AppEventObserver> AppEventObserverDyn for O {
853 fn raw_event_dyn(&mut self, ev: &zng_view_api::Event) {
854 self.raw_event(ev)
855 }
856
857 fn event_preview_dyn(&mut self, update: &mut EventUpdate) {
858 self.event_preview(update)
859 }
860
861 fn event_ui_dyn(&mut self, update: &mut EventUpdate) {
862 self.event_ui(update)
863 }
864
865 fn event_dyn(&mut self, update: &mut EventUpdate) {
866 self.event(update)
867 }
868
869 fn update_preview_dyn(&mut self) {
870 self.update_preview()
871 }
872
873 fn update_ui_dyn(&mut self, update_widgets: &mut WidgetUpdates) {
874 self.update_ui(update_widgets)
875 }
876
877 fn update_dyn(&mut self) {
878 self.update()
879 }
880
881 fn info_dyn(&mut self, info_widgets: &mut InfoUpdates) {
882 self.info(info_widgets)
883 }
884
885 fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates) {
886 self.layout(layout_widgets)
887 }
888
889 fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
890 self.render(render_widgets, render_update_widgets)
891 }
892}
893impl AppEventObserver for DynAppEventObserver<'_> {
894 fn raw_event(&mut self, ev: &zng_view_api::Event) {
895 self.0.raw_event_dyn(ev)
896 }
897
898 fn event_preview(&mut self, update: &mut EventUpdate) {
899 self.0.event_preview_dyn(update)
900 }
901
902 fn event_ui(&mut self, update: &mut EventUpdate) {
903 self.0.event_ui_dyn(update)
904 }
905
906 fn event(&mut self, update: &mut EventUpdate) {
907 self.0.event_dyn(update)
908 }
909
910 fn update_preview(&mut self) {
911 self.0.update_preview_dyn()
912 }
913
914 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
915 self.0.update_ui_dyn(update_widgets)
916 }
917
918 fn update(&mut self) {
919 self.0.update_dyn()
920 }
921
922 fn info(&mut self, info_widgets: &mut InfoUpdates) {
923 self.0.info_dyn(info_widgets)
924 }
925
926 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
927 self.0.layout_dyn(layout_widgets)
928 }
929
930 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
931 self.0.render_dyn(render_widgets, render_update_widgets)
932 }
933
934 fn as_dyn(&mut self) -> DynAppEventObserver<'_> {
935 DynAppEventObserver(self.0)
936 }
937}
938
939impl AppExtension for () {
940 fn register(&self, _: &mut AppExtensionsInfo) {}
941}
942impl<A: AppExtension, B: AppExtension> AppExtension for (A, B) {
943 fn init(&mut self) {
944 self.0.init();
945 self.1.init();
946 }
947
948 fn register(&self, info: &mut AppExtensionsInfo) {
949 self.0.register(info);
950 self.1.register(info);
951 }
952
953 fn update_preview(&mut self) {
954 self.0.update_preview();
955 self.1.update_preview();
956 }
957
958 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
959 self.0.update_ui(update_widgets);
960 self.1.update_ui(update_widgets);
961 }
962
963 fn update(&mut self) {
964 self.0.update();
965 self.1.update();
966 }
967
968 fn info(&mut self, info_widgets: &mut InfoUpdates) {
969 self.0.info(info_widgets);
970 self.1.info(info_widgets);
971 }
972
973 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
974 self.0.layout(layout_widgets);
975 self.1.layout(layout_widgets);
976 }
977
978 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
979 self.0.render(render_widgets, render_update_widgets);
980 self.1.render(render_widgets, render_update_widgets);
981 }
982
983 fn event_preview(&mut self, update: &mut EventUpdate) {
984 self.0.event_preview(update);
985 self.1.event_preview(update);
986 }
987
988 fn event_ui(&mut self, update: &mut EventUpdate) {
989 self.0.event_ui(update);
990 self.1.event_ui(update);
991 }
992
993 fn event(&mut self, update: &mut EventUpdate) {
994 self.0.event(update);
995 self.1.event(update);
996 }
997
998 fn deinit(&mut self) {
999 self.1.deinit();
1000 self.0.deinit();
1001 }
1002}
1003
1004#[cfg(feature = "dyn_app_extension")]
1005impl AppExtension for Vec<Box<dyn AppExtensionBoxed>> {
1006 fn init(&mut self) {
1007 for ext in self {
1008 ext.init();
1009 }
1010 }
1011
1012 fn register(&self, info: &mut AppExtensionsInfo) {
1013 for ext in self {
1014 ext.register(info);
1015 }
1016 }
1017
1018 fn update_preview(&mut self) {
1019 for ext in self {
1020 ext.update_preview();
1021 }
1022 }
1023
1024 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
1025 for ext in self {
1026 ext.update_ui(update_widgets);
1027 }
1028 }
1029
1030 fn update(&mut self) {
1031 for ext in self {
1032 ext.update();
1033 }
1034 }
1035
1036 fn event_preview(&mut self, update: &mut EventUpdate) {
1037 for ext in self {
1038 ext.event_preview(update);
1039 }
1040 }
1041
1042 fn event_ui(&mut self, update: &mut EventUpdate) {
1043 for ext in self {
1044 ext.event_ui(update);
1045 }
1046 }
1047
1048 fn event(&mut self, update: &mut EventUpdate) {
1049 for ext in self {
1050 ext.event(update);
1051 }
1052 }
1053
1054 fn info(&mut self, info_widgets: &mut InfoUpdates) {
1055 for ext in self {
1056 ext.info(info_widgets);
1057 }
1058 }
1059
1060 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
1061 for ext in self {
1062 ext.layout(layout_widgets);
1063 }
1064 }
1065
1066 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1067 for ext in self {
1068 ext.render(render_widgets, render_update_widgets);
1069 }
1070 }
1071
1072 fn deinit(&mut self) {
1073 for ext in self.iter_mut().rev() {
1074 ext.deinit();
1075 }
1076 }
1077}
1078
1079pub struct APP;
1081impl APP {
1082 pub fn multi_app_enabled(&self) -> bool {
1086 cfg!(feature = "multi_app")
1087 }
1088
1089 pub fn is_started(&self) -> bool {
1098 LocalContext::current_app().is_some()
1099 }
1100
1101 pub fn is_running(&self) -> bool {
1109 self.is_started() && APP_PROCESS_SV.read().is_running()
1110 }
1111
1112 pub fn id(&self) -> Option<AppId> {
1120 LocalContext::current_app()
1121 }
1122
1123 #[cfg(not(feature = "multi_app"))]
1124 fn assert_can_run_single() {
1125 use std::sync::atomic::*;
1126 static CAN_RUN: AtomicBool = AtomicBool::new(true);
1127
1128 if !CAN_RUN.swap(false, Ordering::SeqCst) {
1129 panic!("only one app is allowed per process")
1130 }
1131 }
1132
1133 fn assert_can_run() {
1134 #[cfg(not(feature = "multi_app"))]
1135 Self::assert_can_run_single();
1136 if APP.is_running() {
1137 panic!("only one app is allowed per thread")
1138 }
1139 }
1140
1141 pub fn window_mode(&self) -> WindowMode {
1145 if VIEW_PROCESS.is_available() {
1146 if VIEW_PROCESS.is_headless_with_render() {
1147 WindowMode::HeadlessWithRenderer
1148 } else {
1149 WindowMode::Headed
1150 }
1151 } else {
1152 WindowMode::Headless
1153 }
1154 }
1155 pub fn extensions(&self) -> Arc<AppExtensionsInfo> {
1157 APP_PROCESS_SV.read().extensions()
1158 }
1159
1160 pub fn device_events_filter(&self) -> Var<DeviceEventsFilter> {
1167 APP_PROCESS_SV.read().device_events_filter.clone()
1168 }
1169}
1170
1171impl APP {
1172 #[cfg(feature = "dyn_app_extension")]
1174 pub fn minimal(&self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1175 zng_env::init_process_name("app-process");
1176
1177 #[cfg(debug_assertions)]
1178 print_tracing(tracing::Level::INFO);
1179 assert_not_view_process();
1180 Self::assert_can_run();
1181 spawn_deadlock_detection();
1182
1183 let _ = INSTANT.now();
1184 let scope = LocalContext::start_app(AppId::new_unique());
1185 AppExtended {
1186 extensions: vec![],
1187 view_process_exe: None,
1188 view_process_env: HashMap::new(),
1189 _cleanup: scope,
1190 }
1191 }
1192
1193 #[cfg(not(feature = "dyn_app_extension"))]
1195 pub fn minimal(&self) -> AppExtended<()> {
1196 #[cfg(debug_assertions)]
1197 print_tracing(tracing::Level::INFO);
1198 assert_not_view_process();
1199 Self::assert_can_run();
1200 spawn_deadlock_detection();
1201 let scope = LocalContext::start_app(AppId::new_unique());
1202 AppExtended {
1203 extensions: (),
1204 view_process_exe: None,
1205 view_process_env: HashMap::new(),
1206 _cleanup: scope,
1207 }
1208 }
1209}
1210
1211pub struct AppExtended<E: AppExtension> {
1215 extensions: E,
1216 view_process_exe: Option<PathBuf>,
1217 view_process_env: HashMap<Txt, Txt>,
1218
1219 _cleanup: AppScope,
1221}
1222#[cfg(feature = "dyn_app_extension")]
1223impl AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1224 pub fn extend<F: AppExtension>(mut self, extension: F) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1226 self.extensions.push(TraceAppExt(extension).boxed());
1227 self
1228 }
1229
1230 fn run_dyn(self, start: std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
1231 let app = RunningApp::start(
1232 self._cleanup,
1233 self.extensions,
1234 true,
1235 true,
1236 self.view_process_exe,
1237 self.view_process_env,
1238 );
1239
1240 UPDATES.run(start).perm();
1241
1242 app.run_headed();
1243 }
1244
1245 fn run_headless_dyn(self, with_renderer: bool) -> HeadlessApp {
1246 let app = RunningApp::start(
1247 self._cleanup,
1248 self.extensions.boxed(),
1249 false,
1250 with_renderer,
1251 self.view_process_exe,
1252 self.view_process_env,
1253 );
1254
1255 HeadlessApp { app }
1256 }
1257}
1258
1259#[cfg(feature = "dyn_app_extension")]
1261impl<E: AppExtension> AppExtended<E> {
1262 fn cast_app(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1263 let app: Box<dyn std::any::Any> = Box::new(self);
1264 match app.downcast::<AppExtended<Vec<Box<dyn AppExtensionBoxed>>>>() {
1265 Ok(ok) => *ok,
1266 Err(e) => {
1267 let app = *e.downcast::<Self>().unwrap();
1268 AppExtended {
1269 extensions: vec![app.extensions.boxed()],
1270 view_process_exe: app.view_process_exe,
1271 view_process_env: app.view_process_env,
1272 _cleanup: app._cleanup,
1273 }
1274 }
1275 }
1276 }
1277
1278 fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1279 self.cast_app().run_dyn(Box::pin(start))
1280 }
1281
1282 fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1283 self.cast_app().run_headless_dyn(with_renderer)
1284 }
1285}
1286
1287#[cfg(not(feature = "dyn_app_extension"))]
1288impl<E: AppExtension> AppExtended<E> {
1289 pub fn extend<F: AppExtension>(self, extension: F) -> AppExtended<impl AppExtension> {
1291 AppExtended {
1292 _cleanup: self._cleanup,
1293 extensions: (self.extensions, TraceAppExt(extension)),
1294 view_process_exe: self.view_process_exe,
1295 view_process_env: self.view_process_env,
1296 }
1297 }
1298
1299 fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1300 let app = RunningApp::start(
1301 self._cleanup,
1302 self.extensions,
1303 true,
1304 true,
1305 self.view_process_exe,
1306 self.view_process_env,
1307 );
1308
1309 UPDATES.run(start).perm();
1310
1311 app.run_headed();
1312 }
1313
1314 fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1315 let app = RunningApp::start(
1316 self._cleanup,
1317 self.extensions.boxed(),
1318 false,
1319 with_renderer,
1320 self.view_process_exe,
1321 self.view_process_env,
1322 );
1323
1324 HeadlessApp { app }
1325 }
1326}
1327impl<E: AppExtension> AppExtended<E> {
1328 pub fn view_process_exe(mut self, view_process_exe: impl Into<PathBuf>) -> Self {
1338 self.view_process_exe = Some(view_process_exe.into());
1339 self
1340 }
1341
1342 pub fn view_process_env(mut self, name: impl Into<Txt>, value: impl Into<Txt>) -> Self {
1344 self.view_process_env.insert(name.into(), value.into());
1345 self
1346 }
1347
1348 pub fn run<F: Future<Output = ()> + Send + 'static>(self, start: impl IntoFuture<IntoFuture = F>) {
1355 let start = start.into_future();
1356 self.run_impl(start)
1357 }
1358
1359 pub fn run_headless(self, with_renderer: bool) -> HeadlessApp {
1364 self.run_headless_impl(with_renderer)
1365 }
1366}
1367
1368mod running;
1370pub use running::*;
1371use zng_view_api::DeviceEventsFilter;
1372
1373mod private {
1374 pub trait Sealed {}
1376}
1377
1378pub fn print_tracing(max: tracing::Level) -> bool {
1394 use tracing_subscriber::prelude::*;
1395
1396 let layers = tracing_subscriber::registry().with(FilterLayer(max));
1397
1398 #[cfg(target_os = "android")]
1399 let layers = layers.with(tracing_android::layer(&zng_env::about().pkg_name).unwrap());
1400
1401 #[cfg(not(target_os = "android"))]
1402 let layers = {
1403 let fmt_layer = tracing_subscriber::fmt::layer().without_time();
1404
1405 #[cfg(target_arch = "wasm32")]
1406 let fmt_layer = fmt_layer.with_ansi(false).with_writer(tracing_web::MakeWebConsoleWriter::new());
1407
1408 layers.with(fmt_layer)
1409 };
1410
1411 layers.try_init().is_ok()
1412}
1413
1414struct FilterLayer(tracing::Level);
1415impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for FilterLayer {
1416 fn enabled(&self, metadata: &tracing::Metadata<'_>, _: tracing_subscriber::layer::Context<'_, S>) -> bool {
1417 print_tracing_filter(&self.0, metadata)
1418 }
1419
1420 fn max_level_hint(&self) -> Option<tracing::metadata::LevelFilter> {
1421 Some(self.0.into())
1422 }
1423
1424 #[cfg(any(test, feature = "test_util"))]
1425 fn on_event(&self, event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
1426 if event.metadata().level() == &tracing::Level::ERROR && APP.is_running() && TEST_LOG.get() {
1427 struct MsgCollector<'a>(&'a mut String);
1428 impl tracing::field::Visit for MsgCollector<'_> {
1429 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn fmt::Debug) {
1430 use std::fmt::Write;
1431 write!(self.0, "\n {} = {:?}", field.name(), value).unwrap();
1432 }
1433 }
1434
1435 let meta = event.metadata();
1436 let file = meta.file().unwrap_or("");
1437 let line = meta.line().unwrap_or(0);
1438
1439 let mut msg = format!("[{file}:{line}]");
1440 event.record(&mut MsgCollector(&mut msg));
1441
1442 panic!("[LOG-ERROR]{msg}")
1443 }
1444 }
1445}
1446pub fn print_tracing_filter(level: &tracing::Level, metadata: &tracing::Metadata) -> bool {
1450 if metadata.level() > level {
1451 return false;
1452 }
1453
1454 if metadata.level() == &tracing::Level::INFO {
1455 if metadata.target() == "zng_webrender::device::gl" {
1457 return false;
1458 }
1459 if metadata.target() == "zng_webrender::renderer::init" {
1461 return false;
1462 }
1463 } else if metadata.level() == &tracing::Level::WARN {
1464 if metadata.target() == "zng_webrender::device::gl" {
1467 if metadata.line() == Some(4647) {
1470 return false;
1471 }
1472 }
1473
1474 if metadata.target() == "font_kit::loaders::freetype" {
1477 if metadata.line() == Some(734) {
1481 return false;
1482 }
1483 }
1484 }
1485
1486 true
1487}
1488
1489#[cfg(any(test, feature = "test_util"))]
1491pub fn test_log() {
1492 TEST_LOG.set(true);
1493}
1494
1495#[cfg(any(test, feature = "test_util"))]
1496zng_app_context::app_local! {
1497 static TEST_LOG: bool = false;
1498}
1499
1500#[doc(hidden)]
1501pub fn name_from_pkg_name(name: &'static str) -> Txt {
1502 let mut n = String::new();
1503 let mut sep = "";
1504 for part in name.split(&['-', '_']) {
1505 n.push_str(sep);
1506 let mut chars = part.char_indices();
1507 let (_, c) = chars.next().unwrap();
1508 c.to_uppercase().for_each(|c| n.push(c));
1509 if let Some((i, _)) = chars.next() {
1510 n.push_str(&part[i..]);
1511 }
1512 sep = " ";
1513 }
1514 n.into()
1515}
1516
1517#[doc(hidden)]
1518pub fn txt_from_pkg_meta(value: &'static str) -> Txt {
1519 value.into()
1520}