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 AppChannelError, AppEventSender, AppExtension, LoopTimer,
18 event::{AnyEvent, AnyEventArgs, 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 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 }
653
654 fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
655
656 fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
657
658 fn event(&self, event: &tracing::Event<'_>) {
659 let action = match visit_str(|v| event.record(v), "kind").as_str() {
660 "var" => UpdateAction::Var {
661 type_name: visit_str(|v| event.record(v), "type_name"),
662 },
663 "event" => UpdateAction::Event {
664 type_name: visit_str(|v| event.record(v), "type_name"),
665 },
666 "request" => UpdateAction::Update,
667 "info" => UpdateAction::Info,
668 "layout" => UpdateAction::Layout,
669 "render" => UpdateAction::Render,
670 "custom" => UpdateAction::Custom {
671 tag: visit_str(|v| event.record(v), "tag"),
672 },
673 _ => return,
674 };
675
676 let ctx = self.context.lock().clone();
677 let entry = UpdateTrace { ctx, action };
682 self.trace.lock().push(entry);
683 }
684
685 fn enter(&self, _span: &tracing::span::Id) {}
686
687 fn exit(&self, span: &tracing::span::Id) {
688 let mut ctx = self.context.lock();
689 if span == &tracing::span::Id::from_u64(1) {
690 ctx.node_parent = self.node_parents_stack.lock().pop();
691 ctx.tag = self.tags_stack.lock().pop();
692 } else if span == &tracing::span::Id::from_u64(2) {
693 ctx.widget = self.widgets_stack.lock().pop();
694 ctx.node_parent = self.node_parents_stack.lock().pop();
695 ctx.tag = self.tags_stack.lock().pop();
696 } else if span == &tracing::span::Id::from_u64(3) {
697 ctx.window_id = None;
698 ctx.tag = self.tags_stack.lock().pop();
699 } else if span == &tracing::span::Id::from_u64(4) {
700 ctx.app_extension = None;
701 ctx.tag = self.tags_stack.lock().pop();
702 } else if span == &tracing::span::Id::from_u64(5) {
703 ctx.tag = self.tags_stack.lock().pop();
704 }
705 }
706}
707static UPDATES_TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
708impl UpdatesTrace {
709 const UPDATES_TARGET: &'static str = "zng-updates";
710
711 fn new() -> Self {
712 UpdatesTrace {
713 context: Mutex::new(UpdateContext::default()),
714 trace: Arc::new(Mutex::new(Vec::with_capacity(100))),
715 widgets_stack: Mutex::new(Vec::with_capacity(100)),
716 node_parents_stack: Mutex::new(Vec::with_capacity(100)),
717 tags_stack: Mutex::new(Vec::new()),
718 }
719 }
720
721 #[inline(always)]
723 pub fn is_tracing() -> bool {
724 UPDATES_TRACE_ENABLED.load(atomic::Ordering::Relaxed)
725 }
726
727 pub fn extension_span<E: AppExtension>(ext_mtd: &'static str) -> tracing::span::EnteredSpan {
729 if Self::is_tracing() {
730 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "AppExtension", name = pretty_type_name::pretty_type_name::<E>(), %ext_mtd).entered()
731 } else {
732 tracing::span::Span::none().entered()
733 }
734 }
735
736 pub fn window_span(id: WindowId) -> tracing::span::EnteredSpan {
738 if Self::is_tracing() {
739 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "Window", %id, raw_id = id.get() as u64).entered()
740 } else {
741 tracing::span::Span::none().entered()
742 }
743 }
744
745 #[cfg(feature = "trace_widget")]
747 pub fn widget_span(id: WidgetId, name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
748 if Self::is_tracing() {
749 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "widget", %id, raw_id = id.get(), name, %node_mtd).entered()
750 } else {
751 tracing::span::Span::none().entered()
752 }
753 }
754
755 #[cfg(feature = "trace_wgt_item")]
757 pub fn property_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
758 if Self::is_tracing() {
759 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "property", name, %node_mtd).entered()
760 } else {
761 tracing::span::Span::none().entered()
762 }
763 }
764
765 #[cfg(feature = "trace_wgt_item")]
767 pub fn intrinsic_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
768 if Self::is_tracing() {
769 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "intrinsic", name, %node_mtd).entered()
770 } else {
771 tracing::span::Span::none().entered()
772 }
773 }
774
775 pub fn custom_span(name: &str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
777 if Self::is_tracing() {
778 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "tag", %name, %node_mtd).entered()
779 } else {
780 tracing::Span::none().entered()
781 }
782 }
783
784 pub fn log_update() {
786 if Self::is_tracing() {
787 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
788 kind = "update"
789 });
790 }
791 }
792
793 pub fn log_info() {
795 if Self::is_tracing() {
796 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
797 kind = "info"
798 });
799 }
800 }
801
802 pub fn log_layout() {
804 if Self::is_tracing() {
805 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
806 kind = "layout"
807 });
808 }
809 }
810
811 pub fn log_render() {
813 if Self::is_tracing() {
814 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
815 kind = "render"
816 });
817 }
818 }
819
820 pub fn log_custom(tag: &str) {
822 if Self::is_tracing() {
823 tracing::event!(
824 target: UpdatesTrace::UPDATES_TARGET,
825 tracing::Level::TRACE,
826 { kind = "custom", %tag }
827 );
828 }
829 }
830
831 pub fn log_var(type_name: &str) {
833 if Self::is_tracing() {
834 tracing::event!(
835 target: UpdatesTrace::UPDATES_TARGET,
836 tracing::Level::TRACE,
837 { kind = "var", type_name = pretty_type_name::pretty_type_name_str(type_name) }
838 );
839 }
840 }
841
842 pub fn log_event(event: AnyEvent) {
844 if Self::is_tracing() {
845 tracing::event!(
846 target: UpdatesTrace::UPDATES_TARGET,
847 tracing::Level::TRACE,
848 { kind = "event", type_name = event.name() }
849 );
850 }
851 }
852
853 pub fn collect_trace<R>(trace: &mut Vec<UpdateTrace>, action: impl FnOnce() -> R) -> R {
855 let trace_enabled = UPDATES_TRACE_ENABLED.swap(true, atomic::Ordering::Relaxed);
856
857 let tracer = UpdatesTrace::new();
858 let result = Arc::clone(&tracer.trace);
859 let r = tracing::subscriber::with_default(tracer, action);
860 trace.extend(Arc::try_unwrap(result).unwrap().into_inner());
861
862 UPDATES_TRACE_ENABLED.store(trace_enabled, atomic::Ordering::Relaxed);
863
864 r
865 }
866
867 pub fn format_trace(trace: Vec<UpdateTrace>) -> String {
869 let mut frequencies = HashMap::with_capacity(50);
870 for t in trace {
871 match frequencies.entry(t) {
872 hash_map::Entry::Vacant(e) => {
873 e.insert(1);
874 }
875 hash_map::Entry::Occupied(mut e) => {
876 *e.get_mut() += 1;
877 }
878 }
879 }
880 let mut frequencies: Vec<_> = frequencies.into_iter().collect();
881 frequencies.sort_by_key(|(_, c)| -c);
882
883 let mut trace = String::new();
884 for (t, c) in frequencies.into_iter().take(20) {
885 use std::fmt::Write;
886 let _ = writeln!(&mut trace, "{t} ({c} times)");
887 }
888 trace
889 }
890}
891#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
892struct UpdateContext {
893 app_extension: Option<String>,
894 window_id: Option<WindowId>,
895 widget: Option<(WidgetId, String)>,
896 node_parent: Option<String>,
897 tag: Option<String>,
898}
899impl fmt::Display for UpdateContext {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 if let Some(e) = &self.app_extension {
902 write!(f, "{}", e.rsplit("::").next().unwrap())?;
903 } else {
904 write!(f, "<unknown>")?;
905 }
906 if let Some(w) = self.window_id {
907 write!(f, "//{w}")?;
908 }
909 if let Some((id, name)) = &self.widget {
910 write!(f, "/../{name}#{id}")?;
911 }
912 if let Some(p) = &self.node_parent {
913 if !p.is_empty() {
914 write!(f, "//{p}")?;
915 }
916 }
917 if let Some(t) = &self.tag {
918 if !t.is_empty() {
919 write!(f, "//{t}")?;
920 }
921 }
922 Ok(())
923 }
924}
925
926#[derive(Debug, PartialEq, Eq, Hash)]
927pub(crate) struct UpdateTrace {
928 ctx: UpdateContext,
929 action: UpdateAction,
930}
931impl fmt::Display for UpdateTrace {
932 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933 write!(f, "{} {}", self.ctx, self.action)
934 }
935}
936#[derive(Debug, PartialEq, Eq, Hash)]
937enum UpdateAction {
938 Info,
939 Update,
940 Layout,
941 Render,
942 Var { type_name: String },
943 Event { type_name: String },
944 Custom { tag: String },
945}
946impl fmt::Display for UpdateAction {
947 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
948 match self {
949 UpdateAction::Info => write!(f, "info"),
950 UpdateAction::Update => write!(f, "update"),
951 UpdateAction::Layout => write!(f, "layout"),
952 UpdateAction::Render => write!(f, "render"),
953 UpdateAction::Var { type_name } => write!(f, "update var of type {type_name}"),
954 UpdateAction::Event { type_name } => write!(f, "update event {type_name}"),
955 UpdateAction::Custom { tag } => write!(f, "{tag}"),
956 }
957 }
958}
959
960fn visit_str(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> String {
961 struct Visitor<'a> {
962 name: &'a str,
963 result: String,
964 }
965 impl tracing::field::Visit for Visitor<'_> {
966 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
967 if field.name() == self.name {
968 self.result = format!("{value:?}");
969 }
970 }
971 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
972 if field.name() == self.name {
973 value.clone_into(&mut self.result);
974 }
975 }
976 }
977
978 let mut visitor = Visitor {
979 name,
980 result: String::new(),
981 };
982 record(&mut visitor);
983 visitor.result
984}
985fn visit_u64(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> Option<u64> {
986 struct Visitor<'a> {
987 name: &'a str,
988 result: Option<u64>,
989 }
990 impl tracing::field::Visit for Visitor<'_> {
991 fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
992 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
993 if field.name() == self.name {
994 self.result = Some(value)
995 }
996 }
997 }
998
999 let mut visitor = Visitor { name, result: None };
1000 record(&mut visitor);
1001 visitor.result
1002}
1003
1004pub struct UPDATES;
1006impl UPDATES {
1007 pub(crate) fn init(&self, event_sender: AppEventSender) {
1008 UPDATES_SV.write().event_sender = Some(event_sender);
1009 }
1010
1011 #[must_use]
1012 #[cfg(any(test, doc, feature = "test_util"))]
1013 pub(crate) fn apply(&self) -> ContextUpdates {
1014 self.apply_updates() | self.apply_info() | self.apply_layout_render()
1015 }
1016
1017 #[must_use]
1018 pub(crate) fn apply_updates(&self) -> ContextUpdates {
1019 let events = EVENTS.apply_updates();
1020 VARS_APP.apply_updates();
1021
1022 let (update, update_widgets) = UPDATES.take_update();
1023
1024 ContextUpdates {
1025 events,
1026 update,
1027 update_widgets,
1028 info: false,
1029 info_widgets: InfoUpdates::default(),
1030 layout: false,
1031 layout_widgets: LayoutUpdates::default(),
1032 render: false,
1033 render_widgets: RenderUpdates::default(),
1034 render_update_widgets: RenderUpdates::default(),
1035 }
1036 }
1037 #[must_use]
1038 pub(crate) fn apply_info(&self) -> ContextUpdates {
1039 let (info, info_widgets) = UPDATES.take_info();
1040
1041 ContextUpdates {
1042 events: vec![],
1043 update: false,
1044 update_widgets: WidgetUpdates::default(),
1045 info,
1046 info_widgets,
1047 layout: false,
1048 layout_widgets: LayoutUpdates::default(),
1049 render: false,
1050 render_widgets: RenderUpdates::default(),
1051 render_update_widgets: RenderUpdates::default(),
1052 }
1053 }
1054 #[must_use]
1055 pub(crate) fn apply_layout_render(&self) -> ContextUpdates {
1056 let (layout, layout_widgets) = UPDATES.take_layout();
1057 let (render, render_widgets, render_update_widgets) = UPDATES.take_render();
1058
1059 ContextUpdates {
1060 events: vec![],
1061 update: false,
1062 update_widgets: WidgetUpdates::default(),
1063 info: false,
1064 info_widgets: InfoUpdates::default(),
1065 layout,
1066 layout_widgets,
1067 render,
1068 render_widgets,
1069 render_update_widgets,
1070 }
1071 }
1072
1073 pub(crate) fn on_app_awake(&self) {
1074 UPDATES_SV.write().app_awake(true);
1075 }
1076
1077 pub(crate) fn on_app_sleep(&self) {
1078 UPDATES_SV.write().app_awake(false);
1079 }
1080
1081 pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
1083 TIMERS_SV.write().next_deadline(timer);
1084 VARS_APP.next_deadline(timer);
1085 }
1086
1087 pub(crate) fn update_timers(&self, timer: &mut LoopTimer) {
1089 TIMERS_SV.write().apply_updates(timer);
1090 VARS_APP.update_animations(timer);
1091 }
1092
1093 #[must_use]
1095 pub(crate) fn has_pending_updates(&self) -> bool {
1096 UPDATES_SV.read().update_ext.intersects(UpdateFlags::UPDATE | UpdateFlags::INFO)
1097 || VARS_APP.has_pending_updates()
1098 || EVENTS_SV.write().has_pending_updates()
1099 || TIMERS_SV.read().has_pending_updates()
1100 }
1101
1102 #[must_use]
1103 pub(crate) fn has_pending_layout_or_render(&self) -> bool {
1104 UPDATES_SV
1105 .read()
1106 .update_ext
1107 .intersects(UpdateFlags::LAYOUT | UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE)
1108 }
1109
1110 pub fn sender(&self) -> AppEventSender {
1112 UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
1113 }
1114
1115 pub fn waker(&self, target: impl Into<Option<WidgetId>>) -> Waker {
1117 UPDATES_SV.read().event_sender.as_ref().unwrap().waker(target)
1118 }
1119
1120 pub(crate) fn update_flags_root(&self, flags: UpdateFlags, window_id: WindowId, root_id: WidgetId) {
1121 if flags.is_empty() {
1122 return;
1123 }
1124
1125 let mut u = UPDATES_SV.write();
1126 if flags.contains(UpdateFlags::UPDATE) {
1127 u.update_widgets.insert_updates_root(window_id, root_id);
1128 }
1129 if flags.contains(UpdateFlags::INFO) {
1130 u.info_widgets.insert_updates_root(window_id, root_id);
1131 }
1132 if flags.contains(UpdateFlags::LAYOUT) {
1133 u.layout_widgets.insert_updates_root(window_id, root_id);
1134 }
1135
1136 if flags.contains(UpdateFlags::RENDER) {
1137 u.render_widgets.insert_updates_root(window_id, root_id);
1138 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1139 u.render_update_widgets.insert_updates_root(window_id, root_id);
1140 }
1141
1142 u.update_ext |= flags;
1143 }
1144
1145 pub(crate) fn update_flags(&self, flags: UpdateFlags, target: impl Into<Option<WidgetId>>) {
1146 if flags.is_empty() {
1147 return;
1148 }
1149
1150 let mut u = UPDATES_SV.write();
1151
1152 if let Some(id) = target.into() {
1153 if flags.contains(UpdateFlags::UPDATE) {
1154 u.update_widgets.search_widget(id);
1155 }
1156 if flags.contains(UpdateFlags::INFO) {
1157 u.info_widgets.search_widget(id);
1158 }
1159 if flags.contains(UpdateFlags::LAYOUT) {
1160 u.layout_widgets.search_widget(id);
1161 }
1162
1163 if flags.contains(UpdateFlags::RENDER) {
1164 u.render_widgets.search_widget(id);
1165 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1166 u.render_update_widgets.search_widget(id);
1167 }
1168 }
1169
1170 u.update_ext |= flags;
1171 }
1172
1173 pub fn update_op(&self, op: UpdateOp, target: impl Into<Option<WidgetId>>) -> &Self {
1175 let target = target.into();
1176 match op {
1177 UpdateOp::Update => self.update(target),
1178 UpdateOp::Info => self.update_info(target),
1179 UpdateOp::Layout => self.layout(target),
1180 UpdateOp::Render => self.render(target),
1181 UpdateOp::RenderUpdate => self.render_update(target),
1182 }
1183 }
1184
1185 pub fn update_op_window(&self, op: UpdateOp, target: WindowId) -> &Self {
1187 match op {
1188 UpdateOp::Update => self.update_window(target),
1189 UpdateOp::Info => self.update_info_window(target),
1190 UpdateOp::Layout => self.layout_window(target),
1191 UpdateOp::Render => self.render_window(target),
1192 UpdateOp::RenderUpdate => self.render_update_window(target),
1193 }
1194 }
1195
1196 pub fn update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1200 UpdatesTrace::log_update();
1201 self.update_internal(target.into())
1202 }
1203 pub(crate) fn update_internal(&self, target: Option<WidgetId>) -> &UPDATES {
1205 let mut u = UPDATES_SV.write();
1206 u.update_ext.insert(UpdateFlags::UPDATE);
1207 u.send_awake();
1208 if let Some(id) = target {
1209 u.update_widgets.search_widget(id);
1210 }
1211 self
1212 }
1213
1214 pub fn update_window(&self, target: WindowId) -> &Self {
1216 let mut u = UPDATES_SV.write();
1217 u.update_ext.insert(UpdateFlags::UPDATE);
1218 u.send_awake();
1219 u.update_widgets.insert_window(target);
1220 self
1221 }
1222
1223 pub(crate) fn send_awake(&self) {
1224 UPDATES_SV.write().send_awake();
1225 }
1226
1227 pub fn update_info(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1231 UpdatesTrace::log_info();
1232 let mut u = UPDATES_SV.write();
1233 u.update_ext.insert(UpdateFlags::INFO);
1234 u.send_awake();
1235 if let Some(id) = target.into() {
1236 u.info_widgets.search_widget(id);
1237 }
1238 self
1239 }
1240
1241 pub fn update_info_window(&self, target: WindowId) -> &Self {
1243 UpdatesTrace::log_info();
1244 let mut u = UPDATES_SV.write();
1245 u.update_ext.insert(UpdateFlags::INFO);
1246 u.send_awake();
1247 u.info_widgets.insert_window(target);
1248 self
1249 }
1250
1251 pub fn layout(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1255 UpdatesTrace::log_layout();
1256 let mut u = UPDATES_SV.write();
1257 u.update_ext.insert(UpdateFlags::LAYOUT);
1258 u.send_awake();
1259 if let Some(id) = target.into() {
1260 u.layout_widgets.search_widget(id);
1261 }
1262 self
1263 }
1264
1265 pub fn layout_window(&self, target: WindowId) -> &Self {
1267 UpdatesTrace::log_layout();
1268 let mut u = UPDATES_SV.write();
1269 u.update_ext.insert(UpdateFlags::LAYOUT);
1270 u.send_awake();
1271 u.layout_widgets.insert_window(target);
1272 self
1273 }
1274
1275 pub fn render(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1282 UpdatesTrace::log_render();
1283 let mut u = UPDATES_SV.write();
1284 u.update_ext.insert(UpdateFlags::RENDER);
1285 u.send_awake();
1286 if let Some(id) = target.into() {
1287 u.render_widgets.search_widget(id);
1288 }
1289 self
1290 }
1291
1292 pub fn render_window(&self, target: WindowId) -> &Self {
1294 UpdatesTrace::log_render();
1295 let mut u = UPDATES_SV.write();
1296 u.update_ext.insert(UpdateFlags::RENDER);
1297 u.send_awake();
1298 u.render_widgets.insert_window(target);
1299 self
1300 }
1301
1302 pub fn render_update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1308 UpdatesTrace::log_render();
1309 let mut u = UPDATES_SV.write();
1310 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1311 u.send_awake();
1312 if let Some(id) = target.into() {
1313 u.render_update_widgets.search_widget(id);
1314 }
1315 self
1316 }
1317
1318 pub fn render_update_window(&self, target: WindowId) -> &Self {
1320 UpdatesTrace::log_render();
1321 let mut u = UPDATES_SV.write();
1322 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1323 u.send_awake();
1324 u.render_update_widgets.insert_window(target);
1325 self
1326 }
1327
1328 pub fn is_pending_render(&self, window_id: WindowId) -> bool {
1330 let u = UPDATES_SV.read();
1331 u.render_widgets.enter_window(window_id) || u.render_update_widgets.enter_window(window_id)
1332 }
1333
1334 pub fn run<F: Future<Output = ()> + Send + 'static>(&self, future: F) -> OnUpdateHandle {
1338 self.run_hn_once(async_app_hn_once!(|_| future.await))
1339 }
1340
1341 pub fn run_hn_once<H: AppHandler<UpdateArgs>>(&self, handler: H) -> OnUpdateHandle {
1346 let mut u = UPDATES_SV.write();
1347 u.update_ext.insert(UpdateFlags::UPDATE);
1348 u.send_awake();
1349 Self::push_handler(u.pos_handlers.get_mut(), true, handler, true)
1350 }
1351
1352 pub fn on_pre_update<H>(&self, handler: H) -> OnUpdateHandle
1366 where
1367 H: AppHandler<UpdateArgs>,
1368 {
1369 let u = UPDATES_SV.read();
1370 Self::push_handler(&mut u.pre_handlers.lock(), true, handler, false)
1371 }
1372
1373 pub fn on_update<H>(&self, handler: H) -> OnUpdateHandle
1387 where
1388 H: AppHandler<UpdateArgs>,
1389 {
1390 let u = UPDATES_SV.read();
1391 Self::push_handler(&mut u.pos_handlers.lock(), false, handler, false)
1392 }
1393
1394 fn push_handler<H>(entries: &mut Vec<UpdateHandler>, is_preview: bool, mut handler: H, force_once: bool) -> OnUpdateHandle
1395 where
1396 H: AppHandler<UpdateArgs>,
1397 {
1398 let (handle_owner, handle) = OnUpdateHandle::new();
1399 entries.push(UpdateHandler {
1400 handle: handle_owner,
1401 count: 0,
1402 handler: Box::new(move |args, handle| {
1403 let handler_args = AppHandlerArgs { handle, is_preview };
1404 handler.event(args, &handler_args);
1405 if force_once {
1406 handler_args.handle.unsubscribe();
1407 }
1408 }),
1409 });
1410 handle
1411 }
1412
1413 pub(crate) fn on_pre_updates(&self) {
1414 let _s = tracing::trace_span!("UPDATES.on_pre_updates");
1415 let mut handlers = mem::take(UPDATES_SV.write().pre_handlers.get_mut());
1416 Self::retain_updates(&mut handlers);
1417
1418 let mut u = UPDATES_SV.write();
1419 handlers.append(u.pre_handlers.get_mut());
1420 *u.pre_handlers.get_mut() = handlers;
1421 }
1422
1423 pub(crate) fn on_updates(&self) {
1424 let _s = tracing::trace_span!("UPDATES.on_updates");
1425 let mut handlers = mem::take(UPDATES_SV.write().pos_handlers.get_mut());
1426 Self::retain_updates(&mut handlers);
1427
1428 let mut u = UPDATES_SV.write();
1429 handlers.append(u.pos_handlers.get_mut());
1430 *u.pos_handlers.get_mut() = handlers;
1431 }
1432
1433 fn retain_updates(handlers: &mut Vec<UpdateHandler>) {
1434 handlers.retain_mut(|e| {
1435 !e.handle.is_dropped() && {
1436 e.count = e.count.wrapping_add(1);
1437 (e.handler)(&UpdateArgs { count: e.count }, &e.handle.weak_handle());
1438 !e.handle.is_dropped()
1439 }
1440 });
1441 }
1442
1443 pub(super) fn take_update(&self) -> (bool, WidgetUpdates) {
1445 let mut u = UPDATES_SV.write();
1446
1447 let ext = u.update_ext.contains(UpdateFlags::UPDATE);
1448 u.update_ext.remove(UpdateFlags::UPDATE);
1449
1450 (
1451 ext,
1452 WidgetUpdates {
1453 delivery_list: mem::take(&mut u.update_widgets),
1454 },
1455 )
1456 }
1457
1458 pub(super) fn take_info(&self) -> (bool, InfoUpdates) {
1460 let mut u = UPDATES_SV.write();
1461
1462 let ext = u.update_ext.contains(UpdateFlags::INFO);
1463 u.update_ext.remove(UpdateFlags::INFO);
1464
1465 (
1466 ext,
1467 InfoUpdates {
1468 delivery_list: mem::take(&mut u.info_widgets),
1469 },
1470 )
1471 }
1472
1473 pub(super) fn take_layout(&self) -> (bool, LayoutUpdates) {
1475 let mut u = UPDATES_SV.write();
1476
1477 let ext = u.update_ext.contains(UpdateFlags::LAYOUT);
1478 u.update_ext.remove(UpdateFlags::LAYOUT);
1479
1480 (
1481 ext,
1482 LayoutUpdates {
1483 delivery_list: mem::take(&mut u.layout_widgets),
1484 },
1485 )
1486 }
1487
1488 pub(super) fn take_render(&self) -> (bool, RenderUpdates, RenderUpdates) {
1490 let mut u = UPDATES_SV.write();
1491
1492 let ext = u.update_ext.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1493 u.update_ext.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1494
1495 (
1496 ext,
1497 RenderUpdates {
1498 delivery_list: mem::take(&mut u.render_widgets),
1499 },
1500 RenderUpdates {
1501 delivery_list: mem::take(&mut u.render_update_widgets),
1502 },
1503 )
1504 }
1505
1506 pub(crate) fn handler_lens(&self) -> (usize, usize) {
1507 let u = UPDATES_SV.read();
1508
1509 (u.pre_handlers.lock().len(), u.pos_handlers.lock().len())
1510 }
1511 pub(crate) fn new_update_handlers(&self, pre_from: usize, pos_from: usize) -> Vec<Box<dyn Fn() -> bool>> {
1512 let u = UPDATES_SV.read();
1513
1514 u.pre_handlers
1515 .lock()
1516 .iter()
1517 .skip(pre_from)
1518 .chain(u.pos_handlers.lock().iter().skip(pos_from))
1519 .map(|h| h.handle.weak_handle())
1520 .map(|h| {
1521 let r: Box<dyn Fn() -> bool> = Box::new(move || h.upgrade().is_some());
1522 r
1523 })
1524 .collect()
1525 }
1526}
1527
1528app_local! {
1529 static UPDATES_SV: UpdatesService = UpdatesService::new();
1530}
1531struct UpdatesService {
1532 event_sender: Option<AppEventSender>,
1533
1534 update_ext: UpdateFlags,
1535 update_widgets: UpdateDeliveryList,
1536 info_widgets: UpdateDeliveryList,
1537 layout_widgets: UpdateDeliveryList,
1538 render_widgets: UpdateDeliveryList,
1539 render_update_widgets: UpdateDeliveryList,
1540
1541 pre_handlers: Mutex<Vec<UpdateHandler>>,
1542 pos_handlers: Mutex<Vec<UpdateHandler>>,
1543
1544 app_is_awake: bool,
1545 awake_pending: bool,
1546}
1547impl UpdatesService {
1548 fn new() -> Self {
1549 Self {
1550 event_sender: None,
1551 update_ext: UpdateFlags::empty(),
1552 update_widgets: UpdateDeliveryList::new_any(),
1553 info_widgets: UpdateDeliveryList::new_any(),
1554 layout_widgets: UpdateDeliveryList::new_any(),
1555 render_widgets: UpdateDeliveryList::new_any(),
1556 render_update_widgets: UpdateDeliveryList::new_any(),
1557
1558 pre_handlers: Mutex::new(vec![]),
1559 pos_handlers: Mutex::new(vec![]),
1560
1561 app_is_awake: false,
1562 awake_pending: false,
1563 }
1564 }
1565
1566 fn send_awake(&mut self) {
1567 if !self.app_is_awake && !self.awake_pending {
1568 self.awake_pending = true;
1569 match self.event_sender.as_ref() {
1570 Some(s) => {
1571 if let Err(AppChannelError::Disconnected) = s.send_check_update() {
1572 tracing::debug!("no app connected to update");
1573 }
1574 }
1575 None => {
1576 tracing::debug!("no app connected yet to update");
1577 }
1578 }
1579 }
1580 }
1581
1582 fn app_awake(&mut self, wake: bool) {
1583 self.awake_pending = false;
1584 self.app_is_awake = wake;
1585 }
1586}
1587
1588#[non_exhaustive]
1592#[derive(Default)]
1593pub struct ContextUpdates {
1594 pub events: Vec<EventUpdate>,
1598
1599 pub update: bool,
1604
1605 pub info: bool,
1610
1611 pub layout: bool,
1616
1617 pub render: bool,
1622
1623 pub update_widgets: WidgetUpdates,
1627
1628 pub info_widgets: InfoUpdates,
1632
1633 pub layout_widgets: LayoutUpdates,
1637
1638 pub render_widgets: RenderUpdates,
1642
1643 pub render_update_widgets: RenderUpdates,
1647}
1648
1649impl fmt::Debug for ContextUpdates {
1650 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1651 if f.alternate() {
1652 f.debug_struct("ContextUpdates")
1653 .field("update", &self.update)
1654 .field("info", &self.info)
1655 .field("layout", &self.layout)
1656 .field("render", &self.render)
1657 .field("events", &self.events)
1658 .field("update_widgets", &self.update_widgets)
1659 .field("info_widgets", &self.info_widgets)
1660 .field("layout_widgets", &self.layout_widgets)
1661 .field("render_widgets", &self.render_widgets)
1662 .field("render_update_widgets", &self.render_update_widgets)
1663 .finish()
1664 } else {
1665 write!(f, "ContextUpdates: ")?;
1666 let mut sep = "";
1667 if !self.events.is_empty() {
1668 write!(f, "{sep}events[")?;
1669 for e in &self.events {
1670 write!(f, "{sep}{}", e.event.name())?;
1671 sep = ", ";
1672 }
1673 write!(f, "]")?;
1674 }
1675 if self.update {
1676 write!(f, "{sep}update")?;
1677 sep = ", ";
1678 }
1679 if self.info {
1680 write!(f, "{sep}info")?;
1681 sep = ", ";
1682 }
1683 if self.layout {
1684 write!(f, "{sep}layout")?;
1685 sep = ", ";
1686 }
1687 if self.render {
1688 write!(f, "{sep}render")?;
1689 sep = ", ";
1690 }
1691 if sep.is_empty() {
1692 write!(f, "<none>")?;
1693 }
1694 Ok(())
1695 }
1696 }
1697}
1698impl ContextUpdates {
1699 pub fn has_updates(&self) -> bool {
1701 !self.events.is_empty() || self.update || self.info || self.layout || self.render
1702 }
1703}
1704impl std::ops::BitOrAssign for ContextUpdates {
1705 fn bitor_assign(&mut self, rhs: Self) {
1706 self.events.extend(rhs.events);
1707 self.update |= rhs.update;
1708 self.update_widgets.extend(rhs.update_widgets);
1709 self.info |= rhs.info;
1710 self.info_widgets.extend(rhs.info_widgets);
1711 self.layout |= rhs.layout;
1712 self.layout_widgets.extend(rhs.layout_widgets);
1713 self.render |= rhs.render;
1714 self.render_widgets.extend(rhs.render_widgets);
1715 self.render_update_widgets.extend(rhs.render_update_widgets);
1716 }
1717}
1718impl std::ops::BitOr for ContextUpdates {
1719 type Output = Self;
1720
1721 fn bitor(mut self, rhs: Self) -> Self {
1722 self |= rhs;
1723 self
1724 }
1725}
1726
1727bitflags::bitflags! {
1728 #[derive(Clone, Copy, Debug, bytemuck::NoUninit)]
1729 #[repr(transparent)]
1730 pub(crate) struct UpdateFlags: u8 {
1731 const REINIT = 0b1000_0000;
1732 const INFO = 0b0001_0000;
1733 const UPDATE = 0b0000_0001;
1734 const LAYOUT = 0b0000_0010;
1735 const RENDER = 0b0000_0100;
1736 const RENDER_UPDATE = 0b0000_1000;
1737 }
1738}
1739
1740#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1745#[repr(transparent)]
1746#[must_use = "dropping the handle unsubscribes update handler"]
1747pub struct OnUpdateHandle(Handle<()>);
1748impl OnUpdateHandle {
1749 fn new() -> (HandleOwner<()>, OnUpdateHandle) {
1750 let (owner, handle) = Handle::new(());
1751 (owner, OnUpdateHandle(handle))
1752 }
1753
1754 pub fn dummy() -> Self {
1758 OnUpdateHandle(Handle::dummy(()))
1759 }
1760
1761 pub fn perm(self) {
1765 self.0.perm();
1766 }
1767
1768 pub fn is_permanent(&self) -> bool {
1772 self.0.is_permanent()
1773 }
1774
1775 pub fn unsubscribe(self) {
1777 self.0.force_drop()
1778 }
1779
1780 pub fn is_unsubscribed(&self) -> bool {
1784 self.0.is_dropped()
1785 }
1786
1787 pub fn downgrade(&self) -> WeakOnUpdateHandle {
1789 WeakOnUpdateHandle(self.0.downgrade())
1790 }
1791}
1792
1793#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1795pub struct WeakOnUpdateHandle(WeakHandle<()>);
1796impl WeakOnUpdateHandle {
1797 pub fn new() -> Self {
1799 Self(WeakHandle::new())
1800 }
1801
1802 pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1804 self.0.upgrade().map(OnUpdateHandle)
1805 }
1806}
1807
1808#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1810pub enum UpdateOp {
1811 Update,
1819 Info,
1828 Layout,
1836 Render,
1844 RenderUpdate,
1855}
1856
1857#[derive(Debug, Clone, Copy)]
1859#[non_exhaustive]
1860pub struct UpdateArgs {
1861 pub count: usize,
1863}
1864
1865struct UpdateHandler {
1866 handle: HandleOwner<()>,
1867 count: usize,
1868 handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1869}