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#![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 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#[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; #[doc(hidden)]
89pub mod __proc_macro_util {
90 #[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
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)]
216 fn enable_device_events(&self) -> bool {
217 false
218 }
219
220 #[inline(always)]
227 fn event_preview(&mut self, update: &mut EventUpdate) {
228 let _ = update;
229 }
230
231 #[inline(always)]
236 fn event_ui(&mut self, update: &mut EventUpdate) {
237 let _ = update;
238 }
239
240 #[inline(always)]
244 fn event(&mut self, update: &mut EventUpdate) {
245 let _ = update;
246 }
247
248 #[inline(always)]
254 fn info(&mut self, info_widgets: &mut InfoUpdates) {
255 let _ = info_widgets;
256 }
257
258 #[inline(always)]
265 fn update_preview(&mut self) {}
266
267 #[inline(always)]
275 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
276 let _ = update_widgets;
277 }
278
279 #[inline(always)]
284 fn update(&mut self) {}
285
286 #[inline(always)]
292 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
293 let _ = layout_widgets;
294 }
295
296 #[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 #[inline(always)]
312 fn deinit(&mut self) {}
313
314 #[inline(always)]
318 fn boxed(self) -> Box<dyn AppExtensionBoxed>
319 where
320 Self: Sized,
321 {
322 Box::new(self)
323 }
324}
325
326#[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#[derive(Clone, Copy)]
534#[non_exhaustive]
535pub struct AppExtensionInfo {
536 pub type_id: TypeId,
538 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 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#[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 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 pub fn contains<E: AppExtension>(&self) -> bool {
586 self.contains_info(AppExtensionInfo::new::<E>())
587 }
588
589 pub fn contains_info(&self, info: AppExtensionInfo) -> bool {
591 self.infos.iter().any(|e| e.type_id == info.type_id)
592 }
593
594 #[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#[derive(Copy, Clone, Debug, PartialEq, Eq)]
611#[must_use = "methods that return `AppControlFlow` expect to be inside a controlled loop"]
612pub enum AppControlFlow {
613 Poll,
615 Wait,
619 Exit,
621}
622impl AppControlFlow {
623 #[track_caller]
625 pub fn assert_wait(self) {
626 assert_eq!(AppControlFlow::Wait, self)
627 }
628
629 #[track_caller]
631 pub fn assert_exit(self) {
632 assert_eq!(AppControlFlow::Exit, self)
633 }
634}
635
636pub struct HeadlessApp {
643 app: RunningApp<Box<dyn AppExtensionBoxed>>,
644}
645impl HeadlessApp {
646 pub fn renderer_enabled(&mut self) -> bool {
657 VIEW_PROCESS.is_available()
658 }
659
660 pub fn update(&mut self, wait_app_event: bool) -> AppControlFlow {
666 self.update_observed(&mut (), wait_app_event)
667 }
668
669 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 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 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 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 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 pub fn has_exited(&self) -> bool {
787 self.app.has_exited()
788 }
789}
790
791pub trait AppEventObserver {
795 fn raw_event(&mut self, ev: &zng_view_api::Event) {
797 let _ = ev;
798 }
799
800 fn event_preview(&mut self, update: &mut EventUpdate) {
802 let _ = update;
803 }
804
805 fn event_ui(&mut self, update: &mut EventUpdate) {
807 let _ = update;
808 }
809
810 fn event(&mut self, update: &mut EventUpdate) {
812 let _ = update;
813 }
814
815 fn update_preview(&mut self) {}
817
818 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
820 let _ = update_widgets;
821 }
822
823 fn update(&mut self) {}
825
826 fn info(&mut self, info_widgets: &mut InfoUpdates) {
828 let _ = info_widgets;
829 }
830
831 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
833 let _ = layout_widgets;
834 }
835
836 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
838 let _ = (render_widgets, render_update_widgets);
839 }
840
841 fn as_dyn(&mut self) -> DynAppEventObserver<'_>
845 where
846 Self: Sized,
847 {
848 DynAppEventObserver(self)
849 }
850}
851impl 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
1104pub struct APP;
1106impl APP {
1107 pub fn multi_app_enabled(&self) -> bool {
1111 cfg!(feature = "multi_app")
1112 }
1113
1114 pub fn is_running(&self) -> bool {
1123 LocalContext::current_app().is_some()
1124 }
1125
1126 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 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 pub fn extensions(&self) -> Arc<AppExtensionsInfo> {
1171 APP_PROCESS_SV.read().extensions()
1172 }
1173
1174 pub fn device_events(&self) -> bool {
1178 APP_PROCESS_SV.read().device_events
1179 }
1180}
1181
1182impl APP {
1183 #[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 #[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
1219pub struct AppExtended<E: AppExtension> {
1223 extensions: E,
1224 view_process_exe: Option<PathBuf>,
1225 view_process_env: HashMap<Txt, Txt>,
1226
1227 _cleanup: AppScope,
1229}
1230#[cfg(feature = "dyn_app_extension")]
1231impl AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1232 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 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#[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 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 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 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 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 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 pub fn run_headless(self, with_renderer: bool) -> HeadlessApp {
1404 self.run_headless_impl(with_renderer)
1405 }
1406}
1407
1408mod running;
1410pub use running::*;
1411
1412mod private {
1413 pub trait Sealed {}
1415}
1416
1417pub 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}
1485pub 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 if metadata.target() == "zng_webrender::device::gl" {
1496 return false;
1497 }
1498 if metadata.target() == "zng_webrender::renderer::init" {
1500 return false;
1501 }
1502 } else if metadata.level() == &tracing::Level::WARN {
1503 if metadata.target() == "zng_webrender::device::gl" {
1506 if metadata.line() == Some(4647) {
1509 return false;
1510 }
1511 }
1512
1513 if metadata.target() == "font_kit::loaders::freetype" {
1516 if metadata.line() == Some(734) {
1520 return false;
1521 }
1522 }
1523 }
1524
1525 true
1526}
1527
1528#[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}