zng_app/
update.rs

1//! App updates API.
2
3use 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
30/// Represents all the widgets and windows marked to receive an update.
31pub 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    /// New list that only allows `subscribers`.
55    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    /// New list that does not allow any entry.
66    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    /// New list that allows all entries.
80    ///
81    /// This is the default value.
82    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    /// Insert the `wgt` and ancestors up-to the inner most that is included in the subscribers.
101    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    /// Insert the window by itself, the window root widget will be targeted.
115    pub fn insert_window(&mut self, id: WindowId) {
116        self.windows.insert(id);
117        self.search_root = true;
118    }
119
120    /// Register all subscribers for search and delivery.
121    pub fn search_all(&mut self) {
122        self.search = self.subscribers.to_set();
123    }
124
125    /// Register the widget of unknown location for search before delivery routing starts.
126    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    /// If the list has pending widgets that must be found before delivery can start.
133    pub fn has_pending_search(&mut self) -> bool {
134        self.search_root || !self.search.is_empty()
135    }
136
137    /// Search all pending widgets in all `windows`, all search items are cleared, even if not found.
138    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    /// Copy windows, widgets and search from `other`, trusting that all values are allowed.
161    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    /// Returns `true` if the window is on the list.
182    pub fn enter_window(&self, window_id: WindowId) -> bool {
183        self.windows.contains(&window_id)
184    }
185
186    /// Returns `true` if the widget is on the list.
187    pub fn enter_widget(&self, widget_id: WidgetId) -> bool {
188        self.widgets.contains(&widget_id)
189    }
190
191    /// Windows in the delivery list.
192    pub fn windows(&self) -> &IdSet<WindowId> {
193        &self.windows
194    }
195
196    /// Found widgets in the delivery list, can be targets or ancestors of targets.
197    pub fn widgets(&self) -> &IdSet<WidgetId> {
198        &self.widgets
199    }
200
201    /// Widgets still pending search or not found.
202    #[must_use = "use `search_all` to request search"]
203    pub fn search_widgets(&mut self) -> &IdSet<WidgetId> {
204        &self.search
205    }
206
207    /// If search for window a root is pending.
208    #[must_use = "use `search_widget` to request search"]
209    pub fn search_root(&mut self) -> bool {
210        self.search_root
211    }
212}
213
214/// Provides an iterator of widget IDs and a window ID.
215pub trait WidgetPathProvider {
216    /// Output of `widget_and_ancestors`.
217    type WidgetIter<'s>: Iterator<Item = WidgetId>
218    where
219        Self: 's;
220
221    /// The window parent.
222    fn window_id(&self) -> WindowId;
223    /// Iterate over the widget, parent, grandparent, .., root.
224    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
263/// Represents a set of widgets that subscribe to an event source.
264pub trait UpdateSubscribers: Send + Sync + 'static {
265    /// Returns `true` if the widget is one of the subscribers.
266    fn contains(&self, widget_id: WidgetId) -> bool;
267    /// Gets all subscribers as a set.
268    fn to_set(&self) -> IdSet<WidgetId>;
269}
270
271/// Represents a single event update.
272pub struct EventUpdate {
273    pub(crate) event: AnyEvent,
274    pub(crate) args: Box<dyn AnyEventArgs>,
275    pub(crate) delivery_list: UpdateDeliveryList,
276    // never locked, only used to get `Sync`.
277    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    /// The event.
282    pub fn event(&self) -> AnyEvent {
283        self.event
284    }
285
286    /// The update delivery list.
287    pub fn delivery_list(&self) -> &UpdateDeliveryList {
288        &self.delivery_list
289    }
290
291    /// Mutable reference to the update delivery list.
292    ///
293    /// Note that this is only available app-extensions, nodes don't get mutable access to the event update.
294    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
295        &mut self.delivery_list
296    }
297
298    /// The update args.
299    pub fn args(&self) -> &dyn AnyEventArgs {
300        &*self.args
301    }
302
303    /// Calls `handle` if the event targets the [`WINDOW`].
304    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    /// Calls `handle` if the event targets the [`WIDGET`] and propagation is not stopped.
316    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    /// Create an event update for the same event and args, but with a custom `delivery_list`.
332    ///
333    /// Note that the returned instance can only be used to notify app extensions or nodes that the caller can reference.
334    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/// Widget info updates of the current cycle.
379#[derive(Debug, Default)]
380pub struct InfoUpdates {
381    delivery_list: UpdateDeliveryList,
382}
383impl InfoUpdates {
384    /// New with list.
385    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
386        Self { delivery_list }
387    }
388
389    /// Request delivery list.
390    pub fn delivery_list(&self) -> &UpdateDeliveryList {
391        &self.delivery_list
392    }
393
394    /// Request delivery list.
395    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
396        &mut self.delivery_list
397    }
398
399    /// Calls `handle` if info rebuild was requested for the window.
400    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    /// Copy all delivery from `other` onto `self`.
412    pub fn extend(&mut self, other: InfoUpdates) {
413        self.delivery_list.extend_unchecked(other.delivery_list)
414    }
415}
416
417/// Widget updates of the current cycle.
418#[derive(Debug, Default)]
419pub struct WidgetUpdates {
420    pub(crate) delivery_list: UpdateDeliveryList,
421}
422impl WidgetUpdates {
423    /// New with list.
424    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
425        Self { delivery_list }
426    }
427
428    /// Updates delivery list.
429    pub fn delivery_list(&self) -> &UpdateDeliveryList {
430        &self.delivery_list
431    }
432
433    /// Updates delivery list.
434    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
435        &mut self.delivery_list
436    }
437
438    /// Calls `handle` if update was requested for the [`WINDOW`].
439    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    /// Calls `handle` if update was requested for the [`WIDGET`].
451    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    /// Copy all delivery from `other` onto `self`.
463    pub fn extend(&mut self, other: WidgetUpdates) {
464        self.delivery_list.extend_unchecked(other.delivery_list)
465    }
466}
467
468/// Widget layout updates of the current cycle.
469#[derive(Debug, Default)]
470pub struct LayoutUpdates {
471    pub(crate) delivery_list: UpdateDeliveryList,
472}
473impl LayoutUpdates {
474    /// New with list.
475    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
476        Self { delivery_list }
477    }
478
479    /// Request delivery list.
480    pub fn delivery_list(&self) -> &UpdateDeliveryList {
481        &self.delivery_list
482    }
483
484    /// Request delivery list.
485    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
486        &mut self.delivery_list
487    }
488
489    /// Calls `handle` if layout rebuild was requested for the window.
490    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    /// Copy all delivery from `other` onto `self`.
502    pub fn extend(&mut self, other: LayoutUpdates) {
503        self.delivery_list.extend_unchecked(other.delivery_list)
504    }
505}
506
507/// Widget render updates of the current cycle.
508#[derive(Debug, Default)]
509pub struct RenderUpdates {
510    delivery_list: UpdateDeliveryList,
511}
512impl RenderUpdates {
513    /// New with list.
514    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
515        Self { delivery_list }
516    }
517
518    /// Request delivery list.
519    pub fn delivery_list(&self) -> &UpdateDeliveryList {
520        &self.delivery_list
521    }
522
523    /// Request delivery list.
524    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
525        &mut self.delivery_list
526    }
527
528    /// Calls `handle` if render frame rebuild or update was requested for the window.
529    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    /// Copy all delivery from `other` onto `self`.
541    pub fn extend(&mut self, other: RenderUpdates) {
542        self.delivery_list.extend_unchecked(other.delivery_list)
543    }
544}
545
546/// Extension methods for infinite loop diagnostics.
547///
548/// You can also use [`updates_trace_span`] and [`updates_trace_event`] to define custom scopes and entries.
549pub trait UpdatesTraceUiNodeExt {
550    /// Defines a custom span.
551    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
562/// Custom span in the app loop diagnostics.
563///
564/// See [`UpdatesTraceUiNodeExt`] for more details.
565pub fn updates_trace_span(tag: &'static str) -> tracing::span::EnteredSpan {
566    UpdatesTrace::custom_span(tag, "")
567}
568
569/// Custom log entry in the app loop diagnostics.
570///
571/// See [`UpdatesTraceUiNodeExt`] for more details.
572pub 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        // if ctx.app_extension.is_none() {
692        //     return;
693        // }
694
695        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    /// If updates trace is currently collecting.
736    #[inline(always)]
737    pub fn is_tracing() -> bool {
738        UPDATES_TRACE_ENABLED.load(atomic::Ordering::Relaxed)
739    }
740
741    /// Opens an app extension span.
742    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    /// Opens a window span.
751    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    /// Opens a widget span.
760    #[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    /// Opens a property span.
770    #[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    /// Opens an intrinsic span.
780    #[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    /// Opens a custom named span.
790    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    /// Log a direct update request.
799    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    /// Log a direct info rebuild request.
808    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    /// Log a direct layout request.
817    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    /// Log a direct render request.
826    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    /// Log a custom event.
835    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    /// Log a var update request.
846    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    /// Log an event update request.
857    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    /// Run `action` collecting a trace of what caused updates.
868    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    /// Displays the top 20 most frequent update sources in the trace.
882    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
1018/// Update schedule service.
1019pub 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    /// Returns next timer or animation tick time.
1096    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    /// Update timers and animations, returns next wake time.
1102    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    /// If a call to `apply_updates` will generate updates (ignoring timers).
1108    #[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    /// Create an [`AppEventSender`] that can be used to awake the app and send app events from threads outside of the app.
1125    pub fn sender(&self) -> AppEventSender {
1126        UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
1127    }
1128
1129    /// Create an std task waker that wakes the event loop and updates.
1130    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    /// Schedules an [`UpdateOp`] that optionally affects the `target` widget.
1188    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    /// Schedules an [`UpdateOp`] for the window only.
1200    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    /// Schedules an update that affects the `target`.
1211    ///
1212    /// After the current update cycle ends a new update will happen that includes the `target` widget.
1213    pub fn update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1214        UpdatesTrace::log_update();
1215        self.update_internal(target.into())
1216    }
1217    /// Implements `update` without `log_update`.
1218    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    /// Schedules an update for the window only.
1229    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    /// Schedules an info rebuild that affects the `target`.
1242    ///
1243    /// After the current update cycle ends a new update will happen that requests an info rebuild that includes the `target` widget.
1244    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    /// Schedules an info rebuild for the window only.
1256    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    /// Schedules a layout update that affects the `target`.
1266    ///
1267    /// After the current update cycle ends and there are no more updates requested a layout pass is issued that includes the `target` widget.
1268    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    /// Schedules a layout update for the window only.
1280    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    /// Schedules a full render that affects the `target`.
1290    ///
1291    /// After the current update cycle ends and there are no more updates or layouts requested a render pass is issued that
1292    /// includes the `target` widget.
1293    ///
1294    /// If no `target` is provided only the app extensions receive a render request.
1295    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    /// Schedules a new frame for the window only.
1307    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    /// Schedules a render update that affects the `target`.
1317    ///
1318    /// After the current update cycle ends and there are no more updates or layouts requested a render pass is issued that
1319    /// includes the `target` widget marked for render update only. Note that if a full render was requested for another widget
1320    /// on the same window this request is upgraded to a full frame render.
1321    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    /// Schedules a render update for the window only.
1333    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    /// Returns `true` is render or render update is requested for the window.
1343    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    /// Schedule the `future` to run in the app context, in the *preview* track of the next update.
1349    ///
1350    /// This requests an app update. Each future awake also requests an app update and also runs in the *preview* track.
1351    ///
1352    /// Returns a handle that can be dropped to cancel execution.
1353    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    /// Schedule a handler to run once in the app context, in the *preview* track of the next update.
1359    ///
1360    /// The [`Handler`] can be any kind, including async handlers. If the handler is async and does not finish in
1361    /// one call it is scheduled to update in *preview* updates.
1362    ///
1363    /// Returns a handle that can be dropped to cancel execution.
1364    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    /// Create a preview update handler.
1372    ///
1373    /// The `handler` is called every time the app updates, just before the UI updates. It can be any of the non-async [`Handler`],
1374    /// use the [`hn!`] or [`hn_once!`] macros to declare the closure. You must avoid using async handlers because UI bound async
1375    /// tasks cause app updates to awake, so it is very easy to lock the app in a constant sequence of updates. You can use [`run`](Self::run)
1376    /// to start an async app context task.
1377    ///
1378    /// Returns an [`OnUpdateHandle`] that can be used to unsubscribe, you can also unsubscribe from inside the handler by calling
1379    /// [`APP_HANDLER.unsubscribe`].
1380    ///
1381    /// [`hn_once!`]: macro@crate::handler::hn_once
1382    /// [`hn!`]: macro@crate::handler::hn
1383    /// [`async_hn!`]: macro@crate::handler::async_hn
1384    /// [`APP_HANDLER.unsubscribe`]: crate::handler::APP_HANDLER::unsubscribe
1385    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    /// Create an update handler.
1391    ///
1392    /// The `handler` is called every time the app updates, just after the UI updates. It can be any of the non-async [`Handler`],
1393    /// use the [`hn!`] or [`hn_once!`] macros to declare the closure. You must avoid using async handlers because UI bound async
1394    /// tasks cause app updates to awake, so it is very easy to lock the app in a constant sequence of updates. You can use [`run`](Self::run)
1395    /// to start an async app context task.
1396    ///
1397    /// Returns an [`OnUpdateHandle`] that can be used to unsubscribe, you can also unsubscribe from inside the handler by calling
1398    /// [`APP_HANDLER.unsubscribe`].
1399    ///
1400    /// [`hn_once!`]: macro@crate::handler::hn_once
1401    /// [`hn!`]: macro@crate::handler::hn
1402    /// [`async_hn!`]: macro@crate::handler::async_hn
1403    /// [`APP_HANDLER.unsubscribe`]: crate::handler::APP_HANDLER::unsubscribe
1404    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    /// Returns (update_ext, update_widgets)
1460    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    /// Returns (info_ext, info_widgets)
1475    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    /// Returns (layout_ext, layout_widgets)
1490    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    /// Returns (render_ext, render_widgets, render_update_widgets)
1505    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/// Updates that must be reacted by an app owner.
1605///
1606/// This type is public only for testing, it is the return type for test methods of [`WINDOW`].
1607#[non_exhaustive]
1608#[derive(Default)]
1609pub struct ContextUpdates {
1610    /// Events to notify.
1611    ///
1612    /// When this is not empty [`update`](Self::update) is `true`.
1613    pub events: Vec<EventUpdate>,
1614
1615    /// Update requested.
1616    ///
1617    /// When this is `true`, [`update_widgets`](Self::update_widgets)
1618    /// may contain widgets, if not then only app extensions must update.
1619    pub update: bool,
1620
1621    /// Info rebuild requested.
1622    ///
1623    /// When this is `true`, [`info_widgets`](Self::info_widgets)
1624    /// may contain widgets, if not then only app extensions must update.
1625    pub info: bool,
1626
1627    /// Layout requested.
1628    ///
1629    /// When this is `true`, [`layout_widgets`](Self::layout_widgets)
1630    /// may contain widgets, if not then only app extensions must update.
1631    pub layout: bool,
1632
1633    /// Render requested.
1634    ///
1635    /// When this is `true`, [`render_widgets`](Self::render_widgets) or [`render_update_widgets`](Self::render_update_widgets)
1636    /// may contain widgets, if not then only app extensions must update.
1637    pub render: bool,
1638
1639    /// Update targets.
1640    ///
1641    /// When this is not empty [`update`](Self::update) is `true`.
1642    pub update_widgets: WidgetUpdates,
1643
1644    /// Info rebuild targets.
1645    ///
1646    /// When this is not empty [`info`](Self::info) is `true`.
1647    pub info_widgets: InfoUpdates,
1648
1649    /// Layout targets.
1650    ///
1651    /// When this is not empty [`layout`](Self::layout) is `true`.
1652    pub layout_widgets: LayoutUpdates,
1653
1654    /// Full render targets.
1655    ///
1656    /// When this is not empty [`render`](Self::render) is `true`.
1657    pub render_widgets: RenderUpdates,
1658
1659    /// Render update targets.
1660    ///
1661    /// When this is not empty [`render`](Self::render) is `true`.
1662    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    /// If has events, update, layout or render was requested.
1716    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/// Represents an [`on_pre_update`](UPDATES::on_pre_update) or [`on_update`](UPDATES::on_update) handler.
1757///
1758/// Drop all clones of this handle to drop the binding, or call [`perm`](Self::perm) to drop the handle
1759/// but keep the handler alive for the duration of the app.
1760#[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    /// Create a handle to nothing, the handle always in the *unsubscribed* state.
1771    ///
1772    /// Note that `Option<OnUpdateHandle>` takes up the same space as `OnUpdateHandle` and avoids an allocation.
1773    pub fn dummy() -> Self {
1774        OnUpdateHandle(Handle::dummy(()))
1775    }
1776
1777    /// Drops the handle but does **not** unsubscribe.
1778    ///
1779    /// The handler stays in memory for the duration of the app or until another handle calls [`unsubscribe`](Self::unsubscribe)
1780    pub fn perm(self) {
1781        self.0.perm();
1782    }
1783
1784    /// If another handle has called [`perm`](Self::perm).
1785    ///
1786    /// If `true` the handler will stay active until the app exits, unless [`unsubscribe`](Self::unsubscribe) is called.
1787    pub fn is_permanent(&self) -> bool {
1788        self.0.is_permanent()
1789    }
1790
1791    /// Drops the handle and forces the handler to drop.
1792    pub fn unsubscribe(self) {
1793        self.0.force_drop()
1794    }
1795
1796    /// If another handle has called [`unsubscribe`](Self::unsubscribe).
1797    ///
1798    /// The handler is already dropped or will be dropped in the next app update, this is irreversible.
1799    pub fn is_unsubscribed(&self) -> bool {
1800        self.0.is_dropped()
1801    }
1802
1803    /// Create a weak handle.
1804    pub fn downgrade(&self) -> WeakOnUpdateHandle {
1805        WeakOnUpdateHandle(self.0.downgrade())
1806    }
1807}
1808
1809/// Weak [`OnUpdateHandle`].
1810#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1811pub struct WeakOnUpdateHandle(WeakHandle<()>);
1812impl WeakOnUpdateHandle {
1813    /// New weak handle that does not upgrade.
1814    pub fn new() -> Self {
1815        Self(WeakHandle::new())
1816    }
1817
1818    /// Gets the strong handle if it is still subscribed.
1819    pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1820        self.0.upgrade().map(OnUpdateHandle)
1821    }
1822}
1823
1824/// Identify node and app-extension operations that can be requested.
1825#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1826pub enum UpdateOp {
1827    /// Updates the target.
1828    ///
1829    /// Causes [`AppExtension::update_preview`], [`AppExtension::update_ui`] and [`AppExtension::update`].
1830    ///
1831    /// Causes [`UiNode::update`] or [`UiNodeOp::Update`] for the target widget and all ancestors.
1832    ///
1833    /// [`UiNodeOp::Update`]: crate::widget::node::UiNodeOp::Update
1834    Update,
1835    /// Rebuilds info for the target.
1836    ///
1837    /// Causes [`AppExtension::info`].
1838    ///
1839    /// Causes [`UiNode::info`] or [`UiNodeOp::Info`] for the target widget and all ancestors.
1840    ///
1841    /// [`Update`]: UpdateOp::Render
1842    /// [`UiNodeOp::Info`]: crate::widget::node::UiNodeOp::Info
1843    Info,
1844    /// Layouts the target.
1845    ///
1846    /// Causes [`AppExtension::layout`].
1847    ///
1848    /// Causes an [`UiNode::layout`] or [`UiNodeOp::Layout`] for the target widget and all ancestors.
1849    ///
1850    /// [`UiNodeOp::Layout`]: crate::widget::node::UiNodeOp::Layout
1851    Layout,
1852    /// Render the target.
1853    ///
1854    /// Causes [`AppExtension::render`].
1855    ///
1856    /// Causes [`UiNode::render`] or [`UiNodeOp::Render`] for the target widget and all ancestors.
1857    ///
1858    /// [`UiNodeOp::Render`]: crate::widget::node::UiNodeOp::Render
1859    Render,
1860    /// Update frame bindings of the target.
1861    ///
1862    /// Causes [`AppExtension::render`].
1863    ///
1864    /// Causes [`UiNode::render_update`] or [`UiNodeOp::RenderUpdate`] for the target widget and all ancestors.
1865    ///
1866    /// This OP is upgraded to [`Render`] if any other widget requests a full render in the same window.
1867    ///
1868    /// [`Render`]: UpdateOp::Render
1869    /// [`UiNodeOp::RenderUpdate`]: crate::widget::node::UiNodeOp::RenderUpdate
1870    RenderUpdate,
1871}
1872
1873/// Arguments for an [`on_pre_update`](UPDATES::on_pre_update), [`on_update`](UPDATES::on_update) or [`run`](UPDATES::run) handler.
1874#[derive(Debug, Clone, Copy)]
1875#[non_exhaustive]
1876pub struct UpdateArgs {
1877    /// Number of times the handler was called.
1878    pub count: usize,
1879}
1880
1881struct UpdateHandler {
1882    handle: HandleOwner<()>,
1883    count: usize,
1884    handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1885}