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