1use std::{
4 collections::{HashMap, hash_map},
5 fmt, mem,
6 sync::{Arc, atomic::AtomicBool},
7 task::Waker,
8};
9
10use parking_lot::Mutex;
11use zng_app_context::app_local;
12use zng_handle::{Handle, HandleOwner, WeakHandle};
13use zng_unique_id::IdSet;
14use zng_var::VARS_APP;
15
16use crate::{
17 AppEventSender, AppExtension, LoopTimer,
18 event::{AnyEvent, AnyEventArgs, AppDisconnected, EVENTS, EVENTS_SV},
19 handler::{AppHandler, AppHandlerArgs, AppWeakHandle, async_app_hn_once},
20 timer::TIMERS_SV,
21 widget::{
22 WIDGET, WidgetId,
23 info::{InteractionPath, WidgetInfo, WidgetInfoTree, WidgetPath},
24 node::{BoxedUiNode, UiNode},
25 },
26 window::{WINDOW, WindowId},
27};
28
29pub struct UpdateDeliveryList {
31 subscribers: Box<dyn UpdateSubscribers>,
32
33 windows: IdSet<WindowId>,
34 widgets: IdSet<WidgetId>,
35 search: IdSet<WidgetId>,
36 search_root: bool,
37}
38impl fmt::Debug for UpdateDeliveryList {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.debug_struct("UpdateDeliveryList")
41 .field("windows", &self.windows)
42 .field("widgets", &self.widgets)
43 .field("search", &self.search)
44 .finish_non_exhaustive()
45 }
46}
47impl Default for UpdateDeliveryList {
48 fn default() -> Self {
49 Self::new_any()
50 }
51}
52impl UpdateDeliveryList {
53 pub fn new(subscribers: Box<dyn UpdateSubscribers>) -> Self {
55 Self {
56 subscribers,
57 windows: IdSet::default(),
58 widgets: IdSet::default(),
59 search: IdSet::default(),
60 search_root: false,
61 }
62 }
63
64 pub fn new_none() -> Self {
66 struct UpdateDeliveryListNone;
67 impl UpdateSubscribers for UpdateDeliveryListNone {
68 fn contains(&self, _: WidgetId) -> bool {
69 false
70 }
71 fn to_set(&self) -> IdSet<WidgetId> {
72 IdSet::default()
73 }
74 }
75 Self::new(Box::new(UpdateDeliveryListNone))
76 }
77
78 pub fn new_any() -> Self {
82 struct UpdateDeliveryListAny;
83 impl UpdateSubscribers for UpdateDeliveryListAny {
84 fn contains(&self, _: WidgetId) -> bool {
85 true
86 }
87 fn to_set(&self) -> IdSet<WidgetId> {
88 IdSet::default()
89 }
90 }
91 Self::new(Box::new(UpdateDeliveryListAny))
92 }
93
94 pub(crate) fn insert_updates_root(&mut self, window_id: WindowId, root_id: WidgetId) {
95 self.windows.insert(window_id);
96 self.widgets.insert(root_id);
97 }
98
99 pub fn insert_wgt(&mut self, wgt: &impl WidgetPathProvider) {
101 let mut any = false;
102 for w in wgt.widget_and_ancestors() {
103 if any || self.subscribers.contains(w) {
104 any = true;
105 self.widgets.insert(w);
106 }
107 }
108 if any {
109 self.windows.insert(wgt.window_id());
110 }
111 }
112
113 pub fn insert_window(&mut self, id: WindowId) {
115 self.windows.insert(id);
116 self.search_root = true;
117 }
118
119 pub fn search_all(&mut self) {
121 self.search = self.subscribers.to_set();
122 }
123
124 pub fn search_widget(&mut self, widget_id: WidgetId) {
126 if self.subscribers.contains(widget_id) {
127 self.search.insert(widget_id);
128 }
129 }
130
131 pub fn has_pending_search(&mut self) -> bool {
133 self.search_root || !self.search.is_empty()
134 }
135
136 pub fn fulfill_search<'a, 'b>(&'a mut self, windows: impl Iterator<Item = &'b WidgetInfoTree>) {
138 for window in windows {
139 if self.search_root && self.windows.contains(&window.window_id()) {
140 self.widgets.insert(window.root().id());
141 }
142
143 self.search.retain(|w| {
144 if let Some(w) = window.get(*w) {
145 for w in w.widget_and_ancestors() {
146 self.widgets.insert(w);
147 }
148 self.windows.insert(w.window_id());
149 false
150 } else {
151 true
152 }
153 });
154 }
155 self.search.clear();
156 self.search_root = true;
157 }
158
159 fn extend_unchecked(&mut self, other: UpdateDeliveryList) {
161 if self.windows.is_empty() {
162 self.windows = other.windows;
163 } else {
164 self.windows.extend(other.windows);
165 }
166
167 if self.widgets.is_empty() {
168 self.widgets = other.widgets;
169 } else {
170 self.widgets.extend(other.widgets);
171 }
172
173 if self.search.is_empty() {
174 self.search = other.search;
175 } else {
176 self.search.extend(other.search);
177 }
178 }
179
180 pub fn enter_window(&self, window_id: WindowId) -> bool {
182 self.windows.contains(&window_id)
183 }
184
185 pub fn enter_widget(&self, widget_id: WidgetId) -> bool {
187 self.widgets.contains(&widget_id)
188 }
189
190 pub fn windows(&self) -> &IdSet<WindowId> {
192 &self.windows
193 }
194
195 pub fn widgets(&self) -> &IdSet<WidgetId> {
197 &self.widgets
198 }
199
200 #[must_use = "use `search_all` to request search"]
202 pub fn search_widgets(&mut self) -> &IdSet<WidgetId> {
203 &self.search
204 }
205
206 #[must_use = "use `search_widget` to request search"]
208 pub fn search_root(&mut self) -> bool {
209 self.search_root
210 }
211}
212
213pub trait WidgetPathProvider {
215 type WidgetIter<'s>: Iterator<Item = WidgetId>
217 where
218 Self: 's;
219
220 fn window_id(&self) -> WindowId;
222 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_>;
224}
225impl WidgetPathProvider for WidgetInfo {
226 type WidgetIter<'s> = std::iter::Map<crate::widget::info::iter::Ancestors, fn(WidgetInfo) -> WidgetId>;
227
228 fn window_id(&self) -> WindowId {
229 self.tree().window_id()
230 }
231
232 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
233 fn wgt_to_id(wgt: WidgetInfo) -> WidgetId {
234 wgt.id()
235 }
236 self.self_and_ancestors().map(wgt_to_id)
237 }
238}
239impl WidgetPathProvider for WidgetPath {
240 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
241
242 fn window_id(&self) -> WindowId {
243 self.window_id()
244 }
245
246 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
247 self.widgets_path().iter().copied().rev()
248 }
249}
250impl WidgetPathProvider for InteractionPath {
251 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
252
253 fn window_id(&self) -> WindowId {
254 WidgetPath::window_id(self)
255 }
256
257 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
258 self.widgets_path().iter().copied().rev()
259 }
260}
261
262pub trait UpdateSubscribers: Send + Sync + 'static {
264 fn contains(&self, widget_id: WidgetId) -> bool;
266 fn to_set(&self) -> IdSet<WidgetId>;
268}
269
270pub struct EventUpdate {
272 pub(crate) event: AnyEvent,
273 pub(crate) args: Box<dyn AnyEventArgs>,
274 pub(crate) delivery_list: UpdateDeliveryList,
275 pub(crate) pre_actions: Mutex<Vec<Box<dyn FnOnce(&EventUpdate) + Send>>>,
277 pub(crate) pos_actions: Mutex<Vec<Box<dyn FnOnce(&EventUpdate) + Send>>>,
278}
279impl EventUpdate {
280 pub fn event(&self) -> AnyEvent {
282 self.event
283 }
284
285 pub fn delivery_list(&self) -> &UpdateDeliveryList {
287 &self.delivery_list
288 }
289
290 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
294 &mut self.delivery_list
295 }
296
297 pub fn args(&self) -> &dyn AnyEventArgs {
299 &*self.args
300 }
301
302 pub fn with_window<H, R>(&self, handle: H) -> Option<R>
304 where
305 H: FnOnce() -> R,
306 {
307 if self.delivery_list.enter_window(WINDOW.id()) {
308 Some(handle())
309 } else {
310 None
311 }
312 }
313
314 pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
316 where
317 H: FnOnce() -> R,
318 {
319 if self.delivery_list.enter_widget(WIDGET.id()) {
320 if self.args.propagation().is_stopped() {
321 None
322 } else {
323 Some(handle())
324 }
325 } else {
326 None
327 }
328 }
329
330 pub(crate) fn push_once_action(&mut self, action: Box<dyn FnOnce(&EventUpdate) + Send>, is_preview: bool) {
331 if is_preview {
332 self.pre_actions.get_mut().push(action);
333 } else {
334 self.pos_actions.get_mut().push(action);
335 }
336 }
337
338 pub(crate) fn call_pre_actions(&mut self) {
339 let _s = tracing::trace_span!("call_pre_actions");
340 let actions = mem::take(self.pre_actions.get_mut());
341 for action in actions {
342 action(self)
343 }
344 }
345
346 pub(crate) fn call_pos_actions(&mut self) {
347 let _s = tracing::trace_span!("call_pos_actions");
348 let actions = mem::take(self.pos_actions.get_mut());
349 for action in actions {
350 action(self)
351 }
352 }
353}
354impl fmt::Debug for EventUpdate {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 f.debug_struct("EventUpdate")
357 .field("event", &self.event)
358 .field("args", &self.args)
359 .field("delivery_list", &self.delivery_list)
360 .finish_non_exhaustive()
361 }
362}
363
364#[derive(Debug, Default)]
366pub struct InfoUpdates {
367 delivery_list: UpdateDeliveryList,
368}
369impl InfoUpdates {
370 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
372 Self { delivery_list }
373 }
374
375 pub fn delivery_list(&self) -> &UpdateDeliveryList {
377 &self.delivery_list
378 }
379
380 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
382 &mut self.delivery_list
383 }
384
385 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
387 where
388 H: FnOnce() -> R,
389 {
390 if self.delivery_list.enter_window(window_id) {
391 Some(handle())
392 } else {
393 None
394 }
395 }
396
397 pub fn extend(&mut self, other: InfoUpdates) {
399 self.delivery_list.extend_unchecked(other.delivery_list)
400 }
401}
402
403#[derive(Debug, Default)]
405pub struct WidgetUpdates {
406 pub(crate) delivery_list: UpdateDeliveryList,
407}
408impl WidgetUpdates {
409 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
411 Self { delivery_list }
412 }
413
414 pub fn delivery_list(&self) -> &UpdateDeliveryList {
416 &self.delivery_list
417 }
418
419 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
421 &mut self.delivery_list
422 }
423
424 pub fn with_window<H, R>(&self, handle: H) -> Option<R>
426 where
427 H: FnOnce() -> R,
428 {
429 if self.delivery_list.enter_window(WINDOW.id()) {
430 Some(handle())
431 } else {
432 None
433 }
434 }
435
436 pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
438 where
439 H: FnOnce() -> R,
440 {
441 if WIDGET.take_update(UpdateFlags::UPDATE) || self.delivery_list.enter_widget(WIDGET.id()) {
442 Some(handle())
443 } else {
444 None
445 }
446 }
447
448 pub fn extend(&mut self, other: WidgetUpdates) {
450 self.delivery_list.extend_unchecked(other.delivery_list)
451 }
452}
453
454#[derive(Debug, Default)]
456pub struct LayoutUpdates {
457 pub(crate) delivery_list: UpdateDeliveryList,
458}
459impl LayoutUpdates {
460 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
462 Self { delivery_list }
463 }
464
465 pub fn delivery_list(&self) -> &UpdateDeliveryList {
467 &self.delivery_list
468 }
469
470 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
472 &mut self.delivery_list
473 }
474
475 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
477 where
478 H: FnOnce() -> R,
479 {
480 if self.delivery_list.enter_window(window_id) {
481 Some(handle())
482 } else {
483 None
484 }
485 }
486
487 pub fn extend(&mut self, other: LayoutUpdates) {
489 self.delivery_list.extend_unchecked(other.delivery_list)
490 }
491}
492
493#[derive(Debug, Default)]
495pub struct RenderUpdates {
496 delivery_list: UpdateDeliveryList,
497}
498impl RenderUpdates {
499 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
501 Self { delivery_list }
502 }
503
504 pub fn delivery_list(&self) -> &UpdateDeliveryList {
506 &self.delivery_list
507 }
508
509 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
511 &mut self.delivery_list
512 }
513
514 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
516 where
517 H: FnOnce() -> R,
518 {
519 if self.delivery_list.enter_window(window_id) {
520 Some(handle())
521 } else {
522 None
523 }
524 }
525
526 pub fn extend(&mut self, other: RenderUpdates) {
528 self.delivery_list.extend_unchecked(other.delivery_list)
529 }
530}
531
532pub trait UpdatesTraceUiNodeExt: UiNode {
536 fn instrument<S: Into<String>>(self, tag: S) -> BoxedUiNode
538 where
539 Self: Sized;
540}
541impl<U: UiNode> UpdatesTraceUiNodeExt for U {
542 fn instrument<S: Into<String>>(self, tag: S) -> BoxedUiNode {
543 let tag = tag.into();
544 self.trace(move |op| UpdatesTrace::custom_span(&tag, op.mtd_name()))
545 }
546}
547
548pub fn updates_trace_span(tag: &'static str) -> tracing::span::EnteredSpan {
552 UpdatesTrace::custom_span(tag, "")
553}
554
555pub fn updates_trace_event(tag: &str) {
559 UpdatesTrace::log_custom(tag)
560}
561
562pub(crate) struct UpdatesTrace {
563 context: Mutex<UpdateContext>,
564 trace: Arc<Mutex<Vec<UpdateTrace>>>,
565
566 widgets_stack: Mutex<Vec<(WidgetId, String)>>,
567 node_parents_stack: Mutex<Vec<String>>,
568 tags_stack: Mutex<Vec<String>>,
569}
570impl tracing::subscriber::Subscriber for UpdatesTrace {
571 fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
572 metadata.target() == Self::UPDATES_TARGET
573 }
574
575 fn new_span(&self, span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
576 let r = match span.metadata().name() {
577 "property" | "intrinsic" => {
578 let name = visit_str(|v| span.record(v), "name");
579 let mut ctx = self.context.lock();
580
581 if let Some(p) = ctx.node_parent.replace(name) {
582 self.node_parents_stack.lock().push(p);
583 }
584 if let Some(p) = ctx.tag.replace(String::new()) {
585 self.tags_stack.lock().push(p);
586 }
587
588 tracing::span::Id::from_u64(1)
589 }
590 "widget" => {
591 let id = visit_u64(|v| span.record(v), "raw_id").unwrap();
592 if id == 0 {
593 panic!()
594 }
595 let id = WidgetId::from_raw(id);
596
597 let name = visit_str(|v| span.record(v), "name");
598
599 let mut ctx = self.context.lock();
600 if let Some(p) = ctx.widget.replace((id, name)) {
601 self.widgets_stack.lock().push(p);
602 }
603
604 if let Some(p) = ctx.node_parent.replace(String::new()) {
605 self.node_parents_stack.lock().push(p);
606 }
607
608 if let Some(p) = ctx.tag.replace(String::new()) {
609 self.tags_stack.lock().push(p);
610 }
611
612 tracing::span::Id::from_u64(2)
613 }
614 "Window" => {
615 let id = visit_u64(|v| span.record(v), "raw_id").unwrap() as u32;
616 if id == 0 {
617 panic!()
618 }
619 let id = WindowId::from_raw(id);
620
621 let mut ctx = self.context.lock();
622 ctx.window_id = Some(id);
623
624 if let Some(p) = ctx.tag.replace(String::new()) {
625 self.tags_stack.lock().push(p);
626 }
627
628 tracing::span::Id::from_u64(3)
629 }
630 "AppExtension" => {
631 let name = visit_str(|v| span.record(v), "name");
632
633 let mut ctx = self.context.lock();
634 ctx.app_extension = Some(name);
635
636 if let Some(p) = ctx.tag.replace(String::new()) {
637 self.tags_stack.lock().push(p);
638 }
639
640 tracing::span::Id::from_u64(4)
641 }
642 "tag" => {
643 let tag = visit_str(|v| span.record(v), "tag");
644 let mut ctx = self.context.lock();
645 if let Some(p) = ctx.tag.replace(tag) {
646 self.tags_stack.lock().push(p);
647 }
648 tracing::span::Id::from_u64(5)
649 }
650 _ => tracing::span::Id::from_u64(u64::MAX),
651 };
652 r
654 }
655
656 fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
657
658 fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
659
660 fn event(&self, event: &tracing::Event<'_>) {
661 let action = match visit_str(|v| event.record(v), "kind").as_str() {
662 "var" => UpdateAction::Var {
663 type_name: visit_str(|v| event.record(v), "type_name"),
664 },
665 "event" => UpdateAction::Event {
666 type_name: visit_str(|v| event.record(v), "type_name"),
667 },
668 "request" => UpdateAction::Update,
669 "info" => UpdateAction::Info,
670 "layout" => UpdateAction::Layout,
671 "render" => UpdateAction::Render,
672 "custom" => UpdateAction::Custom {
673 tag: visit_str(|v| event.record(v), "tag"),
674 },
675 _ => return,
676 };
677
678 let ctx = self.context.lock().clone();
679 let entry = UpdateTrace { ctx, action };
684 self.trace.lock().push(entry);
685 }
686
687 fn enter(&self, _span: &tracing::span::Id) {}
688
689 fn exit(&self, span: &tracing::span::Id) {
690 let mut ctx = self.context.lock();
691 if span == &tracing::span::Id::from_u64(1) {
692 ctx.node_parent = self.node_parents_stack.lock().pop();
693 ctx.tag = self.tags_stack.lock().pop();
694 } else if span == &tracing::span::Id::from_u64(2) {
695 ctx.widget = self.widgets_stack.lock().pop();
696 ctx.node_parent = self.node_parents_stack.lock().pop();
697 ctx.tag = self.tags_stack.lock().pop();
698 } else if span == &tracing::span::Id::from_u64(3) {
699 ctx.window_id = None;
700 ctx.tag = self.tags_stack.lock().pop();
701 } else if span == &tracing::span::Id::from_u64(4) {
702 ctx.app_extension = None;
703 ctx.tag = self.tags_stack.lock().pop();
704 } else if span == &tracing::span::Id::from_u64(5) {
705 ctx.tag = self.tags_stack.lock().pop();
706 }
707 }
708}
709static UPDATES_TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
710impl UpdatesTrace {
711 const UPDATES_TARGET: &'static str = "zng-updates";
712
713 fn new() -> Self {
714 UpdatesTrace {
715 context: Mutex::new(UpdateContext::default()),
716 trace: Arc::new(Mutex::new(Vec::with_capacity(100))),
717 widgets_stack: Mutex::new(Vec::with_capacity(100)),
718 node_parents_stack: Mutex::new(Vec::with_capacity(100)),
719 tags_stack: Mutex::new(Vec::new()),
720 }
721 }
722
723 #[inline(always)]
725 pub fn is_tracing() -> bool {
726 UPDATES_TRACE_ENABLED.load(atomic::Ordering::Relaxed)
727 }
728
729 pub fn extension_span<E: AppExtension>(ext_mtd: &'static str) -> tracing::span::EnteredSpan {
731 if Self::is_tracing() {
732 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "AppExtension", name = pretty_type_name::pretty_type_name::<E>(), %ext_mtd).entered()
733 } else {
734 tracing::span::Span::none().entered()
735 }
736 }
737
738 pub fn window_span(id: WindowId) -> tracing::span::EnteredSpan {
740 if Self::is_tracing() {
741 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "Window", %id, raw_id = id.get() as u64).entered()
742 } else {
743 tracing::span::Span::none().entered()
744 }
745 }
746
747 #[cfg(feature = "trace_widget")]
749 pub fn widget_span(id: WidgetId, name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
750 if Self::is_tracing() {
751 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "widget", %id, raw_id = id.get(), name, %node_mtd).entered()
752 } else {
753 tracing::span::Span::none().entered()
754 }
755 }
756
757 #[cfg(feature = "trace_wgt_item")]
759 pub fn property_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
760 if Self::is_tracing() {
761 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "property", name, %node_mtd).entered()
762 } else {
763 tracing::span::Span::none().entered()
764 }
765 }
766
767 #[cfg(feature = "trace_wgt_item")]
769 pub fn intrinsic_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
770 if Self::is_tracing() {
771 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "intrinsic", name, %node_mtd).entered()
772 } else {
773 tracing::span::Span::none().entered()
774 }
775 }
776
777 pub fn custom_span(name: &str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
779 if Self::is_tracing() {
780 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "tag", %name, %node_mtd).entered()
781 } else {
782 tracing::Span::none().entered()
783 }
784 }
785
786 pub fn log_update() {
788 if Self::is_tracing() {
789 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
790 kind = "update"
791 });
792 }
793 }
794
795 pub fn log_info() {
797 if Self::is_tracing() {
798 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
799 kind = "info"
800 });
801 }
802 }
803
804 pub fn log_layout() {
806 if Self::is_tracing() {
807 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
808 kind = "layout"
809 });
810 }
811 }
812
813 pub fn log_render() {
815 if Self::is_tracing() {
816 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
817 kind = "render"
818 });
819 }
820 }
821
822 pub fn log_custom(tag: &str) {
824 if Self::is_tracing() {
825 tracing::event!(
826 target: UpdatesTrace::UPDATES_TARGET,
827 tracing::Level::TRACE,
828 { kind = "custom", %tag }
829 );
830 }
831 }
832
833 pub fn log_var(type_name: &str) {
835 if Self::is_tracing() {
836 tracing::event!(
837 target: UpdatesTrace::UPDATES_TARGET,
838 tracing::Level::TRACE,
839 { kind = "var", type_name = pretty_type_name::pretty_type_name_str(type_name) }
840 );
841 }
842 }
843
844 pub fn log_event(event: AnyEvent) {
846 if Self::is_tracing() {
847 tracing::event!(
848 target: UpdatesTrace::UPDATES_TARGET,
849 tracing::Level::TRACE,
850 { kind = "event", type_name = event.name() }
851 );
852 }
853 }
854
855 pub fn collect_trace<R>(trace: &mut Vec<UpdateTrace>, action: impl FnOnce() -> R) -> R {
857 let trace_enabled = UPDATES_TRACE_ENABLED.swap(true, atomic::Ordering::Relaxed);
858
859 let tracer = UpdatesTrace::new();
860 let result = Arc::clone(&tracer.trace);
861 let r = tracing::subscriber::with_default(tracer, action);
862 trace.extend(Arc::try_unwrap(result).unwrap().into_inner());
863
864 UPDATES_TRACE_ENABLED.store(trace_enabled, atomic::Ordering::Relaxed);
865
866 r
867 }
868
869 pub fn format_trace(trace: Vec<UpdateTrace>) -> String {
871 let mut frequencies = HashMap::with_capacity(50);
872 for t in trace {
873 match frequencies.entry(t) {
874 hash_map::Entry::Vacant(e) => {
875 e.insert(1);
876 }
877 hash_map::Entry::Occupied(mut e) => {
878 *e.get_mut() += 1;
879 }
880 }
881 }
882 let mut frequencies: Vec<_> = frequencies.into_iter().collect();
883 frequencies.sort_by_key(|(_, c)| -c);
884
885 let mut trace = String::new();
886 for (t, c) in frequencies.into_iter().take(20) {
887 use std::fmt::Write;
888 let _ = writeln!(&mut trace, "{t} ({c} times)");
889 }
890 trace
891 }
892}
893#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
894struct UpdateContext {
895 app_extension: Option<String>,
896 window_id: Option<WindowId>,
897 widget: Option<(WidgetId, String)>,
898 node_parent: Option<String>,
899 tag: Option<String>,
900}
901impl fmt::Display for UpdateContext {
902 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
903 if let Some(e) = &self.app_extension {
904 write!(f, "{}", e.rsplit("::").next().unwrap())?;
905 } else {
906 write!(f, "<unknown>")?;
907 }
908 if let Some(w) = self.window_id {
909 write!(f, "//{w}")?;
910 }
911 if let Some((id, name)) = &self.widget {
912 write!(f, "/../{name}#{id}")?;
913 }
914 if let Some(p) = &self.node_parent {
915 if !p.is_empty() {
916 write!(f, "//{p}")?;
917 }
918 }
919 if let Some(t) = &self.tag {
920 if !t.is_empty() {
921 write!(f, "//{t}")?;
922 }
923 }
924 Ok(())
925 }
926}
927
928#[derive(Debug, PartialEq, Eq, Hash)]
929pub(crate) struct UpdateTrace {
930 ctx: UpdateContext,
931 action: UpdateAction,
932}
933impl fmt::Display for UpdateTrace {
934 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
935 write!(f, "{} {}", self.ctx, self.action)
936 }
937}
938#[derive(Debug, PartialEq, Eq, Hash)]
939enum UpdateAction {
940 Info,
941 Update,
942 Layout,
943 Render,
944 Var { type_name: String },
945 Event { type_name: String },
946 Custom { tag: String },
947}
948impl fmt::Display for UpdateAction {
949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
950 match self {
951 UpdateAction::Info => write!(f, "info"),
952 UpdateAction::Update => write!(f, "update"),
953 UpdateAction::Layout => write!(f, "layout"),
954 UpdateAction::Render => write!(f, "render"),
955 UpdateAction::Var { type_name } => write!(f, "update var of type {type_name}"),
956 UpdateAction::Event { type_name } => write!(f, "update event {type_name}"),
957 UpdateAction::Custom { tag } => write!(f, "{tag}"),
958 }
959 }
960}
961
962fn visit_str(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> String {
963 struct Visitor<'a> {
964 name: &'a str,
965 result: String,
966 }
967 impl tracing::field::Visit for Visitor<'_> {
968 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
969 if field.name() == self.name {
970 self.result = format!("{value:?}");
971 }
972 }
973 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
974 if field.name() == self.name {
975 value.clone_into(&mut self.result);
976 }
977 }
978 }
979
980 let mut visitor = Visitor {
981 name,
982 result: String::new(),
983 };
984 record(&mut visitor);
985 visitor.result
986}
987fn visit_u64(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> Option<u64> {
988 struct Visitor<'a> {
989 name: &'a str,
990 result: Option<u64>,
991 }
992 impl tracing::field::Visit for Visitor<'_> {
993 fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
994 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
995 if field.name() == self.name {
996 self.result = Some(value)
997 }
998 }
999 }
1000
1001 let mut visitor = Visitor { name, result: None };
1002 record(&mut visitor);
1003 visitor.result
1004}
1005
1006pub struct UPDATES;
1008impl UPDATES {
1009 pub(crate) fn init(&self, event_sender: AppEventSender) {
1010 UPDATES_SV.write().event_sender = Some(event_sender);
1011 }
1012
1013 #[must_use]
1014 #[cfg(any(test, doc, feature = "test_util"))]
1015 pub(crate) fn apply(&self) -> ContextUpdates {
1016 self.apply_updates() | self.apply_info() | self.apply_layout_render()
1017 }
1018
1019 #[must_use]
1020 pub(crate) fn apply_updates(&self) -> ContextUpdates {
1021 let events = EVENTS.apply_updates();
1022 VARS_APP.apply_updates();
1023
1024 let (update, update_widgets) = UPDATES.take_update();
1025
1026 ContextUpdates {
1027 events,
1028 update,
1029 update_widgets,
1030 info: false,
1031 info_widgets: InfoUpdates::default(),
1032 layout: false,
1033 layout_widgets: LayoutUpdates::default(),
1034 render: false,
1035 render_widgets: RenderUpdates::default(),
1036 render_update_widgets: RenderUpdates::default(),
1037 }
1038 }
1039 #[must_use]
1040 pub(crate) fn apply_info(&self) -> ContextUpdates {
1041 let (info, info_widgets) = UPDATES.take_info();
1042
1043 ContextUpdates {
1044 events: vec![],
1045 update: false,
1046 update_widgets: WidgetUpdates::default(),
1047 info,
1048 info_widgets,
1049 layout: false,
1050 layout_widgets: LayoutUpdates::default(),
1051 render: false,
1052 render_widgets: RenderUpdates::default(),
1053 render_update_widgets: RenderUpdates::default(),
1054 }
1055 }
1056 #[must_use]
1057 pub(crate) fn apply_layout_render(&self) -> ContextUpdates {
1058 let (layout, layout_widgets) = UPDATES.take_layout();
1059 let (render, render_widgets, render_update_widgets) = UPDATES.take_render();
1060
1061 ContextUpdates {
1062 events: vec![],
1063 update: false,
1064 update_widgets: WidgetUpdates::default(),
1065 info: false,
1066 info_widgets: InfoUpdates::default(),
1067 layout,
1068 layout_widgets,
1069 render,
1070 render_widgets,
1071 render_update_widgets,
1072 }
1073 }
1074
1075 pub(crate) fn on_app_awake(&self) {
1076 UPDATES_SV.write().app_awake(true);
1077 }
1078
1079 pub(crate) fn on_app_sleep(&self) {
1080 UPDATES_SV.write().app_awake(false);
1081 }
1082
1083 pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
1085 TIMERS_SV.write().next_deadline(timer);
1086 VARS_APP.next_deadline(timer);
1087 }
1088
1089 pub(crate) fn update_timers(&self, timer: &mut LoopTimer) {
1091 TIMERS_SV.write().apply_updates(timer);
1092 VARS_APP.update_animations(timer);
1093 }
1094
1095 #[must_use]
1097 pub(crate) fn has_pending_updates(&self) -> bool {
1098 UPDATES_SV.read().update_ext.intersects(UpdateFlags::UPDATE | UpdateFlags::INFO)
1099 || VARS_APP.has_pending_updates()
1100 || EVENTS_SV.write().has_pending_updates()
1101 || TIMERS_SV.read().has_pending_updates()
1102 }
1103
1104 #[must_use]
1105 pub(crate) fn has_pending_layout_or_render(&self) -> bool {
1106 UPDATES_SV
1107 .read()
1108 .update_ext
1109 .intersects(UpdateFlags::LAYOUT | UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE)
1110 }
1111
1112 pub fn sender(&self) -> AppEventSender {
1114 UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
1115 }
1116
1117 pub fn waker(&self, target: impl Into<Option<WidgetId>>) -> Waker {
1119 UPDATES_SV.read().event_sender.as_ref().unwrap().waker(target)
1120 }
1121
1122 pub(crate) fn update_flags_root(&self, flags: UpdateFlags, window_id: WindowId, root_id: WidgetId) {
1123 if flags.is_empty() {
1124 return;
1125 }
1126
1127 let mut u = UPDATES_SV.write();
1128 if flags.contains(UpdateFlags::UPDATE) {
1129 u.update_widgets.insert_updates_root(window_id, root_id);
1130 }
1131 if flags.contains(UpdateFlags::INFO) {
1132 u.info_widgets.insert_updates_root(window_id, root_id);
1133 }
1134 if flags.contains(UpdateFlags::LAYOUT) {
1135 u.layout_widgets.insert_updates_root(window_id, root_id);
1136 }
1137
1138 if flags.contains(UpdateFlags::RENDER) {
1139 u.render_widgets.insert_updates_root(window_id, root_id);
1140 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1141 u.render_update_widgets.insert_updates_root(window_id, root_id);
1142 }
1143
1144 u.update_ext |= flags;
1145 }
1146
1147 pub(crate) fn update_flags(&self, flags: UpdateFlags, target: impl Into<Option<WidgetId>>) {
1148 if flags.is_empty() {
1149 return;
1150 }
1151
1152 let mut u = UPDATES_SV.write();
1153
1154 if let Some(id) = target.into() {
1155 if flags.contains(UpdateFlags::UPDATE) {
1156 u.update_widgets.search_widget(id);
1157 }
1158 if flags.contains(UpdateFlags::INFO) {
1159 u.info_widgets.search_widget(id);
1160 }
1161 if flags.contains(UpdateFlags::LAYOUT) {
1162 u.layout_widgets.search_widget(id);
1163 }
1164
1165 if flags.contains(UpdateFlags::RENDER) {
1166 u.render_widgets.search_widget(id);
1167 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1168 u.render_update_widgets.search_widget(id);
1169 }
1170 }
1171
1172 u.update_ext |= flags;
1173 }
1174
1175 pub fn update_op(&self, op: UpdateOp, target: impl Into<Option<WidgetId>>) -> &Self {
1177 let target = target.into();
1178 match op {
1179 UpdateOp::Update => self.update(target),
1180 UpdateOp::Info => self.update_info(target),
1181 UpdateOp::Layout => self.layout(target),
1182 UpdateOp::Render => self.render(target),
1183 UpdateOp::RenderUpdate => self.render_update(target),
1184 }
1185 }
1186
1187 pub fn update_op_window(&self, op: UpdateOp, target: WindowId) -> &Self {
1189 match op {
1190 UpdateOp::Update => self.update_window(target),
1191 UpdateOp::Info => self.update_info_window(target),
1192 UpdateOp::Layout => self.layout_window(target),
1193 UpdateOp::Render => self.render_window(target),
1194 UpdateOp::RenderUpdate => self.render_update_window(target),
1195 }
1196 }
1197
1198 pub fn update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1202 UpdatesTrace::log_update();
1203 self.update_internal(target.into())
1204 }
1205 pub(crate) fn update_internal(&self, target: Option<WidgetId>) -> &UPDATES {
1207 let mut u = UPDATES_SV.write();
1208 u.update_ext.insert(UpdateFlags::UPDATE);
1209 u.send_awake();
1210 if let Some(id) = target {
1211 u.update_widgets.search_widget(id);
1212 }
1213 self
1214 }
1215
1216 pub fn update_window(&self, target: WindowId) -> &Self {
1218 let mut u = UPDATES_SV.write();
1219 u.update_ext.insert(UpdateFlags::UPDATE);
1220 u.send_awake();
1221 u.update_widgets.insert_window(target);
1222 self
1223 }
1224
1225 pub(crate) fn send_awake(&self) {
1226 UPDATES_SV.write().send_awake();
1227 }
1228
1229 pub fn update_info(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1233 UpdatesTrace::log_info();
1234 let mut u = UPDATES_SV.write();
1235 u.update_ext.insert(UpdateFlags::INFO);
1236 u.send_awake();
1237 if let Some(id) = target.into() {
1238 u.info_widgets.search_widget(id);
1239 }
1240 self
1241 }
1242
1243 pub fn update_info_window(&self, target: WindowId) -> &Self {
1245 UpdatesTrace::log_info();
1246 let mut u = UPDATES_SV.write();
1247 u.update_ext.insert(UpdateFlags::INFO);
1248 u.send_awake();
1249 u.info_widgets.insert_window(target);
1250 self
1251 }
1252
1253 pub fn layout(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1257 UpdatesTrace::log_layout();
1258 let mut u = UPDATES_SV.write();
1259 u.update_ext.insert(UpdateFlags::LAYOUT);
1260 u.send_awake();
1261 if let Some(id) = target.into() {
1262 u.layout_widgets.search_widget(id);
1263 }
1264 self
1265 }
1266
1267 pub fn layout_window(&self, target: WindowId) -> &Self {
1269 UpdatesTrace::log_layout();
1270 let mut u = UPDATES_SV.write();
1271 u.update_ext.insert(UpdateFlags::LAYOUT);
1272 u.send_awake();
1273 u.layout_widgets.insert_window(target);
1274 self
1275 }
1276
1277 pub fn render(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1284 UpdatesTrace::log_render();
1285 let mut u = UPDATES_SV.write();
1286 u.update_ext.insert(UpdateFlags::RENDER);
1287 u.send_awake();
1288 if let Some(id) = target.into() {
1289 u.render_widgets.search_widget(id);
1290 }
1291 self
1292 }
1293
1294 pub fn render_window(&self, target: WindowId) -> &Self {
1296 UpdatesTrace::log_render();
1297 let mut u = UPDATES_SV.write();
1298 u.update_ext.insert(UpdateFlags::RENDER);
1299 u.send_awake();
1300 u.render_widgets.insert_window(target);
1301 self
1302 }
1303
1304 pub fn render_update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1310 UpdatesTrace::log_render();
1311 let mut u = UPDATES_SV.write();
1312 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1313 u.send_awake();
1314 if let Some(id) = target.into() {
1315 u.render_update_widgets.search_widget(id);
1316 }
1317 self
1318 }
1319
1320 pub fn render_update_window(&self, target: WindowId) -> &Self {
1322 UpdatesTrace::log_render();
1323 let mut u = UPDATES_SV.write();
1324 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1325 u.send_awake();
1326 u.render_update_widgets.insert_window(target);
1327 self
1328 }
1329
1330 pub fn is_pending_render(&self, window_id: WindowId) -> bool {
1332 let u = UPDATES_SV.read();
1333 u.render_widgets.enter_window(window_id) || u.render_update_widgets.enter_window(window_id)
1334 }
1335
1336 pub fn run<F: Future<Output = ()> + Send + 'static>(&self, future: F) -> OnUpdateHandle {
1340 self.run_hn_once(async_app_hn_once!(|_| future.await))
1341 }
1342
1343 pub fn run_hn_once<H: AppHandler<UpdateArgs>>(&self, handler: H) -> OnUpdateHandle {
1348 let mut u = UPDATES_SV.write();
1349 u.update_ext.insert(UpdateFlags::UPDATE);
1350 u.send_awake();
1351 Self::push_handler(u.pos_handlers.get_mut(), true, handler, true)
1352 }
1353
1354 pub fn on_pre_update<H>(&self, handler: H) -> OnUpdateHandle
1368 where
1369 H: AppHandler<UpdateArgs>,
1370 {
1371 let u = UPDATES_SV.read();
1372 let r = Self::push_handler(&mut u.pre_handlers.lock(), true, handler, false);
1373 r
1374 }
1375
1376 pub fn on_update<H>(&self, handler: H) -> OnUpdateHandle
1390 where
1391 H: AppHandler<UpdateArgs>,
1392 {
1393 let u = UPDATES_SV.read();
1394 let r = Self::push_handler(&mut u.pos_handlers.lock(), false, handler, false);
1395 r
1396 }
1397
1398 fn push_handler<H>(entries: &mut Vec<UpdateHandler>, is_preview: bool, mut handler: H, force_once: bool) -> OnUpdateHandle
1399 where
1400 H: AppHandler<UpdateArgs>,
1401 {
1402 let (handle_owner, handle) = OnUpdateHandle::new();
1403 entries.push(UpdateHandler {
1404 handle: handle_owner,
1405 count: 0,
1406 handler: Box::new(move |args, handle| {
1407 let handler_args = AppHandlerArgs { handle, is_preview };
1408 handler.event(args, &handler_args);
1409 if force_once {
1410 handler_args.handle.unsubscribe();
1411 }
1412 }),
1413 });
1414 handle
1415 }
1416
1417 pub(crate) fn on_pre_updates(&self) {
1418 let _s = tracing::trace_span!("UPDATES.on_pre_updates");
1419 let mut handlers = mem::take(UPDATES_SV.write().pre_handlers.get_mut());
1420 Self::retain_updates(&mut handlers);
1421
1422 let mut u = UPDATES_SV.write();
1423 handlers.append(u.pre_handlers.get_mut());
1424 *u.pre_handlers.get_mut() = handlers;
1425 }
1426
1427 pub(crate) fn on_updates(&self) {
1428 let _s = tracing::trace_span!("UPDATES.on_updates");
1429 let mut handlers = mem::take(UPDATES_SV.write().pos_handlers.get_mut());
1430 Self::retain_updates(&mut handlers);
1431
1432 let mut u = UPDATES_SV.write();
1433 handlers.append(u.pos_handlers.get_mut());
1434 *u.pos_handlers.get_mut() = handlers;
1435 }
1436
1437 fn retain_updates(handlers: &mut Vec<UpdateHandler>) {
1438 handlers.retain_mut(|e| {
1439 !e.handle.is_dropped() && {
1440 e.count = e.count.wrapping_add(1);
1441 (e.handler)(&UpdateArgs { count: e.count }, &e.handle.weak_handle());
1442 !e.handle.is_dropped()
1443 }
1444 });
1445 }
1446
1447 pub(super) fn take_update(&self) -> (bool, WidgetUpdates) {
1449 let mut u = UPDATES_SV.write();
1450
1451 let ext = u.update_ext.contains(UpdateFlags::UPDATE);
1452 u.update_ext.remove(UpdateFlags::UPDATE);
1453
1454 (
1455 ext,
1456 WidgetUpdates {
1457 delivery_list: mem::take(&mut u.update_widgets),
1458 },
1459 )
1460 }
1461
1462 pub(super) fn take_info(&self) -> (bool, InfoUpdates) {
1464 let mut u = UPDATES_SV.write();
1465
1466 let ext = u.update_ext.contains(UpdateFlags::INFO);
1467 u.update_ext.remove(UpdateFlags::INFO);
1468
1469 (
1470 ext,
1471 InfoUpdates {
1472 delivery_list: mem::take(&mut u.info_widgets),
1473 },
1474 )
1475 }
1476
1477 pub(super) fn take_layout(&self) -> (bool, LayoutUpdates) {
1479 let mut u = UPDATES_SV.write();
1480
1481 let ext = u.update_ext.contains(UpdateFlags::LAYOUT);
1482 u.update_ext.remove(UpdateFlags::LAYOUT);
1483
1484 (
1485 ext,
1486 LayoutUpdates {
1487 delivery_list: mem::take(&mut u.layout_widgets),
1488 },
1489 )
1490 }
1491
1492 pub(super) fn take_render(&self) -> (bool, RenderUpdates, RenderUpdates) {
1494 let mut u = UPDATES_SV.write();
1495
1496 let ext = u.update_ext.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1497 u.update_ext.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1498
1499 (
1500 ext,
1501 RenderUpdates {
1502 delivery_list: mem::take(&mut u.render_widgets),
1503 },
1504 RenderUpdates {
1505 delivery_list: mem::take(&mut u.render_update_widgets),
1506 },
1507 )
1508 }
1509
1510 pub(crate) fn handler_lens(&self) -> (usize, usize) {
1511 let u = UPDATES_SV.read();
1512 let r = (u.pre_handlers.lock().len(), u.pos_handlers.lock().len());
1513 r
1514 }
1515 pub(crate) fn new_update_handlers(&self, pre_from: usize, pos_from: usize) -> Vec<Box<dyn Fn() -> bool>> {
1516 let u = UPDATES_SV.read();
1517 let r = u
1518 .pre_handlers
1519 .lock()
1520 .iter()
1521 .skip(pre_from)
1522 .chain(u.pos_handlers.lock().iter().skip(pos_from))
1523 .map(|h| h.handle.weak_handle())
1524 .map(|h| {
1525 let r: Box<dyn Fn() -> bool> = Box::new(move || h.upgrade().is_some());
1526 r
1527 })
1528 .collect();
1529 r
1530 }
1531}
1532
1533app_local! {
1534 static UPDATES_SV: UpdatesService = UpdatesService::new();
1535}
1536struct UpdatesService {
1537 event_sender: Option<AppEventSender>,
1538
1539 update_ext: UpdateFlags,
1540 update_widgets: UpdateDeliveryList,
1541 info_widgets: UpdateDeliveryList,
1542 layout_widgets: UpdateDeliveryList,
1543 render_widgets: UpdateDeliveryList,
1544 render_update_widgets: UpdateDeliveryList,
1545
1546 pre_handlers: Mutex<Vec<UpdateHandler>>,
1547 pos_handlers: Mutex<Vec<UpdateHandler>>,
1548
1549 app_is_awake: bool,
1550 awake_pending: bool,
1551}
1552impl UpdatesService {
1553 fn new() -> Self {
1554 Self {
1555 event_sender: None,
1556 update_ext: UpdateFlags::empty(),
1557 update_widgets: UpdateDeliveryList::new_any(),
1558 info_widgets: UpdateDeliveryList::new_any(),
1559 layout_widgets: UpdateDeliveryList::new_any(),
1560 render_widgets: UpdateDeliveryList::new_any(),
1561 render_update_widgets: UpdateDeliveryList::new_any(),
1562
1563 pre_handlers: Mutex::new(vec![]),
1564 pos_handlers: Mutex::new(vec![]),
1565
1566 app_is_awake: false,
1567 awake_pending: false,
1568 }
1569 }
1570
1571 fn send_awake(&mut self) {
1572 if !self.app_is_awake && !self.awake_pending {
1573 self.awake_pending = true;
1574 match self.event_sender.as_ref() {
1575 Some(s) => {
1576 if let Err(AppDisconnected(())) = s.send_check_update() {
1577 tracing::debug!("no app connected to update");
1578 }
1579 }
1580 None => {
1581 tracing::debug!("no app connected yet to update");
1582 }
1583 }
1584 }
1585 }
1586
1587 fn app_awake(&mut self, wake: bool) {
1588 self.awake_pending = false;
1589 self.app_is_awake = wake;
1590 }
1591}
1592
1593#[derive(Default)]
1597pub struct ContextUpdates {
1598 pub events: Vec<EventUpdate>,
1602
1603 pub update: bool,
1608
1609 pub info: bool,
1614
1615 pub layout: bool,
1620
1621 pub render: bool,
1626
1627 pub update_widgets: WidgetUpdates,
1631
1632 pub info_widgets: InfoUpdates,
1636
1637 pub layout_widgets: LayoutUpdates,
1641
1642 pub render_widgets: RenderUpdates,
1646
1647 pub render_update_widgets: RenderUpdates,
1651}
1652
1653impl fmt::Debug for ContextUpdates {
1654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1655 if f.alternate() {
1656 f.debug_struct("ContextUpdates")
1657 .field("update", &self.update)
1658 .field("info", &self.info)
1659 .field("layout", &self.layout)
1660 .field("render", &self.render)
1661 .field("events", &self.events)
1662 .field("update_widgets", &self.update_widgets)
1663 .field("info_widgets", &self.info_widgets)
1664 .field("layout_widgets", &self.layout_widgets)
1665 .field("render_widgets", &self.render_widgets)
1666 .field("render_update_widgets", &self.render_update_widgets)
1667 .finish()
1668 } else {
1669 write!(f, "ContextUpdates: ")?;
1670 let mut sep = "";
1671 if !self.events.is_empty() {
1672 write!(f, "{sep}events[")?;
1673 for e in &self.events {
1674 write!(f, "{sep}{}", e.event.name())?;
1675 sep = ", ";
1676 }
1677 write!(f, "]")?;
1678 }
1679 if self.update {
1680 write!(f, "{sep}update")?;
1681 sep = ", ";
1682 }
1683 if self.info {
1684 write!(f, "{sep}info")?;
1685 sep = ", ";
1686 }
1687 if self.layout {
1688 write!(f, "{sep}layout")?;
1689 sep = ", ";
1690 }
1691 if self.render {
1692 write!(f, "{sep}render")?;
1693 sep = ", ";
1694 }
1695 if sep.is_empty() {
1696 write!(f, "<none>")?;
1697 }
1698 Ok(())
1699 }
1700 }
1701}
1702impl ContextUpdates {
1703 pub fn has_updates(&self) -> bool {
1705 !self.events.is_empty() || self.update || self.info || self.layout || self.render
1706 }
1707}
1708impl std::ops::BitOrAssign for ContextUpdates {
1709 fn bitor_assign(&mut self, rhs: Self) {
1710 self.events.extend(rhs.events);
1711 self.update |= rhs.update;
1712 self.update_widgets.extend(rhs.update_widgets);
1713 self.info |= rhs.info;
1714 self.info_widgets.extend(rhs.info_widgets);
1715 self.layout |= rhs.layout;
1716 self.layout_widgets.extend(rhs.layout_widgets);
1717 self.render |= rhs.render;
1718 self.render_widgets.extend(rhs.render_widgets);
1719 self.render_update_widgets.extend(rhs.render_update_widgets);
1720 }
1721}
1722impl std::ops::BitOr for ContextUpdates {
1723 type Output = Self;
1724
1725 fn bitor(mut self, rhs: Self) -> Self {
1726 self |= rhs;
1727 self
1728 }
1729}
1730
1731bitflags::bitflags! {
1732 #[derive(Clone, Copy, Debug, bytemuck::NoUninit)]
1733 #[repr(transparent)]
1734 pub(crate) struct UpdateFlags: u8 {
1735 const REINIT = 0b1000_0000;
1736 const INFO = 0b0001_0000;
1737 const UPDATE = 0b0000_0001;
1738 const LAYOUT = 0b0000_0010;
1739 const RENDER = 0b0000_0100;
1740 const RENDER_UPDATE = 0b0000_1000;
1741 }
1742}
1743
1744#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1749#[repr(transparent)]
1750#[must_use = "dropping the handle unsubscribes update handler"]
1751pub struct OnUpdateHandle(Handle<()>);
1752impl OnUpdateHandle {
1753 fn new() -> (HandleOwner<()>, OnUpdateHandle) {
1754 let (owner, handle) = Handle::new(());
1755 (owner, OnUpdateHandle(handle))
1756 }
1757
1758 pub fn dummy() -> Self {
1762 OnUpdateHandle(Handle::dummy(()))
1763 }
1764
1765 pub fn perm(self) {
1769 self.0.perm();
1770 }
1771
1772 pub fn is_permanent(&self) -> bool {
1776 self.0.is_permanent()
1777 }
1778
1779 pub fn unsubscribe(self) {
1781 self.0.force_drop()
1782 }
1783
1784 pub fn is_unsubscribed(&self) -> bool {
1788 self.0.is_dropped()
1789 }
1790
1791 pub fn downgrade(&self) -> WeakOnUpdateHandle {
1793 WeakOnUpdateHandle(self.0.downgrade())
1794 }
1795}
1796
1797#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1799pub struct WeakOnUpdateHandle(WeakHandle<()>);
1800impl WeakOnUpdateHandle {
1801 pub fn new() -> Self {
1803 Self(WeakHandle::new())
1804 }
1805
1806 pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1808 self.0.upgrade().map(OnUpdateHandle)
1809 }
1810}
1811
1812#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1814pub enum UpdateOp {
1815 Update,
1823 Info,
1832 Layout,
1840 Render,
1848 RenderUpdate,
1859}
1860
1861#[derive(Debug, Clone, Copy)]
1863pub struct UpdateArgs {
1864 pub count: usize,
1866}
1867
1868struct UpdateHandler {
1869 handle: HandleOwner<()>,
1870 count: usize,
1871 handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1872}