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;
50
51pub use zng_time::{DInstant, Deadline, INSTANT, InstantMode};
52
53use update::{EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdatesTrace, WidgetUpdates};
54use window::WindowMode;
55use zng_app_context::{AppId, AppScope, LocalContext};
56use zng_task::UiTask;
57
58pub use zng_unique_id::static_id;
59
60#[macro_export]
70macro_rules! enable_widget_macros {
71 () => {
72 #[doc(hidden)]
73 #[allow(unused_extern_crates)]
74 extern crate self as zng;
75
76 #[doc(hidden)]
77 pub use $crate::__proc_macro_util;
78 };
79}
80
81#[doc(hidden)]
82#[allow(unused_extern_crates)]
83extern crate self as zng;
84
85#[doc(hidden)]
86#[allow(unused_extern_crates)]
87extern crate self as zng_app; #[doc(hidden)]
90pub mod __proc_macro_util {
91 #[doc(hidden)]
95 pub use zng_unique_id::static_id;
96
97 #[doc(hidden)]
98 pub mod widget {
99 #[doc(hidden)]
100 pub mod builder {
101 #[doc(hidden)]
102 pub use crate::widget::builder::{
103 AnyArcWidgetHandler, ArcWidgetHandler, Importance, InputKind, PropertyArgs, PropertyId, PropertyInfo, PropertyInput,
104 PropertyInputTypes, PropertyNewArgs, SourceLocation, UiNodeInWhenExprError, UiNodeListInWhenExprError, WgtInfo, WhenInput,
105 WhenInputMember, WhenInputVar, WidgetHandlerInWhenExprError, WidgetType, getter_var, iter_input_build_actions,
106 nest_group_items, new_dyn_other, new_dyn_ui_node, new_dyn_ui_node_list, new_dyn_var, new_dyn_widget_handler, panic_input,
107 state_var, ui_node_list_to_args, ui_node_to_args, value_to_args, var_to_args, when_condition_expr_var,
108 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::{
120 ArcNode, ArcNodeList, BoxedUiNode, BoxedUiNodeList, NilUiNode, UiNode, UiNodeList, UiVec, ui_node_list_default,
121 };
122 }
123
124 #[doc(hidden)]
125 pub mod info {
126 pub use crate::widget::info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure};
127 }
128
129 #[doc(hidden)]
130 pub use crate::widget::{easing_property, widget_new};
131
132 #[doc(hidden)]
133 pub use crate::widget::WIDGET;
134 }
135
136 #[doc(hidden)]
137 pub mod update {
138 pub use crate::update::{EventUpdate, WidgetUpdates};
139 }
140
141 #[doc(hidden)]
142 pub mod layout {
143 #[doc(hidden)]
144 pub mod unit {
145 #[doc(hidden)]
146 pub use crate::layout::unit::{PxSize, TimeUnits};
147 }
148
149 #[doc(hidden)]
150 pub mod context {
151 #[doc(hidden)]
152 pub use crate::layout::context::LAYOUT;
153 }
154 }
155
156 #[doc(hidden)]
157 pub mod render {
158 pub use crate::render::{FrameBuilder, FrameUpdate};
159 }
160
161 #[doc(hidden)]
162 pub mod handler {
163 #[doc(hidden)]
164 pub use crate::handler::hn;
165 }
166
167 #[doc(hidden)]
168 pub mod var {
169 #[doc(hidden)]
170 pub use crate::var::{AnyVar, AnyVarValue, BoxedVar, Var, expr_var};
171
172 #[doc(hidden)]
173 pub mod animation {
174 #[doc(hidden)]
175 pub mod easing {
176 #[doc(hidden)]
177 pub use crate::var::animation::easing::{
178 back, bounce, circ, cubic, cubic_bezier, ease_in, ease_in_out, ease_out, ease_out_in, elastic, expo, linear, none,
179 quad, quart, quint, reverse, reverse_out, sine, step_ceil, step_floor,
180 };
181 }
182 }
183 }
184}
185
186pub trait AppExtension: 'static {
194 #[inline(always)]
196 fn register(&self, info: &mut AppExtensionsInfo)
197 where
198 Self: Sized,
199 {
200 info.push::<Self>()
201 }
202
203 #[inline(always)]
205 fn init(&mut self) {}
206
207 #[inline(always)]
217 fn enable_device_events(&self) -> bool {
218 false
219 }
220
221 #[inline(always)]
228 fn event_preview(&mut self, update: &mut EventUpdate) {
229 let _ = update;
230 }
231
232 #[inline(always)]
237 fn event_ui(&mut self, update: &mut EventUpdate) {
238 let _ = update;
239 }
240
241 #[inline(always)]
245 fn event(&mut self, update: &mut EventUpdate) {
246 let _ = update;
247 }
248
249 #[inline(always)]
255 fn info(&mut self, info_widgets: &mut InfoUpdates) {
256 let _ = info_widgets;
257 }
258
259 #[inline(always)]
266 fn update_preview(&mut self) {}
267
268 #[inline(always)]
276 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
277 let _ = update_widgets;
278 }
279
280 #[inline(always)]
285 fn update(&mut self) {}
286
287 #[inline(always)]
293 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
294 let _ = layout_widgets;
295 }
296
297 #[inline(always)]
304 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
305 let _ = (render_widgets, render_update_widgets);
306 }
307
308 #[inline(always)]
313 fn deinit(&mut self) {}
314
315 #[inline(always)]
319 fn boxed(self) -> Box<dyn AppExtensionBoxed>
320 where
321 Self: Sized,
322 {
323 Box::new(self)
324 }
325}
326
327#[doc(hidden)]
329pub trait AppExtensionBoxed: 'static {
330 fn register_boxed(&self, info: &mut AppExtensionsInfo);
331 fn init_boxed(&mut self);
332 fn enable_device_events_boxed(&self) -> bool;
333 fn update_preview_boxed(&mut self);
334 fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates);
335 fn update_boxed(&mut self);
336 fn event_preview_boxed(&mut self, update: &mut EventUpdate);
337 fn event_ui_boxed(&mut self, update: &mut EventUpdate);
338 fn event_boxed(&mut self, update: &mut EventUpdate);
339 fn info_boxed(&mut self, info_widgets: &mut InfoUpdates);
340 fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates);
341 fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
342 fn deinit_boxed(&mut self);
343}
344impl<T: AppExtension> AppExtensionBoxed for T {
345 fn register_boxed(&self, info: &mut AppExtensionsInfo) {
346 self.register(info);
347 }
348
349 fn init_boxed(&mut self) {
350 self.init();
351 }
352
353 fn enable_device_events_boxed(&self) -> bool {
354 self.enable_device_events()
355 }
356
357 fn update_preview_boxed(&mut self) {
358 self.update_preview();
359 }
360
361 fn update_ui_boxed(&mut self, updates: &mut WidgetUpdates) {
362 self.update_ui(updates);
363 }
364
365 fn info_boxed(&mut self, info_widgets: &mut InfoUpdates) {
366 self.info(info_widgets);
367 }
368
369 fn update_boxed(&mut self) {
370 self.update();
371 }
372
373 fn event_preview_boxed(&mut self, update: &mut EventUpdate) {
374 self.event_preview(update);
375 }
376
377 fn event_ui_boxed(&mut self, update: &mut EventUpdate) {
378 self.event_ui(update);
379 }
380
381 fn event_boxed(&mut self, update: &mut EventUpdate) {
382 self.event(update);
383 }
384
385 fn layout_boxed(&mut self, layout_widgets: &mut LayoutUpdates) {
386 self.layout(layout_widgets);
387 }
388
389 fn render_boxed(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
390 self.render(render_widgets, render_update_widgets);
391 }
392
393 fn deinit_boxed(&mut self) {
394 self.deinit();
395 }
396}
397impl AppExtension for Box<dyn AppExtensionBoxed> {
398 fn register(&self, info: &mut AppExtensionsInfo) {
399 self.as_ref().register_boxed(info);
400 }
401
402 fn init(&mut self) {
403 self.as_mut().init_boxed();
404 }
405
406 fn enable_device_events(&self) -> bool {
407 self.as_ref().enable_device_events_boxed()
408 }
409
410 fn update_preview(&mut self) {
411 self.as_mut().update_preview_boxed();
412 }
413
414 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
415 self.as_mut().update_ui_boxed(update_widgets);
416 }
417
418 fn update(&mut self) {
419 self.as_mut().update_boxed();
420 }
421
422 fn event_preview(&mut self, update: &mut EventUpdate) {
423 self.as_mut().event_preview_boxed(update);
424 }
425
426 fn event_ui(&mut self, update: &mut EventUpdate) {
427 self.as_mut().event_ui_boxed(update);
428 }
429
430 fn event(&mut self, update: &mut EventUpdate) {
431 self.as_mut().event_boxed(update);
432 }
433
434 fn info(&mut self, info_widgets: &mut InfoUpdates) {
435 self.as_mut().info_boxed(info_widgets);
436 }
437
438 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
439 self.as_mut().layout_boxed(layout_widgets);
440 }
441
442 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
443 self.as_mut().render_boxed(render_widgets, render_update_widgets);
444 }
445
446 fn deinit(&mut self) {
447 self.as_mut().deinit_boxed();
448 }
449
450 fn boxed(self) -> Box<dyn AppExtensionBoxed>
451 where
452 Self: Sized,
453 {
454 self
455 }
456}
457
458struct TraceAppExt<E: AppExtension>(E);
459impl<E: AppExtension> AppExtension for TraceAppExt<E> {
460 fn register(&self, info: &mut AppExtensionsInfo) {
461 self.0.register(info)
462 }
463
464 fn init(&mut self) {
465 let _span = UpdatesTrace::extension_span::<E>("init");
466 self.0.init();
467 }
468
469 fn enable_device_events(&self) -> bool {
470 self.0.enable_device_events()
471 }
472
473 fn event_preview(&mut self, update: &mut EventUpdate) {
474 let _span = UpdatesTrace::extension_span::<E>("event_preview");
475 self.0.event_preview(update);
476 }
477
478 fn event_ui(&mut self, update: &mut EventUpdate) {
479 let _span = UpdatesTrace::extension_span::<E>("event_ui");
480 self.0.event_ui(update);
481 }
482
483 fn event(&mut self, update: &mut EventUpdate) {
484 let _span = UpdatesTrace::extension_span::<E>("event");
485 self.0.event(update);
486 }
487
488 fn update_preview(&mut self) {
489 let _span = UpdatesTrace::extension_span::<E>("update_preview");
490 self.0.update_preview();
491 }
492
493 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
494 let _span = UpdatesTrace::extension_span::<E>("update_ui");
495 self.0.update_ui(update_widgets);
496 }
497
498 fn update(&mut self) {
499 let _span = UpdatesTrace::extension_span::<E>("update");
500 self.0.update();
501 }
502
503 fn info(&mut self, info_widgets: &mut InfoUpdates) {
504 let _span = UpdatesTrace::extension_span::<E>("info");
505 self.0.info(info_widgets);
506 }
507
508 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
509 let _span = UpdatesTrace::extension_span::<E>("layout");
510 self.0.layout(layout_widgets);
511 }
512
513 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
514 let _span = UpdatesTrace::extension_span::<E>("render");
515 self.0.render(render_widgets, render_update_widgets);
516 }
517
518 fn deinit(&mut self) {
519 let _span = UpdatesTrace::extension_span::<E>("deinit");
520 self.0.deinit();
521 }
522
523 fn boxed(self) -> Box<dyn AppExtensionBoxed>
524 where
525 Self: Sized,
526 {
527 Box::new(self)
528 }
529}
530
531#[derive(Clone, Copy)]
535#[non_exhaustive]
536pub struct AppExtensionInfo {
537 pub type_id: TypeId,
539 pub type_name: &'static str,
541}
542impl PartialEq for AppExtensionInfo {
543 fn eq(&self, other: &Self) -> bool {
544 self.type_id == other.type_id
545 }
546}
547impl fmt::Debug for AppExtensionInfo {
548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549 write!(f, "{}", self.type_name)
550 }
551}
552impl Eq for AppExtensionInfo {}
553impl AppExtensionInfo {
554 pub fn new<E: AppExtension>() -> Self {
556 Self {
557 type_id: TypeId::of::<E>(),
558 type_name: type_name::<E>(),
559 }
560 }
561}
562
563#[derive(Clone, PartialEq)]
565pub struct AppExtensionsInfo {
566 infos: Vec<AppExtensionInfo>,
567}
568impl fmt::Debug for AppExtensionsInfo {
569 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570 f.debug_list().entries(&self.infos).finish()
571 }
572}
573impl AppExtensionsInfo {
574 pub(crate) fn start() -> Self {
575 Self { infos: vec![] }
576 }
577
578 pub fn push<E: AppExtension>(&mut self) {
580 let info = AppExtensionInfo::new::<E>();
581 assert!(!self.contains::<E>(), "app-extension `{info:?}` is already in the list");
582 self.infos.push(info);
583 }
584
585 pub fn contains<E: AppExtension>(&self) -> bool {
587 self.contains_info(AppExtensionInfo::new::<E>())
588 }
589
590 pub fn contains_info(&self, info: AppExtensionInfo) -> bool {
592 self.infos.iter().any(|e| e.type_id == info.type_id)
593 }
594
595 #[track_caller]
597 pub fn require<E: AppExtension>(&self) {
598 let info = AppExtensionInfo::new::<E>();
599 assert!(self.contains_info(info), "app-extension `{info:?}` is required");
600 }
601}
602impl ops::Deref for AppExtensionsInfo {
603 type Target = [AppExtensionInfo];
604
605 fn deref(&self) -> &Self::Target {
606 &self.infos
607 }
608}
609
610#[derive(Copy, Clone, Debug, PartialEq, Eq)]
612#[must_use = "methods that return `AppControlFlow` expect to be inside a controlled loop"]
613pub enum AppControlFlow {
614 Poll,
616 Wait,
620 Exit,
622}
623impl AppControlFlow {
624 #[track_caller]
626 pub fn assert_wait(self) {
627 assert_eq!(AppControlFlow::Wait, self)
628 }
629
630 #[track_caller]
632 pub fn assert_exit(self) {
633 assert_eq!(AppControlFlow::Exit, self)
634 }
635}
636
637pub struct HeadlessApp {
644 app: RunningApp<Box<dyn AppExtensionBoxed>>,
645}
646impl HeadlessApp {
647 pub fn renderer_enabled(&mut self) -> bool {
658 VIEW_PROCESS.is_available()
659 }
660
661 pub fn update(&mut self, wait_app_event: bool) -> AppControlFlow {
667 self.update_observed(&mut (), wait_app_event)
668 }
669
670 pub fn update_observe(&mut self, on_update: impl FnMut(), wait_app_event: bool) -> AppControlFlow {
677 struct Observer<F>(F);
678 impl<F: FnMut()> AppEventObserver for Observer<F> {
679 fn update(&mut self) {
680 (self.0)()
681 }
682 }
683 let mut observer = Observer(on_update);
684
685 self.update_observed(&mut observer, wait_app_event)
686 }
687
688 pub fn update_observe_event(&mut self, on_event: impl FnMut(&mut EventUpdate), wait_app_event: bool) -> AppControlFlow {
695 struct Observer<F>(F);
696 impl<F: FnMut(&mut EventUpdate)> AppEventObserver for Observer<F> {
697 fn event(&mut self, update: &mut EventUpdate) {
698 (self.0)(update);
699 }
700 }
701 let mut observer = Observer(on_event);
702 self.update_observed(&mut observer, wait_app_event)
703 }
704
705 pub fn update_observed<O: AppEventObserver>(&mut self, observer: &mut O, mut wait_app_event: bool) -> AppControlFlow {
710 if self.app.has_exited() {
711 return AppControlFlow::Exit;
712 }
713
714 loop {
715 match self.app.poll(wait_app_event, observer) {
716 AppControlFlow::Poll => {
717 wait_app_event = false;
718 continue;
719 }
720 flow => return flow,
721 }
722 }
723 }
724
725 pub fn run_task<R, T>(&mut self, task: impl IntoFuture<IntoFuture = T>) -> Option<R>
729 where
730 R: 'static,
731 T: Future<Output = R> + Send + Sync + 'static,
732 {
733 let mut task = UiTask::new(None, task);
734
735 let mut flow = self.update_observe(
736 || {
737 task.update();
738 },
739 false,
740 );
741
742 if task.update().is_some() {
743 let r = task.into_result().ok();
744 debug_assert!(r.is_some());
745 return r;
746 }
747
748 let mut n = 0;
749 while flow != AppControlFlow::Exit {
750 flow = self.update_observe(
751 || {
752 task.update();
753 },
754 true,
755 );
756
757 if n == 10_000 {
758 tracing::error!("excessive future awaking, run_task ran 10_000 update cycles without finishing");
759 } else if n == 100_000 {
760 panic!("run_task stuck, ran 100_000 update cycles without finishing");
761 }
762 n += 1;
763
764 match task.into_result() {
765 Ok(r) => return Some(r),
766 Err(t) => task = t,
767 }
768 }
769 task.cancel();
770
771 None
772 }
773
774 pub fn exit(mut self) {
778 self.run_task(async move {
779 let req = APP.exit();
780 req.wait_rsp().await;
781 });
782 }
783
784 pub fn has_exited(&self) -> bool {
788 self.app.has_exited()
789 }
790}
791
792pub trait AppEventObserver {
796 fn raw_event(&mut self, ev: &zng_view_api::Event) {
798 let _ = ev;
799 }
800
801 fn event_preview(&mut self, update: &mut EventUpdate) {
803 let _ = update;
804 }
805
806 fn event_ui(&mut self, update: &mut EventUpdate) {
808 let _ = update;
809 }
810
811 fn event(&mut self, update: &mut EventUpdate) {
813 let _ = update;
814 }
815
816 fn update_preview(&mut self) {}
818
819 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
821 let _ = update_widgets;
822 }
823
824 fn update(&mut self) {}
826
827 fn info(&mut self, info_widgets: &mut InfoUpdates) {
829 let _ = info_widgets;
830 }
831
832 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
834 let _ = layout_widgets;
835 }
836
837 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
839 let _ = (render_widgets, render_update_widgets);
840 }
841
842 fn as_dyn(&mut self) -> DynAppEventObserver<'_>
846 where
847 Self: Sized,
848 {
849 DynAppEventObserver(self)
850 }
851}
852impl AppEventObserver for () {}
854
855#[doc(hidden)]
856pub struct DynAppEventObserver<'a>(&'a mut dyn AppEventObserverDyn);
857
858trait AppEventObserverDyn {
859 fn raw_event_dyn(&mut self, ev: &zng_view_api::Event);
860 fn event_preview_dyn(&mut self, update: &mut EventUpdate);
861 fn event_ui_dyn(&mut self, update: &mut EventUpdate);
862 fn event_dyn(&mut self, update: &mut EventUpdate);
863 fn update_preview_dyn(&mut self);
864 fn update_ui_dyn(&mut self, updates: &mut WidgetUpdates);
865 fn update_dyn(&mut self);
866 fn info_dyn(&mut self, info_widgets: &mut InfoUpdates);
867 fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates);
868 fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates);
869}
870impl<O: AppEventObserver> AppEventObserverDyn for O {
871 fn raw_event_dyn(&mut self, ev: &zng_view_api::Event) {
872 self.raw_event(ev)
873 }
874
875 fn event_preview_dyn(&mut self, update: &mut EventUpdate) {
876 self.event_preview(update)
877 }
878
879 fn event_ui_dyn(&mut self, update: &mut EventUpdate) {
880 self.event_ui(update)
881 }
882
883 fn event_dyn(&mut self, update: &mut EventUpdate) {
884 self.event(update)
885 }
886
887 fn update_preview_dyn(&mut self) {
888 self.update_preview()
889 }
890
891 fn update_ui_dyn(&mut self, update_widgets: &mut WidgetUpdates) {
892 self.update_ui(update_widgets)
893 }
894
895 fn update_dyn(&mut self) {
896 self.update()
897 }
898
899 fn info_dyn(&mut self, info_widgets: &mut InfoUpdates) {
900 self.info(info_widgets)
901 }
902
903 fn layout_dyn(&mut self, layout_widgets: &mut LayoutUpdates) {
904 self.layout(layout_widgets)
905 }
906
907 fn render_dyn(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
908 self.render(render_widgets, render_update_widgets)
909 }
910}
911impl AppEventObserver for DynAppEventObserver<'_> {
912 fn raw_event(&mut self, ev: &zng_view_api::Event) {
913 self.0.raw_event_dyn(ev)
914 }
915
916 fn event_preview(&mut self, update: &mut EventUpdate) {
917 self.0.event_preview_dyn(update)
918 }
919
920 fn event_ui(&mut self, update: &mut EventUpdate) {
921 self.0.event_ui_dyn(update)
922 }
923
924 fn event(&mut self, update: &mut EventUpdate) {
925 self.0.event_dyn(update)
926 }
927
928 fn update_preview(&mut self) {
929 self.0.update_preview_dyn()
930 }
931
932 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
933 self.0.update_ui_dyn(update_widgets)
934 }
935
936 fn update(&mut self) {
937 self.0.update_dyn()
938 }
939
940 fn info(&mut self, info_widgets: &mut InfoUpdates) {
941 self.0.info_dyn(info_widgets)
942 }
943
944 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
945 self.0.layout_dyn(layout_widgets)
946 }
947
948 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
949 self.0.render_dyn(render_widgets, render_update_widgets)
950 }
951
952 fn as_dyn(&mut self) -> DynAppEventObserver<'_> {
953 DynAppEventObserver(self.0)
954 }
955}
956
957impl AppExtension for () {
958 fn register(&self, _: &mut AppExtensionsInfo) {}
959}
960impl<A: AppExtension, B: AppExtension> AppExtension for (A, B) {
961 fn init(&mut self) {
962 self.0.init();
963 self.1.init();
964 }
965
966 fn register(&self, info: &mut AppExtensionsInfo) {
967 self.0.register(info);
968 self.1.register(info);
969 }
970
971 fn enable_device_events(&self) -> bool {
972 self.0.enable_device_events() || self.1.enable_device_events()
973 }
974
975 fn update_preview(&mut self) {
976 self.0.update_preview();
977 self.1.update_preview();
978 }
979
980 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
981 self.0.update_ui(update_widgets);
982 self.1.update_ui(update_widgets);
983 }
984
985 fn update(&mut self) {
986 self.0.update();
987 self.1.update();
988 }
989
990 fn info(&mut self, info_widgets: &mut InfoUpdates) {
991 self.0.info(info_widgets);
992 self.1.info(info_widgets);
993 }
994
995 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
996 self.0.layout(layout_widgets);
997 self.1.layout(layout_widgets);
998 }
999
1000 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1001 self.0.render(render_widgets, render_update_widgets);
1002 self.1.render(render_widgets, render_update_widgets);
1003 }
1004
1005 fn event_preview(&mut self, update: &mut EventUpdate) {
1006 self.0.event_preview(update);
1007 self.1.event_preview(update);
1008 }
1009
1010 fn event_ui(&mut self, update: &mut EventUpdate) {
1011 self.0.event_ui(update);
1012 self.1.event_ui(update);
1013 }
1014
1015 fn event(&mut self, update: &mut EventUpdate) {
1016 self.0.event(update);
1017 self.1.event(update);
1018 }
1019
1020 fn deinit(&mut self) {
1021 self.1.deinit();
1022 self.0.deinit();
1023 }
1024}
1025
1026#[cfg(feature = "dyn_app_extension")]
1027impl AppExtension for Vec<Box<dyn AppExtensionBoxed>> {
1028 fn init(&mut self) {
1029 for ext in self {
1030 ext.init();
1031 }
1032 }
1033
1034 fn register(&self, info: &mut AppExtensionsInfo) {
1035 for ext in self {
1036 ext.register(info);
1037 }
1038 }
1039
1040 fn enable_device_events(&self) -> bool {
1041 self.iter().any(|e| e.enable_device_events())
1042 }
1043
1044 fn update_preview(&mut self) {
1045 for ext in self {
1046 ext.update_preview();
1047 }
1048 }
1049
1050 fn update_ui(&mut self, update_widgets: &mut WidgetUpdates) {
1051 for ext in self {
1052 ext.update_ui(update_widgets);
1053 }
1054 }
1055
1056 fn update(&mut self) {
1057 for ext in self {
1058 ext.update();
1059 }
1060 }
1061
1062 fn event_preview(&mut self, update: &mut EventUpdate) {
1063 for ext in self {
1064 ext.event_preview(update);
1065 }
1066 }
1067
1068 fn event_ui(&mut self, update: &mut EventUpdate) {
1069 for ext in self {
1070 ext.event_ui(update);
1071 }
1072 }
1073
1074 fn event(&mut self, update: &mut EventUpdate) {
1075 for ext in self {
1076 ext.event(update);
1077 }
1078 }
1079
1080 fn info(&mut self, info_widgets: &mut InfoUpdates) {
1081 for ext in self {
1082 ext.info(info_widgets);
1083 }
1084 }
1085
1086 fn layout(&mut self, layout_widgets: &mut LayoutUpdates) {
1087 for ext in self {
1088 ext.layout(layout_widgets);
1089 }
1090 }
1091
1092 fn render(&mut self, render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1093 for ext in self {
1094 ext.render(render_widgets, render_update_widgets);
1095 }
1096 }
1097
1098 fn deinit(&mut self) {
1099 for ext in self.iter_mut().rev() {
1100 ext.deinit();
1101 }
1102 }
1103}
1104
1105pub struct APP;
1107impl APP {
1108 pub fn multi_app_enabled(&self) -> bool {
1112 cfg!(feature = "multi_app")
1113 }
1114
1115 pub fn is_running(&self) -> bool {
1124 LocalContext::current_app().is_some()
1125 }
1126
1127 pub fn id(&self) -> Option<AppId> {
1135 LocalContext::current_app()
1136 }
1137
1138 #[cfg(not(feature = "multi_app"))]
1139 fn assert_can_run_single() {
1140 use std::sync::atomic::*;
1141 static CAN_RUN: AtomicBool = AtomicBool::new(true);
1142
1143 if !CAN_RUN.swap(false, Ordering::SeqCst) {
1144 panic!("only one app is allowed per process")
1145 }
1146 }
1147
1148 fn assert_can_run() {
1149 #[cfg(not(feature = "multi_app"))]
1150 Self::assert_can_run_single();
1151 if APP.is_running() {
1152 panic!("only one app is allowed per thread")
1153 }
1154 }
1155
1156 pub fn window_mode(&self) -> WindowMode {
1160 if VIEW_PROCESS.is_available() {
1161 if VIEW_PROCESS.is_headless_with_render() {
1162 WindowMode::HeadlessWithRenderer
1163 } else {
1164 WindowMode::Headed
1165 }
1166 } else {
1167 WindowMode::Headless
1168 }
1169 }
1170 pub fn extensions(&self) -> Arc<AppExtensionsInfo> {
1172 APP_PROCESS_SV.read().extensions()
1173 }
1174
1175 pub fn device_events(&self) -> bool {
1179 APP_PROCESS_SV.read().device_events
1180 }
1181}
1182
1183impl APP {
1184 #[cfg(feature = "dyn_app_extension")]
1186 pub fn minimal(&self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1187 zng_env::init_process_name("app-process");
1188
1189 #[cfg(debug_assertions)]
1190 print_tracing(tracing::Level::INFO);
1191 assert_not_view_process();
1192 Self::assert_can_run();
1193 check_deadlock();
1194
1195 let _ = INSTANT.now();
1196 let scope = LocalContext::start_app(AppId::new_unique());
1197 AppExtended {
1198 extensions: vec![],
1199 view_process_exe: None,
1200 view_process_env: HashMap::new(),
1201 _cleanup: scope,
1202 }
1203 }
1204
1205 #[cfg(not(feature = "dyn_app_extension"))]
1207 pub fn minimal(&self) -> AppExtended<()> {
1208 #[cfg(debug_assertions)]
1209 print_tracing(tracing::Level::INFO);
1210 assert_not_view_process();
1211 Self::assert_can_run();
1212 check_deadlock();
1213 let scope = LocalContext::start_app(AppId::new_unique());
1214 AppExtended {
1215 extensions: (),
1216 view_process_exe: None,
1217 view_process_env: HashMap::new(),
1218 _cleanup: scope,
1219 }
1220 }
1221}
1222
1223pub struct AppExtended<E: AppExtension> {
1227 extensions: E,
1228 view_process_exe: Option<PathBuf>,
1229 view_process_env: HashMap<Txt, Txt>,
1230
1231 _cleanup: AppScope,
1233}
1234#[cfg(feature = "dyn_app_extension")]
1235impl AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1236 pub fn extend<F: AppExtension>(mut self, extension: F) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1238 self.extensions.push(TraceAppExt(extension).boxed());
1239 self
1240 }
1241
1242 #[deprecated = "use `enable_input_device_events`"]
1244 pub fn enable_device_events(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1245 self.enable_input_device_events()
1246 }
1247
1248 pub fn enable_input_device_events(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1254 struct EnableDeviceEvents;
1255 impl AppExtension for EnableDeviceEvents {
1256 fn enable_device_events(&self) -> bool {
1257 true
1258 }
1259 }
1260 self.extend(EnableDeviceEvents)
1261 }
1262
1263 fn run_dyn(self, start: std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
1269 let app = RunningApp::start(
1270 self._cleanup,
1271 self.extensions,
1272 true,
1273 true,
1274 self.view_process_exe,
1275 self.view_process_env,
1276 );
1277
1278 UPDATES.run(start).perm();
1279
1280 app.run_headed();
1281 }
1282
1283 fn run_headless_dyn(self, with_renderer: bool) -> HeadlessApp {
1284 let app = RunningApp::start(
1285 self._cleanup,
1286 self.extensions.boxed(),
1287 false,
1288 with_renderer,
1289 self.view_process_exe,
1290 self.view_process_env,
1291 );
1292
1293 HeadlessApp { app }
1294 }
1295}
1296
1297#[cfg(feature = "dyn_app_extension")]
1299impl<E: AppExtension> AppExtended<E> {
1300 fn cast_app(self) -> AppExtended<Vec<Box<dyn AppExtensionBoxed>>> {
1301 let app: Box<dyn std::any::Any> = Box::new(self);
1302 match app.downcast::<AppExtended<Vec<Box<dyn AppExtensionBoxed>>>>() {
1303 Ok(ok) => *ok,
1304 Err(e) => {
1305 let app = *e.downcast::<Self>().unwrap();
1306 AppExtended {
1307 extensions: vec![app.extensions.boxed()],
1308 view_process_exe: app.view_process_exe,
1309 view_process_env: app.view_process_env,
1310 _cleanup: app._cleanup,
1311 }
1312 }
1313 }
1314 }
1315
1316 fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1317 self.cast_app().run_dyn(Box::pin(start))
1318 }
1319
1320 fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1321 self.cast_app().run_headless_dyn(with_renderer)
1322 }
1323}
1324
1325#[cfg(not(feature = "dyn_app_extension"))]
1326impl<E: AppExtension> AppExtended<E> {
1327 pub fn extend<F: AppExtension>(self, extension: F) -> AppExtended<impl AppExtension> {
1329 AppExtended {
1330 _cleanup: self._cleanup,
1331 extensions: (self.extensions, TraceAppExt(extension)),
1332 view_process_exe: self.view_process_exe,
1333 view_process_env: self.view_process_env,
1334 }
1335 }
1336
1337 pub fn enable_device_events(self) -> AppExtended<impl AppExtension> {
1343 struct EnableDeviceEvents;
1344 impl AppExtension for EnableDeviceEvents {
1345 fn enable_device_events(&self) -> bool {
1346 true
1347 }
1348 }
1349 self.extend(EnableDeviceEvents)
1350 }
1351
1352 fn run_impl(self, start: impl Future<Output = ()> + Send + 'static) {
1353 let app = RunningApp::start(
1354 self._cleanup,
1355 self.extensions,
1356 true,
1357 true,
1358 self.view_process_exe,
1359 self.view_process_env,
1360 );
1361
1362 UPDATES.run(start).perm();
1363
1364 app.run_headed();
1365 }
1366
1367 fn run_headless_impl(self, with_renderer: bool) -> HeadlessApp {
1368 let app = RunningApp::start(
1369 self._cleanup,
1370 self.extensions.boxed(),
1371 false,
1372 with_renderer,
1373 self.view_process_exe,
1374 self.view_process_env,
1375 );
1376
1377 HeadlessApp { app }
1378 }
1379}
1380impl<E: AppExtension> AppExtended<E> {
1381 pub fn view_process_exe(mut self, view_process_exe: impl Into<PathBuf>) -> Self {
1391 self.view_process_exe = Some(view_process_exe.into());
1392 self
1393 }
1394
1395 pub fn view_process_env(mut self, name: impl Into<Txt>, value: impl Into<Txt>) -> Self {
1397 self.view_process_env.insert(name.into(), value.into());
1398 self
1399 }
1400
1401 pub fn run<F: Future<Output = ()> + Send + 'static>(self, start: impl IntoFuture<IntoFuture = F>) {
1408 let start = start.into_future();
1409 #[cfg(feature = "dyn_closure")]
1410 let start = Box::pin(start);
1411 self.run_impl(start)
1412 }
1413
1414 pub fn run_headless(self, with_renderer: bool) -> HeadlessApp {
1419 self.run_headless_impl(with_renderer)
1420 }
1421}
1422
1423mod running;
1425pub use running::*;
1426
1427mod private {
1428 pub trait Sealed {}
1430}
1431
1432pub fn print_tracing(max: tracing::Level) -> bool {
1448 use tracing_subscriber::prelude::*;
1449
1450 let layers = tracing_subscriber::registry().with(FilterLayer(max));
1451
1452 #[cfg(target_os = "android")]
1453 let layers = layers.with(tracing_android::layer(&zng_env::about().pkg_name).unwrap());
1454
1455 #[cfg(not(target_os = "android"))]
1456 let layers = {
1457 let fmt_layer = tracing_subscriber::fmt::layer().without_time();
1458
1459 #[cfg(target_arch = "wasm32")]
1460 let fmt_layer = fmt_layer.with_ansi(false).with_writer(tracing_web::MakeWebConsoleWriter::new());
1461
1462 layers.with(fmt_layer)
1463 };
1464
1465 layers.try_init().is_ok()
1466}
1467
1468struct FilterLayer(tracing::Level);
1469impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for FilterLayer {
1470 fn enabled(&self, metadata: &tracing::Metadata<'_>, _: tracing_subscriber::layer::Context<'_, S>) -> bool {
1471 print_tracing_filter(&self.0, metadata)
1472 }
1473
1474 fn max_level_hint(&self) -> Option<tracing::metadata::LevelFilter> {
1475 Some(self.0.into())
1476 }
1477
1478 #[cfg(any(test, feature = "test_util"))]
1479 fn on_event(&self, event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
1480 if event.metadata().level() == &tracing::Level::ERROR && APP.is_running() && TEST_LOG.get() {
1481 struct MsgCollector<'a>(&'a mut String);
1482 impl tracing::field::Visit for MsgCollector<'_> {
1483 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn fmt::Debug) {
1484 use std::fmt::Write;
1485 write!(self.0, "\n {} = {:?}", field.name(), value).unwrap();
1486 }
1487 }
1488
1489 let meta = event.metadata();
1490 let file = meta.file().unwrap_or("");
1491 let line = meta.line().unwrap_or(0);
1492
1493 let mut msg = format!("[{file}:{line}]");
1494 event.record(&mut MsgCollector(&mut msg));
1495
1496 panic!("[LOG-ERROR]{msg}")
1497 }
1498 }
1499}
1500pub fn print_tracing_filter(level: &tracing::Level, metadata: &tracing::Metadata) -> bool {
1504 if metadata.level() > level {
1505 return false;
1506 }
1507
1508 if metadata.level() == &tracing::Level::INFO {
1509 if metadata.target() == "zng_webrender::device::gl" {
1511 return false;
1512 }
1513 if metadata.target() == "zng_webrender::renderer::init" {
1515 return false;
1516 }
1517 } else if metadata.level() == &tracing::Level::WARN {
1518 if metadata.target() == "zng_webrender::device::gl" {
1521 if metadata.line() == Some(4647) {
1524 return false;
1525 }
1526 }
1527
1528 if metadata.target() == "font_kit::loaders::freetype" {
1531 if metadata.line() == Some(734) {
1535 return false;
1536 }
1537 }
1538 }
1539
1540 true
1541}
1542
1543#[cfg(any(test, feature = "test_util"))]
1545pub fn test_log() {
1546 TEST_LOG.set(true);
1547}
1548
1549#[cfg(any(test, feature = "test_util"))]
1550zng_app_context::app_local! {
1551 static TEST_LOG: bool = false;
1552}
1553
1554#[doc(hidden)]
1555pub fn name_from_pkg_name(name: &'static str) -> Txt {
1556 let mut n = String::new();
1557 let mut sep = "";
1558 for part in name.split(&['-', '_']) {
1559 n.push_str(sep);
1560 let mut chars = part.char_indices();
1561 let (_, c) = chars.next().unwrap();
1562 c.to_uppercase().for_each(|c| n.push(c));
1563 if let Some((i, _)) = chars.next() {
1564 n.push_str(&part[i..]);
1565 }
1566 sep = " ";
1567 }
1568 n.into()
1569}
1570
1571#[doc(hidden)]
1572pub fn txt_from_pkg_meta(value: &'static str) -> Txt {
1573 value.into()
1574}