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