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_unique_id::IdSet;
14use zng_var::VARS_APP;
15
16use crate::{
17    AppChannelError, AppEventSender, AppExtension, LoopTimer, async_hn_once,
18    event::{AnyEvent, AnyEventArgs, EVENTS, EVENTS_SV},
19    handler::{AppWeakHandle, Handler, HandlerExt as _},
20    timer::TIMERS_SV,
21    widget::{
22        WIDGET, WidgetId,
23        info::{InteractionPath, WidgetInfo, WidgetInfoTree, WidgetPath},
24        node::UiNode,
25    },
26    window::{WINDOW, WindowId},
27};
28
29/// Represents all the widgets and windows marked to receive an update.
30pub struct UpdateDeliveryList {
31    subscribers: Box<dyn UpdateSubscribers>,
32
33    windows: IdSet<WindowId>,
34    widgets: IdSet<WidgetId>,
35    search: IdSet<WidgetId>,
36    search_root: bool,
37}
38impl fmt::Debug for UpdateDeliveryList {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        f.debug_struct("UpdateDeliveryList")
41            .field("windows", &self.windows)
42            .field("widgets", &self.widgets)
43            .field("search", &self.search)
44            .finish_non_exhaustive()
45    }
46}
47impl Default for UpdateDeliveryList {
48    fn default() -> Self {
49        Self::new_any()
50    }
51}
52impl UpdateDeliveryList {
53    /// New list that only allows `subscribers`.
54    pub fn new(subscribers: Box<dyn UpdateSubscribers>) -> Self {
55        Self {
56            subscribers,
57            windows: IdSet::default(),
58            widgets: IdSet::default(),
59            search: IdSet::default(),
60            search_root: false,
61        }
62    }
63
64    /// New list that does not allow any entry.
65    pub fn new_none() -> Self {
66        struct UpdateDeliveryListNone;
67        impl UpdateSubscribers for UpdateDeliveryListNone {
68            fn contains(&self, _: WidgetId) -> bool {
69                false
70            }
71            fn to_set(&self) -> IdSet<WidgetId> {
72                IdSet::default()
73            }
74        }
75        Self::new(Box::new(UpdateDeliveryListNone))
76    }
77
78    /// New list that allows all entries.
79    ///
80    /// This is the default value.
81    pub fn new_any() -> Self {
82        struct UpdateDeliveryListAny;
83        impl UpdateSubscribers for UpdateDeliveryListAny {
84            fn contains(&self, _: WidgetId) -> bool {
85                true
86            }
87            fn to_set(&self) -> IdSet<WidgetId> {
88                IdSet::default()
89            }
90        }
91        Self::new(Box::new(UpdateDeliveryListAny))
92    }
93
94    pub(crate) fn insert_updates_root(&mut self, window_id: WindowId, root_id: WidgetId) {
95        self.windows.insert(window_id);
96        self.widgets.insert(root_id);
97    }
98
99    /// Insert the `wgt` and ancestors up-to the inner most that is included in the subscribers.
100    pub fn insert_wgt(&mut self, wgt: &impl WidgetPathProvider) {
101        let mut any = false;
102        for w in wgt.widget_and_ancestors() {
103            if any || self.subscribers.contains(w) {
104                any = true;
105                self.widgets.insert(w);
106            }
107        }
108        if any {
109            self.windows.insert(wgt.window_id());
110        }
111    }
112
113    /// Insert the window by itself, the window root widget will be targeted.
114    pub fn insert_window(&mut self, id: WindowId) {
115        self.windows.insert(id);
116        self.search_root = true;
117    }
118
119    /// Register all subscribers for search and delivery.
120    pub fn search_all(&mut self) {
121        self.search = self.subscribers.to_set();
122    }
123
124    /// Register the widget of unknown location for search before delivery routing starts.
125    pub fn search_widget(&mut self, widget_id: WidgetId) {
126        if self.subscribers.contains(widget_id) {
127            self.search.insert(widget_id);
128        }
129    }
130
131    /// If the list has pending widgets that must be found before delivery can start.
132    pub fn has_pending_search(&mut self) -> bool {
133        self.search_root || !self.search.is_empty()
134    }
135
136    /// Search all pending widgets in all `windows`, all search items are cleared, even if not found.
137    pub fn fulfill_search<'a, 'b>(&'a mut self, windows: impl Iterator<Item = &'b WidgetInfoTree>) {
138        for window in windows {
139            if self.search_root && self.windows.contains(&window.window_id()) {
140                self.widgets.insert(window.root().id());
141            }
142
143            self.search.retain(|w| {
144                if let Some(w) = window.get(*w) {
145                    for w in w.widget_and_ancestors() {
146                        self.widgets.insert(w);
147                    }
148                    self.windows.insert(w.window_id());
149                    false
150                } else {
151                    true
152                }
153            });
154        }
155        self.search.clear();
156        self.search_root = true;
157    }
158
159    /// Copy windows, widgets and search from `other`, trusting that all values are allowed.
160    fn extend_unchecked(&mut self, other: UpdateDeliveryList) {
161        if self.windows.is_empty() {
162            self.windows = other.windows;
163        } else {
164            self.windows.extend(other.windows);
165        }
166
167        if self.widgets.is_empty() {
168            self.widgets = other.widgets;
169        } else {
170            self.widgets.extend(other.widgets);
171        }
172
173        if self.search.is_empty() {
174            self.search = other.search;
175        } else {
176            self.search.extend(other.search);
177        }
178    }
179
180    /// Returns `true` if the window is on the list.
181    pub fn enter_window(&self, window_id: WindowId) -> bool {
182        self.windows.contains(&window_id)
183    }
184
185    /// Returns `true` if the widget is on the list.
186    pub fn enter_widget(&self, widget_id: WidgetId) -> bool {
187        self.widgets.contains(&widget_id)
188    }
189
190    /// Windows in the delivery list.
191    pub fn windows(&self) -> &IdSet<WindowId> {
192        &self.windows
193    }
194
195    /// Found widgets in the delivery list, can be targets or ancestors of targets.
196    pub fn widgets(&self) -> &IdSet<WidgetId> {
197        &self.widgets
198    }
199
200    /// Widgets still pending search or not found.
201    #[must_use = "use `search_all` to request search"]
202    pub fn search_widgets(&mut self) -> &IdSet<WidgetId> {
203        &self.search
204    }
205
206    /// If search for window a root is pending.
207    #[must_use = "use `search_widget` to request search"]
208    pub fn search_root(&mut self) -> bool {
209        self.search_root
210    }
211}
212
213/// Provides an iterator of widget IDs and a window ID.
214pub trait WidgetPathProvider {
215    /// Output of `widget_and_ancestors`.
216    type WidgetIter<'s>: Iterator<Item = WidgetId>
217    where
218        Self: 's;
219
220    /// The window parent.
221    fn window_id(&self) -> WindowId;
222    /// Iterate over the widget, parent, grandparent, .., root.
223    fn widget_and_ancestors(&self) -> Self::WidgetIter<'_>;
224}
225impl WidgetPathProvider for WidgetInfo {
226    type WidgetIter<'s> = std::iter::Map<crate::widget::info::iter::Ancestors, fn(WidgetInfo) -> WidgetId>;
227
228    fn window_id(&self) -> WindowId {
229        self.tree().window_id()
230    }
231
232    fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
233        fn wgt_to_id(wgt: WidgetInfo) -> WidgetId {
234            wgt.id()
235        }
236        self.self_and_ancestors().map(wgt_to_id)
237    }
238}
239impl WidgetPathProvider for WidgetPath {
240    type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
241
242    fn window_id(&self) -> WindowId {
243        self.window_id()
244    }
245
246    fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
247        self.widgets_path().iter().copied().rev()
248    }
249}
250impl WidgetPathProvider for InteractionPath {
251    type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
252
253    fn window_id(&self) -> WindowId {
254        WidgetPath::window_id(self)
255    }
256
257    fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
258        self.widgets_path().iter().copied().rev()
259    }
260}
261
262/// Represents a set of widgets that subscribe to an event source.
263pub trait UpdateSubscribers: Send + Sync + 'static {
264    /// Returns `true` if the widget is one of the subscribers.
265    fn contains(&self, widget_id: WidgetId) -> bool;
266    /// Gets all subscribers as a set.
267    fn to_set(&self) -> IdSet<WidgetId>;
268}
269
270/// Represents a single event update.
271pub struct EventUpdate {
272    pub(crate) event: AnyEvent,
273    pub(crate) args: Box<dyn AnyEventArgs>,
274    pub(crate) delivery_list: UpdateDeliveryList,
275    // never locked, only used to get `Sync`.
276    pub(crate) pre_actions: Mutex<Vec<Box<dyn FnOnce(&EventUpdate) + Send>>>,
277    pub(crate) pos_actions: Mutex<Vec<Box<dyn FnOnce(&EventUpdate) + Send>>>,
278}
279impl EventUpdate {
280    /// The event.
281    pub fn event(&self) -> AnyEvent {
282        self.event
283    }
284
285    /// The update delivery list.
286    pub fn delivery_list(&self) -> &UpdateDeliveryList {
287        &self.delivery_list
288    }
289
290    /// Mutable reference to the update delivery list.
291    ///
292    /// Note that this is only available app-extensions, nodes don't get mutable access to the event update.
293    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
294        &mut self.delivery_list
295    }
296
297    /// The update args.
298    pub fn args(&self) -> &dyn AnyEventArgs {
299        &*self.args
300    }
301
302    /// Calls `handle` if the event targets the [`WINDOW`].
303    pub fn with_window<H, R>(&self, handle: H) -> Option<R>
304    where
305        H: FnOnce() -> R,
306    {
307        if self.delivery_list.enter_window(WINDOW.id()) {
308            Some(handle())
309        } else {
310            None
311        }
312    }
313
314    /// Calls `handle` if the event targets the [`WIDGET`] and propagation is not stopped.
315    pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
316    where
317        H: FnOnce() -> R,
318    {
319        if self.delivery_list.enter_widget(WIDGET.id()) {
320            if self.args.propagation().is_stopped() {
321                None
322            } else {
323                Some(handle())
324            }
325        } else {
326            None
327        }
328    }
329
330    /// Create an event update for the same event and args, but with a custom `delivery_list`.
331    ///
332    /// Note that the returned instance can only be used to notify app extensions or nodes that the caller can reference.
333    pub fn custom(&self, delivery_list: UpdateDeliveryList) -> Self {
334        Self {
335            event: self.event,
336            args: self.args.clone_any(),
337            delivery_list,
338            pre_actions: Mutex::new(vec![]),
339            pos_actions: Mutex::new(vec![]),
340        }
341    }
342
343    pub(crate) fn push_once_action(&mut self, action: Box<dyn FnOnce(&EventUpdate) + Send>, is_preview: bool) {
344        if is_preview {
345            self.pre_actions.get_mut().push(action);
346        } else {
347            self.pos_actions.get_mut().push(action);
348        }
349    }
350
351    pub(crate) fn call_pre_actions(&mut self) {
352        let _s = tracing::trace_span!("call_pre_actions");
353        let actions = mem::take(self.pre_actions.get_mut());
354        for action in actions {
355            action(self)
356        }
357    }
358
359    pub(crate) fn call_pos_actions(&mut self) {
360        let _s = tracing::trace_span!("call_pos_actions");
361        let actions = mem::take(self.pos_actions.get_mut());
362        for action in actions {
363            action(self)
364        }
365    }
366}
367impl fmt::Debug for EventUpdate {
368    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369        f.debug_struct("EventUpdate")
370            .field("event", &self.event)
371            .field("args", &self.args)
372            .field("delivery_list", &self.delivery_list)
373            .finish_non_exhaustive()
374    }
375}
376
377/// Widget info updates of the current cycle.
378#[derive(Debug, Default)]
379pub struct InfoUpdates {
380    delivery_list: UpdateDeliveryList,
381}
382impl InfoUpdates {
383    /// New with list.
384    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
385        Self { delivery_list }
386    }
387
388    /// Request delivery list.
389    pub fn delivery_list(&self) -> &UpdateDeliveryList {
390        &self.delivery_list
391    }
392
393    /// Request delivery list.
394    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
395        &mut self.delivery_list
396    }
397
398    /// Calls `handle` if info rebuild was requested for the window.
399    pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
400    where
401        H: FnOnce() -> R,
402    {
403        if self.delivery_list.enter_window(window_id) {
404            Some(handle())
405        } else {
406            None
407        }
408    }
409
410    /// Copy all delivery from `other` onto `self`.
411    pub fn extend(&mut self, other: InfoUpdates) {
412        self.delivery_list.extend_unchecked(other.delivery_list)
413    }
414}
415
416/// Widget updates of the current cycle.
417#[derive(Debug, Default)]
418pub struct WidgetUpdates {
419    pub(crate) delivery_list: UpdateDeliveryList,
420}
421impl WidgetUpdates {
422    /// New with list.
423    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
424        Self { delivery_list }
425    }
426
427    /// Updates delivery list.
428    pub fn delivery_list(&self) -> &UpdateDeliveryList {
429        &self.delivery_list
430    }
431
432    /// Updates delivery list.
433    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
434        &mut self.delivery_list
435    }
436
437    /// Calls `handle` if update was requested for the [`WINDOW`].
438    pub fn with_window<H, R>(&self, handle: H) -> Option<R>
439    where
440        H: FnOnce() -> R,
441    {
442        if self.delivery_list.enter_window(WINDOW.id()) {
443            Some(handle())
444        } else {
445            None
446        }
447    }
448
449    /// Calls `handle` if update was requested for the [`WIDGET`].
450    pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
451    where
452        H: FnOnce() -> R,
453    {
454        if WIDGET.take_update(UpdateFlags::UPDATE) || self.delivery_list.enter_widget(WIDGET.id()) {
455            Some(handle())
456        } else {
457            None
458        }
459    }
460
461    /// Copy all delivery from `other` onto `self`.
462    pub fn extend(&mut self, other: WidgetUpdates) {
463        self.delivery_list.extend_unchecked(other.delivery_list)
464    }
465}
466
467/// Widget layout updates of the current cycle.
468#[derive(Debug, Default)]
469pub struct LayoutUpdates {
470    pub(crate) delivery_list: UpdateDeliveryList,
471}
472impl LayoutUpdates {
473    /// New with list.
474    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
475        Self { delivery_list }
476    }
477
478    /// Request delivery list.
479    pub fn delivery_list(&self) -> &UpdateDeliveryList {
480        &self.delivery_list
481    }
482
483    /// Request delivery list.
484    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
485        &mut self.delivery_list
486    }
487
488    /// Calls `handle` if layout rebuild was requested for the window.
489    pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
490    where
491        H: FnOnce() -> R,
492    {
493        if self.delivery_list.enter_window(window_id) {
494            Some(handle())
495        } else {
496            None
497        }
498    }
499
500    /// Copy all delivery from `other` onto `self`.
501    pub fn extend(&mut self, other: LayoutUpdates) {
502        self.delivery_list.extend_unchecked(other.delivery_list)
503    }
504}
505
506/// Widget render updates of the current cycle.
507#[derive(Debug, Default)]
508pub struct RenderUpdates {
509    delivery_list: UpdateDeliveryList,
510}
511impl RenderUpdates {
512    /// New with list.
513    pub fn new(delivery_list: UpdateDeliveryList) -> Self {
514        Self { delivery_list }
515    }
516
517    /// Request delivery list.
518    pub fn delivery_list(&self) -> &UpdateDeliveryList {
519        &self.delivery_list
520    }
521
522    /// Request delivery list.
523    pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
524        &mut self.delivery_list
525    }
526
527    /// Calls `handle` if render frame rebuild or update was requested for the window.
528    pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
529    where
530        H: FnOnce() -> R,
531    {
532        if self.delivery_list.enter_window(window_id) {
533            Some(handle())
534        } else {
535            None
536        }
537    }
538
539    /// Copy all delivery from `other` onto `self`.
540    pub fn extend(&mut self, other: RenderUpdates) {
541        self.delivery_list.extend_unchecked(other.delivery_list)
542    }
543}
544
545/// Extension methods for infinite loop diagnostics.
546///
547/// You can also use [`updates_trace_span`] and [`updates_trace_event`] to define custom scopes and entries.
548pub trait UpdatesTraceUiNodeExt {
549    /// Defines a custom span.
550    fn instrument<S: Into<String>>(self, tag: S) -> UiNode
551    where
552        Self: Sized;
553}
554impl UpdatesTraceUiNodeExt for UiNode {
555    fn instrument<S: Into<String>>(self, tag: S) -> UiNode {
556        let tag = tag.into();
557        self.trace(move |op| UpdatesTrace::custom_span(&tag, op.mtd_name()))
558    }
559}
560
561/// Custom span in the app loop diagnostics.
562///
563/// See [`UpdatesTraceUiNodeExt`] for more details.
564pub fn updates_trace_span(tag: &'static str) -> tracing::span::EnteredSpan {
565    UpdatesTrace::custom_span(tag, "")
566}
567
568/// Custom log entry in the app loop diagnostics.
569///
570/// See [`UpdatesTraceUiNodeExt`] for more details.
571pub fn updates_trace_event(tag: &str) {
572    UpdatesTrace::log_custom(tag)
573}
574
575pub(crate) struct UpdatesTrace {
576    context: Mutex<UpdateContext>,
577    trace: Arc<Mutex<Vec<UpdateTrace>>>,
578
579    widgets_stack: Mutex<Vec<(WidgetId, String)>>,
580    node_parents_stack: Mutex<Vec<String>>,
581    tags_stack: Mutex<Vec<String>>,
582}
583impl tracing::subscriber::Subscriber for UpdatesTrace {
584    fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
585        metadata.target() == Self::UPDATES_TARGET
586    }
587
588    fn new_span(&self, span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
589        match span.metadata().name() {
590            "property" | "intrinsic" => {
591                let name = visit_str(|v| span.record(v), "name");
592                let mut ctx = self.context.lock();
593
594                if let Some(p) = ctx.node_parent.replace(name) {
595                    self.node_parents_stack.lock().push(p);
596                }
597                if let Some(p) = ctx.tag.replace(String::new()) {
598                    self.tags_stack.lock().push(p);
599                }
600
601                tracing::span::Id::from_u64(1)
602            }
603            "widget" => {
604                let id = visit_u64(|v| span.record(v), "raw_id").unwrap();
605                if id == 0 {
606                    panic!()
607                }
608                let id = WidgetId::from_raw(id);
609
610                let name = visit_str(|v| span.record(v), "name");
611
612                let mut ctx = self.context.lock();
613                if let Some(p) = ctx.widget.replace((id, name)) {
614                    self.widgets_stack.lock().push(p);
615                }
616
617                if let Some(p) = ctx.node_parent.replace(String::new()) {
618                    self.node_parents_stack.lock().push(p);
619                }
620
621                if let Some(p) = ctx.tag.replace(String::new()) {
622                    self.tags_stack.lock().push(p);
623                }
624
625                tracing::span::Id::from_u64(2)
626            }
627            "Window" => {
628                let id = visit_u64(|v| span.record(v), "raw_id").unwrap() as u32;
629                if id == 0 {
630                    panic!()
631                }
632                let id = WindowId::from_raw(id);
633
634                let mut ctx = self.context.lock();
635                ctx.window_id = Some(id);
636
637                if let Some(p) = ctx.tag.replace(String::new()) {
638                    self.tags_stack.lock().push(p);
639                }
640
641                tracing::span::Id::from_u64(3)
642            }
643            "AppExtension" => {
644                let name = visit_str(|v| span.record(v), "name");
645
646                let mut ctx = self.context.lock();
647                ctx.app_extension = Some(name);
648
649                if let Some(p) = ctx.tag.replace(String::new()) {
650                    self.tags_stack.lock().push(p);
651                }
652
653                tracing::span::Id::from_u64(4)
654            }
655            "tag" => {
656                let tag = visit_str(|v| span.record(v), "tag");
657                let mut ctx = self.context.lock();
658                if let Some(p) = ctx.tag.replace(tag) {
659                    self.tags_stack.lock().push(p);
660                }
661                tracing::span::Id::from_u64(5)
662            }
663            _ => tracing::span::Id::from_u64(u64::MAX),
664        }
665    }
666
667    fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
668
669    fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
670
671    fn event(&self, event: &tracing::Event<'_>) {
672        let action = match visit_str(|v| event.record(v), "kind").as_str() {
673            "var" => UpdateAction::Var {
674                type_name: visit_str(|v| event.record(v), "type_name"),
675            },
676            "event" => UpdateAction::Event {
677                type_name: visit_str(|v| event.record(v), "type_name"),
678            },
679            "request" => UpdateAction::Update,
680            "info" => UpdateAction::Info,
681            "layout" => UpdateAction::Layout,
682            "render" => UpdateAction::Render,
683            "custom" => UpdateAction::Custom {
684                tag: visit_str(|v| event.record(v), "tag"),
685            },
686            _ => return,
687        };
688
689        let ctx = self.context.lock().clone();
690        // if ctx.app_extension.is_none() {
691        //     return;
692        // }
693
694        let entry = UpdateTrace { ctx, action };
695        self.trace.lock().push(entry);
696    }
697
698    fn enter(&self, _span: &tracing::span::Id) {}
699
700    fn exit(&self, span: &tracing::span::Id) {
701        let mut ctx = self.context.lock();
702        if span == &tracing::span::Id::from_u64(1) {
703            ctx.node_parent = self.node_parents_stack.lock().pop();
704            ctx.tag = self.tags_stack.lock().pop();
705        } else if span == &tracing::span::Id::from_u64(2) {
706            ctx.widget = self.widgets_stack.lock().pop();
707            ctx.node_parent = self.node_parents_stack.lock().pop();
708            ctx.tag = self.tags_stack.lock().pop();
709        } else if span == &tracing::span::Id::from_u64(3) {
710            ctx.window_id = None;
711            ctx.tag = self.tags_stack.lock().pop();
712        } else if span == &tracing::span::Id::from_u64(4) {
713            ctx.app_extension = None;
714            ctx.tag = self.tags_stack.lock().pop();
715        } else if span == &tracing::span::Id::from_u64(5) {
716            ctx.tag = self.tags_stack.lock().pop();
717        }
718    }
719}
720static UPDATES_TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
721impl UpdatesTrace {
722    const UPDATES_TARGET: &'static str = "zng-updates";
723
724    fn new() -> Self {
725        UpdatesTrace {
726            context: Mutex::new(UpdateContext::default()),
727            trace: Arc::new(Mutex::new(Vec::with_capacity(100))),
728            widgets_stack: Mutex::new(Vec::with_capacity(100)),
729            node_parents_stack: Mutex::new(Vec::with_capacity(100)),
730            tags_stack: Mutex::new(Vec::new()),
731        }
732    }
733
734    /// If updates trace is currently collecting.
735    #[inline(always)]
736    pub fn is_tracing() -> bool {
737        UPDATES_TRACE_ENABLED.load(atomic::Ordering::Relaxed)
738    }
739
740    /// Opens an app extension span.
741    pub fn extension_span<E: AppExtension>(ext_mtd: &'static str) -> tracing::span::EnteredSpan {
742        if Self::is_tracing() {
743            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "AppExtension", name = pretty_type_name::pretty_type_name::<E>(), %ext_mtd).entered()
744        } else {
745            tracing::span::Span::none().entered()
746        }
747    }
748
749    /// Opens a window span.
750    pub fn window_span(id: WindowId) -> tracing::span::EnteredSpan {
751        if Self::is_tracing() {
752            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "Window", %id, raw_id = id.get() as u64).entered()
753        } else {
754            tracing::span::Span::none().entered()
755        }
756    }
757
758    /// Opens a widget span.
759    #[cfg(feature = "trace_widget")]
760    pub fn widget_span(id: WidgetId, name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
761        if Self::is_tracing() {
762            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "widget", %id, raw_id = id.get(), name, %node_mtd).entered()
763        } else {
764            tracing::span::Span::none().entered()
765        }
766    }
767
768    /// Opens a property span.
769    #[cfg(feature = "trace_wgt_item")]
770    pub fn property_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
771        if Self::is_tracing() {
772            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "property", name, %node_mtd).entered()
773        } else {
774            tracing::span::Span::none().entered()
775        }
776    }
777
778    /// Opens an intrinsic span.
779    #[cfg(feature = "trace_wgt_item")]
780    pub fn intrinsic_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
781        if Self::is_tracing() {
782            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "intrinsic", name, %node_mtd).entered()
783        } else {
784            tracing::span::Span::none().entered()
785        }
786    }
787
788    /// Opens a custom named span.
789    pub fn custom_span(name: &str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
790        if Self::is_tracing() {
791            tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "tag", %name, %node_mtd).entered()
792        } else {
793            tracing::Span::none().entered()
794        }
795    }
796
797    /// Log a direct update request.
798    pub fn log_update() {
799        if Self::is_tracing() {
800            tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
801                kind = "update"
802            });
803        }
804    }
805
806    /// Log a direct info rebuild request.
807    pub fn log_info() {
808        if Self::is_tracing() {
809            tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
810                kind = "info"
811            });
812        }
813    }
814
815    /// Log a direct layout request.
816    pub fn log_layout() {
817        if Self::is_tracing() {
818            tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
819                kind = "layout"
820            });
821        }
822    }
823
824    /// Log a direct render request.
825    pub fn log_render() {
826        if Self::is_tracing() {
827            tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
828                kind = "render"
829            });
830        }
831    }
832
833    /// Log a custom event.
834    pub fn log_custom(tag: &str) {
835        if Self::is_tracing() {
836            tracing::event!(
837                target: UpdatesTrace::UPDATES_TARGET,
838                tracing::Level::TRACE,
839                { kind = "custom", %tag }
840            );
841        }
842    }
843
844    /// Log a var update request.
845    pub fn log_var(type_name: &str) {
846        if Self::is_tracing() {
847            tracing::event!(
848                target: UpdatesTrace::UPDATES_TARGET,
849                tracing::Level::TRACE,
850                { kind = "var", type_name = pretty_type_name::pretty_type_name_str(type_name) }
851            );
852        }
853    }
854
855    /// Log an event update request.
856    pub fn log_event(event: AnyEvent) {
857        if Self::is_tracing() {
858            tracing::event!(
859                target: UpdatesTrace::UPDATES_TARGET,
860                tracing::Level::TRACE,
861                { kind = "event", type_name = event.name() }
862            );
863        }
864    }
865
866    /// Run `action` collecting a trace of what caused updates.
867    pub fn collect_trace<R>(trace: &mut Vec<UpdateTrace>, action: impl FnOnce() -> R) -> R {
868        let trace_enabled = UPDATES_TRACE_ENABLED.swap(true, atomic::Ordering::Relaxed);
869
870        let tracer = UpdatesTrace::new();
871        let result = Arc::clone(&tracer.trace);
872        let r = tracing::subscriber::with_default(tracer, action);
873        trace.extend(Arc::try_unwrap(result).unwrap().into_inner());
874
875        UPDATES_TRACE_ENABLED.store(trace_enabled, atomic::Ordering::Relaxed);
876
877        r
878    }
879
880    /// Displays the top 20 most frequent update sources in the trace.
881    pub fn format_trace(trace: Vec<UpdateTrace>) -> String {
882        let mut frequencies = HashMap::with_capacity(50);
883        for t in trace {
884            match frequencies.entry(t) {
885                hash_map::Entry::Vacant(e) => {
886                    e.insert(1);
887                }
888                hash_map::Entry::Occupied(mut e) => {
889                    *e.get_mut() += 1;
890                }
891            }
892        }
893        let mut frequencies: Vec<_> = frequencies.into_iter().collect();
894        frequencies.sort_by_key(|(_, c)| -c);
895
896        let mut trace = String::new();
897        for (t, c) in frequencies.into_iter().take(20) {
898            use std::fmt::Write;
899            let _ = writeln!(&mut trace, "{t} ({c} times)");
900        }
901        trace
902    }
903}
904#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
905struct UpdateContext {
906    app_extension: Option<String>,
907    window_id: Option<WindowId>,
908    widget: Option<(WidgetId, String)>,
909    node_parent: Option<String>,
910    tag: Option<String>,
911}
912impl fmt::Display for UpdateContext {
913    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914        if let Some(e) = &self.app_extension {
915            write!(f, "{}", e.rsplit("::").next().unwrap())?;
916        } else {
917            write!(f, "<unknown>")?;
918        }
919        if let Some(w) = self.window_id {
920            write!(f, "//{w}")?;
921        }
922        if let Some((id, name)) = &self.widget {
923            write!(f, "/../{name}#{id}")?;
924        }
925        if let Some(p) = &self.node_parent
926            && !p.is_empty()
927        {
928            write!(f, "//{p}")?;
929        }
930        if let Some(t) = &self.tag
931            && !t.is_empty()
932        {
933            write!(f, "//{t}")?;
934        }
935        Ok(())
936    }
937}
938
939#[derive(Debug, PartialEq, Eq, Hash)]
940pub(crate) struct UpdateTrace {
941    ctx: UpdateContext,
942    action: UpdateAction,
943}
944impl fmt::Display for UpdateTrace {
945    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
946        write!(f, "{} {}", self.ctx, self.action)
947    }
948}
949#[derive(Debug, PartialEq, Eq, Hash)]
950enum UpdateAction {
951    Info,
952    Update,
953    Layout,
954    Render,
955    Var { type_name: String },
956    Event { type_name: String },
957    Custom { tag: String },
958}
959impl fmt::Display for UpdateAction {
960    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
961        match self {
962            UpdateAction::Info => write!(f, "info"),
963            UpdateAction::Update => write!(f, "update"),
964            UpdateAction::Layout => write!(f, "layout"),
965            UpdateAction::Render => write!(f, "render"),
966            UpdateAction::Var { type_name } => write!(f, "update var of type {type_name}"),
967            UpdateAction::Event { type_name } => write!(f, "update event {type_name}"),
968            UpdateAction::Custom { tag } => write!(f, "{tag}"),
969        }
970    }
971}
972
973fn visit_str(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> String {
974    struct Visitor<'a> {
975        name: &'a str,
976        result: String,
977    }
978    impl tracing::field::Visit for Visitor<'_> {
979        fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
980            if field.name() == self.name {
981                self.result = format!("{value:?}");
982            }
983        }
984        fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
985            if field.name() == self.name {
986                value.clone_into(&mut self.result);
987            }
988        }
989    }
990
991    let mut visitor = Visitor {
992        name,
993        result: String::new(),
994    };
995    record(&mut visitor);
996    visitor.result
997}
998fn visit_u64(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> Option<u64> {
999    struct Visitor<'a> {
1000        name: &'a str,
1001        result: Option<u64>,
1002    }
1003    impl tracing::field::Visit for Visitor<'_> {
1004        fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
1005        fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
1006            if field.name() == self.name {
1007                self.result = Some(value)
1008            }
1009        }
1010    }
1011
1012    let mut visitor = Visitor { name, result: None };
1013    record(&mut visitor);
1014    visitor.result
1015}
1016
1017/// Update schedule service.
1018pub struct UPDATES;
1019impl UPDATES {
1020    pub(crate) fn init(&self, event_sender: AppEventSender) {
1021        UPDATES_SV.write().event_sender = Some(event_sender);
1022    }
1023
1024    #[must_use]
1025    #[cfg(any(test, doc, feature = "test_util"))]
1026    pub(crate) fn apply(&self) -> ContextUpdates {
1027        self.apply_updates() | self.apply_info() | self.apply_layout_render()
1028    }
1029
1030    #[must_use]
1031    pub(crate) fn apply_updates(&self) -> ContextUpdates {
1032        let events = EVENTS.apply_updates();
1033        VARS_APP.apply_updates();
1034
1035        let (update, update_widgets) = UPDATES.take_update();
1036
1037        ContextUpdates {
1038            events,
1039            update,
1040            update_widgets,
1041            info: false,
1042            info_widgets: InfoUpdates::default(),
1043            layout: false,
1044            layout_widgets: LayoutUpdates::default(),
1045            render: false,
1046            render_widgets: RenderUpdates::default(),
1047            render_update_widgets: RenderUpdates::default(),
1048        }
1049    }
1050    #[must_use]
1051    pub(crate) fn apply_info(&self) -> ContextUpdates {
1052        let (info, info_widgets) = UPDATES.take_info();
1053
1054        ContextUpdates {
1055            events: vec![],
1056            update: false,
1057            update_widgets: WidgetUpdates::default(),
1058            info,
1059            info_widgets,
1060            layout: false,
1061            layout_widgets: LayoutUpdates::default(),
1062            render: false,
1063            render_widgets: RenderUpdates::default(),
1064            render_update_widgets: RenderUpdates::default(),
1065        }
1066    }
1067    #[must_use]
1068    pub(crate) fn apply_layout_render(&self) -> ContextUpdates {
1069        let (layout, layout_widgets) = UPDATES.take_layout();
1070        let (render, render_widgets, render_update_widgets) = UPDATES.take_render();
1071
1072        ContextUpdates {
1073            events: vec![],
1074            update: false,
1075            update_widgets: WidgetUpdates::default(),
1076            info: false,
1077            info_widgets: InfoUpdates::default(),
1078            layout,
1079            layout_widgets,
1080            render,
1081            render_widgets,
1082            render_update_widgets,
1083        }
1084    }
1085
1086    pub(crate) fn on_app_awake(&self) {
1087        UPDATES_SV.write().app_awake(true);
1088    }
1089
1090    pub(crate) fn on_app_sleep(&self) {
1091        UPDATES_SV.write().app_awake(false);
1092    }
1093
1094    /// Returns next timer or animation tick time.
1095    pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
1096        TIMERS_SV.write().next_deadline(timer);
1097        VARS_APP.next_deadline(timer);
1098    }
1099
1100    /// Update timers and animations, returns next wake time.
1101    pub(crate) fn update_timers(&self, timer: &mut LoopTimer) {
1102        TIMERS_SV.write().apply_updates(timer);
1103        VARS_APP.update_animations(timer);
1104    }
1105
1106    /// If a call to `apply_updates` will generate updates (ignoring timers).
1107    #[must_use]
1108    pub(crate) fn has_pending_updates(&self) -> bool {
1109        UPDATES_SV.read().update_ext.intersects(UpdateFlags::UPDATE | UpdateFlags::INFO)
1110            || VARS_APP.has_pending_updates()
1111            || EVENTS_SV.write().has_pending_updates()
1112            || TIMERS_SV.read().has_pending_updates()
1113    }
1114
1115    #[must_use]
1116    pub(crate) fn has_pending_layout_or_render(&self) -> bool {
1117        UPDATES_SV
1118            .read()
1119            .update_ext
1120            .intersects(UpdateFlags::LAYOUT | UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE)
1121    }
1122
1123    /// Create an [`AppEventSender`] that can be used to awake the app and send app events from threads outside of the app.
1124    pub fn sender(&self) -> AppEventSender {
1125        UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
1126    }
1127
1128    /// Create an std task waker that wakes the event loop and updates.
1129    pub fn waker(&self, target: impl Into<Option<WidgetId>>) -> Waker {
1130        UPDATES_SV.read().event_sender.as_ref().unwrap().waker(target)
1131    }
1132
1133    pub(crate) fn update_flags_root(&self, flags: UpdateFlags, window_id: WindowId, root_id: WidgetId) {
1134        if flags.is_empty() {
1135            return;
1136        }
1137
1138        let mut u = UPDATES_SV.write();
1139        if flags.contains(UpdateFlags::UPDATE) {
1140            u.update_widgets.insert_updates_root(window_id, root_id);
1141        }
1142        if flags.contains(UpdateFlags::INFO) {
1143            u.info_widgets.insert_updates_root(window_id, root_id);
1144        }
1145        if flags.contains(UpdateFlags::LAYOUT) {
1146            u.layout_widgets.insert_updates_root(window_id, root_id);
1147        }
1148
1149        if flags.contains(UpdateFlags::RENDER) {
1150            u.render_widgets.insert_updates_root(window_id, root_id);
1151        } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1152            u.render_update_widgets.insert_updates_root(window_id, root_id);
1153        }
1154
1155        u.update_ext |= flags;
1156    }
1157
1158    pub(crate) fn update_flags(&self, flags: UpdateFlags, target: impl Into<Option<WidgetId>>) {
1159        if flags.is_empty() {
1160            return;
1161        }
1162
1163        let mut u = UPDATES_SV.write();
1164
1165        if let Some(id) = target.into() {
1166            if flags.contains(UpdateFlags::UPDATE) {
1167                u.update_widgets.search_widget(id);
1168            }
1169            if flags.contains(UpdateFlags::INFO) {
1170                u.info_widgets.search_widget(id);
1171            }
1172            if flags.contains(UpdateFlags::LAYOUT) {
1173                u.layout_widgets.search_widget(id);
1174            }
1175
1176            if flags.contains(UpdateFlags::RENDER) {
1177                u.render_widgets.search_widget(id);
1178            } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1179                u.render_update_widgets.search_widget(id);
1180            }
1181        }
1182
1183        u.update_ext |= flags;
1184    }
1185
1186    /// Schedules an [`UpdateOp`] that optionally affects the `target` widget.
1187    pub fn update_op(&self, op: UpdateOp, target: impl Into<Option<WidgetId>>) -> &Self {
1188        let target = target.into();
1189        match op {
1190            UpdateOp::Update => self.update(target),
1191            UpdateOp::Info => self.update_info(target),
1192            UpdateOp::Layout => self.layout(target),
1193            UpdateOp::Render => self.render(target),
1194            UpdateOp::RenderUpdate => self.render_update(target),
1195        }
1196    }
1197
1198    /// Schedules an [`UpdateOp`] for the window only.
1199    pub fn update_op_window(&self, op: UpdateOp, target: WindowId) -> &Self {
1200        match op {
1201            UpdateOp::Update => self.update_window(target),
1202            UpdateOp::Info => self.update_info_window(target),
1203            UpdateOp::Layout => self.layout_window(target),
1204            UpdateOp::Render => self.render_window(target),
1205            UpdateOp::RenderUpdate => self.render_update_window(target),
1206        }
1207    }
1208
1209    /// Schedules an update that affects the `target`.
1210    ///
1211    /// After the current update cycle ends a new update will happen that includes the `target` widget.
1212    pub fn update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1213        UpdatesTrace::log_update();
1214        self.update_internal(target.into())
1215    }
1216    /// Implements `update` without `log_update`.
1217    pub(crate) fn update_internal(&self, target: Option<WidgetId>) -> &UPDATES {
1218        let mut u = UPDATES_SV.write();
1219        u.update_ext.insert(UpdateFlags::UPDATE);
1220        u.send_awake();
1221        if let Some(id) = target {
1222            u.update_widgets.search_widget(id);
1223        }
1224        self
1225    }
1226
1227    /// Schedules an update for the window only.
1228    pub fn update_window(&self, target: WindowId) -> &Self {
1229        let mut u = UPDATES_SV.write();
1230        u.update_ext.insert(UpdateFlags::UPDATE);
1231        u.send_awake();
1232        u.update_widgets.insert_window(target);
1233        self
1234    }
1235
1236    pub(crate) fn send_awake(&self) {
1237        UPDATES_SV.write().send_awake();
1238    }
1239
1240    /// Schedules an info rebuild that affects the `target`.
1241    ///
1242    /// After the current update cycle ends a new update will happen that requests an info rebuild that includes the `target` widget.
1243    pub fn update_info(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1244        UpdatesTrace::log_info();
1245        let mut u = UPDATES_SV.write();
1246        u.update_ext.insert(UpdateFlags::INFO);
1247        u.send_awake();
1248        if let Some(id) = target.into() {
1249            u.info_widgets.search_widget(id);
1250        }
1251        self
1252    }
1253
1254    /// Schedules an info rebuild for the window only.
1255    pub fn update_info_window(&self, target: WindowId) -> &Self {
1256        UpdatesTrace::log_info();
1257        let mut u = UPDATES_SV.write();
1258        u.update_ext.insert(UpdateFlags::INFO);
1259        u.send_awake();
1260        u.info_widgets.insert_window(target);
1261        self
1262    }
1263
1264    /// Schedules a layout update that affects the `target`.
1265    ///
1266    /// After the current update cycle ends and there are no more updates requested a layout pass is issued that includes the `target` widget.
1267    pub fn layout(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1268        UpdatesTrace::log_layout();
1269        let mut u = UPDATES_SV.write();
1270        u.update_ext.insert(UpdateFlags::LAYOUT);
1271        u.send_awake();
1272        if let Some(id) = target.into() {
1273            u.layout_widgets.search_widget(id);
1274        }
1275        self
1276    }
1277
1278    /// Schedules a layout update for the window only.
1279    pub fn layout_window(&self, target: WindowId) -> &Self {
1280        UpdatesTrace::log_layout();
1281        let mut u = UPDATES_SV.write();
1282        u.update_ext.insert(UpdateFlags::LAYOUT);
1283        u.send_awake();
1284        u.layout_widgets.insert_window(target);
1285        self
1286    }
1287
1288    /// Schedules a full render that affects the `target`.
1289    ///
1290    /// After the current update cycle ends and there are no more updates or layouts requested a render pass is issued that
1291    /// includes the `target` widget.
1292    ///
1293    /// If no `target` is provided only the app extensions receive a render request.
1294    pub fn render(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1295        UpdatesTrace::log_render();
1296        let mut u = UPDATES_SV.write();
1297        u.update_ext.insert(UpdateFlags::RENDER);
1298        u.send_awake();
1299        if let Some(id) = target.into() {
1300            u.render_widgets.search_widget(id);
1301        }
1302        self
1303    }
1304
1305    /// Schedules a new frame for the window only.
1306    pub fn render_window(&self, target: WindowId) -> &Self {
1307        UpdatesTrace::log_render();
1308        let mut u = UPDATES_SV.write();
1309        u.update_ext.insert(UpdateFlags::RENDER);
1310        u.send_awake();
1311        u.render_widgets.insert_window(target);
1312        self
1313    }
1314
1315    /// Schedules a render update that affects the `target`.
1316    ///
1317    /// After the current update cycle ends and there are no more updates or layouts requested a render pass is issued that
1318    /// includes the `target` widget marked for render update only. Note that if a full render was requested for another widget
1319    /// on the same window this request is upgraded to a full frame render.
1320    pub fn render_update(&self, target: impl Into<Option<WidgetId>>) -> &Self {
1321        UpdatesTrace::log_render();
1322        let mut u = UPDATES_SV.write();
1323        u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1324        u.send_awake();
1325        if let Some(id) = target.into() {
1326            u.render_update_widgets.search_widget(id);
1327        }
1328        self
1329    }
1330
1331    /// Schedules a render update for the window only.
1332    pub fn render_update_window(&self, target: WindowId) -> &Self {
1333        UpdatesTrace::log_render();
1334        let mut u = UPDATES_SV.write();
1335        u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1336        u.send_awake();
1337        u.render_update_widgets.insert_window(target);
1338        self
1339    }
1340
1341    /// Returns `true` is render or render update is requested for the window.
1342    pub fn is_pending_render(&self, window_id: WindowId) -> bool {
1343        let u = UPDATES_SV.read();
1344        u.render_widgets.enter_window(window_id) || u.render_update_widgets.enter_window(window_id)
1345    }
1346
1347    /// Schedule the `future` to run in the app context, in the *preview* track of the next update.
1348    ///
1349    /// This requests an app update. Each future awake also requests an app update and also runs in the *preview* track.
1350    ///
1351    /// Returns a handle that can be dropped to cancel execution.
1352    pub fn run<F: Future<Output = ()> + Send + 'static>(&self, future: impl IntoFuture<Output = (), IntoFuture = F>) -> OnUpdateHandle {
1353        let future = future.into_future();
1354        self.run_hn_once(async_hn_once!(|_| future.await))
1355    }
1356
1357    /// Schedule a handler to run once in the app context, in the *preview* track of the next update.
1358    ///
1359    /// The [`Handler`] can be any kind, including async handlers. If the handler is async and does not finish in
1360    /// one call it is scheduled to update in *preview* updates.
1361    ///
1362    /// Returns a handle that can be dropped to cancel execution.
1363    pub fn run_hn_once(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1364        let mut u = UPDATES_SV.write();
1365        u.update_ext.insert(UpdateFlags::UPDATE);
1366        u.send_awake();
1367        Self::push_handler(u.pre_handlers.get_mut(), true, handler.into_once(), true)
1368    }
1369
1370    /// Create a preview update handler.
1371    ///
1372    /// The `handler` is called every time the app updates, just before the UI updates. It can be any of the non-async [`Handler`],
1373    /// use the [`hn!`] or [`hn_once!`] macros to declare the closure. You must avoid using async handlers because UI bound async
1374    /// 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)
1375    /// to start an async app context task.
1376    ///
1377    /// Returns an [`OnUpdateHandle`] that can be used to unsubscribe, you can also unsubscribe from inside the handler by calling
1378    /// [`APP_HANDLER.unsubscribe`].
1379    ///
1380    /// [`hn_once!`]: macro@crate::handler::hn_once
1381    /// [`hn!`]: macro@crate::handler::hn
1382    /// [`async_hn!`]: macro@crate::handler::async_hn
1383    /// [`APP_HANDLER.unsubscribe`]: crate::handler::APP_HANDLER::unsubscribe
1384    pub fn on_pre_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1385        let u = UPDATES_SV.read();
1386        Self::push_handler(&mut u.pre_handlers.lock(), true, handler, false)
1387    }
1388
1389    /// Create an update handler.
1390    ///
1391    /// The `handler` is called every time the app updates, just after the UI updates. It can be any of the non-async [`Handler`],
1392    /// use the [`hn!`] or [`hn_once!`] macros to declare the closure. You must avoid using async handlers because UI bound async
1393    /// 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)
1394    /// to start an async app context task.
1395    ///
1396    /// Returns an [`OnUpdateHandle`] that can be used to unsubscribe, you can also unsubscribe from inside the handler by calling
1397    /// [`APP_HANDLER.unsubscribe`].
1398    ///
1399    /// [`hn_once!`]: macro@crate::handler::hn_once
1400    /// [`hn!`]: macro@crate::handler::hn
1401    /// [`async_hn!`]: macro@crate::handler::async_hn
1402    /// [`APP_HANDLER.unsubscribe`]: crate::handler::APP_HANDLER::unsubscribe
1403    pub fn on_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1404        let u = UPDATES_SV.read();
1405        Self::push_handler(&mut u.pos_handlers.lock(), false, handler, false)
1406    }
1407
1408    fn push_handler(
1409        entries: &mut Vec<UpdateHandler>,
1410        is_preview: bool,
1411        mut handler: Handler<UpdateArgs>,
1412        force_once: bool,
1413    ) -> OnUpdateHandle {
1414        let (handle_owner, handle) = OnUpdateHandle::new();
1415        entries.push(UpdateHandler {
1416            handle: handle_owner,
1417            count: 0,
1418            handler: Box::new(move |args, handle| {
1419                handler.app_event(handle.clone_boxed(), is_preview, args);
1420                if force_once {
1421                    handle.unsubscribe();
1422                }
1423            }),
1424        });
1425        handle
1426    }
1427
1428    pub(crate) fn on_pre_updates(&self) {
1429        let _s = tracing::trace_span!("UPDATES.on_pre_updates");
1430        let mut handlers = mem::take(UPDATES_SV.write().pre_handlers.get_mut());
1431        Self::retain_updates(&mut handlers);
1432
1433        let mut u = UPDATES_SV.write();
1434        handlers.append(u.pre_handlers.get_mut());
1435        *u.pre_handlers.get_mut() = handlers;
1436    }
1437
1438    pub(crate) fn on_updates(&self) {
1439        let _s = tracing::trace_span!("UPDATES.on_updates");
1440        let mut handlers = mem::take(UPDATES_SV.write().pos_handlers.get_mut());
1441        Self::retain_updates(&mut handlers);
1442
1443        let mut u = UPDATES_SV.write();
1444        handlers.append(u.pos_handlers.get_mut());
1445        *u.pos_handlers.get_mut() = handlers;
1446    }
1447
1448    fn retain_updates(handlers: &mut Vec<UpdateHandler>) {
1449        handlers.retain_mut(|e| {
1450            !e.handle.is_dropped() && {
1451                e.count = e.count.wrapping_add(1);
1452                (e.handler)(&UpdateArgs { count: e.count }, &e.handle.weak_handle());
1453                !e.handle.is_dropped()
1454            }
1455        });
1456    }
1457
1458    /// Returns (update_ext, update_widgets)
1459    pub(super) fn take_update(&self) -> (bool, WidgetUpdates) {
1460        let mut u = UPDATES_SV.write();
1461
1462        let ext = u.update_ext.contains(UpdateFlags::UPDATE);
1463        u.update_ext.remove(UpdateFlags::UPDATE);
1464
1465        (
1466            ext,
1467            WidgetUpdates {
1468                delivery_list: mem::take(&mut u.update_widgets),
1469            },
1470        )
1471    }
1472
1473    /// Returns (info_ext, info_widgets)
1474    pub(super) fn take_info(&self) -> (bool, InfoUpdates) {
1475        let mut u = UPDATES_SV.write();
1476
1477        let ext = u.update_ext.contains(UpdateFlags::INFO);
1478        u.update_ext.remove(UpdateFlags::INFO);
1479
1480        (
1481            ext,
1482            InfoUpdates {
1483                delivery_list: mem::take(&mut u.info_widgets),
1484            },
1485        )
1486    }
1487
1488    /// Returns (layout_ext, layout_widgets)
1489    pub(super) fn take_layout(&self) -> (bool, LayoutUpdates) {
1490        let mut u = UPDATES_SV.write();
1491
1492        let ext = u.update_ext.contains(UpdateFlags::LAYOUT);
1493        u.update_ext.remove(UpdateFlags::LAYOUT);
1494
1495        (
1496            ext,
1497            LayoutUpdates {
1498                delivery_list: mem::take(&mut u.layout_widgets),
1499            },
1500        )
1501    }
1502
1503    /// Returns (render_ext, render_widgets, render_update_widgets)
1504    pub(super) fn take_render(&self) -> (bool, RenderUpdates, RenderUpdates) {
1505        let mut u = UPDATES_SV.write();
1506
1507        let ext = u.update_ext.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1508        u.update_ext.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1509
1510        (
1511            ext,
1512            RenderUpdates {
1513                delivery_list: mem::take(&mut u.render_widgets),
1514            },
1515            RenderUpdates {
1516                delivery_list: mem::take(&mut u.render_update_widgets),
1517            },
1518        )
1519    }
1520
1521    pub(crate) fn handler_lens(&self) -> (usize, usize) {
1522        let u = UPDATES_SV.read();
1523
1524        (u.pre_handlers.lock().len(), u.pos_handlers.lock().len())
1525    }
1526    pub(crate) fn new_update_handlers(&self, pre_from: usize, pos_from: usize) -> Vec<Box<dyn Fn() -> bool>> {
1527        let u = UPDATES_SV.read();
1528
1529        u.pre_handlers
1530            .lock()
1531            .iter()
1532            .skip(pre_from)
1533            .chain(u.pos_handlers.lock().iter().skip(pos_from))
1534            .map(|h| h.handle.weak_handle())
1535            .map(|h| {
1536                let r: Box<dyn Fn() -> bool> = Box::new(move || h.upgrade().is_some());
1537                r
1538            })
1539            .collect()
1540    }
1541}
1542
1543app_local! {
1544    static UPDATES_SV: UpdatesService = UpdatesService::new();
1545}
1546struct UpdatesService {
1547    event_sender: Option<AppEventSender>,
1548
1549    update_ext: UpdateFlags,
1550    update_widgets: UpdateDeliveryList,
1551    info_widgets: UpdateDeliveryList,
1552    layout_widgets: UpdateDeliveryList,
1553    render_widgets: UpdateDeliveryList,
1554    render_update_widgets: UpdateDeliveryList,
1555
1556    pre_handlers: Mutex<Vec<UpdateHandler>>,
1557    pos_handlers: Mutex<Vec<UpdateHandler>>,
1558
1559    app_is_awake: bool,
1560    awake_pending: bool,
1561}
1562impl UpdatesService {
1563    fn new() -> Self {
1564        Self {
1565            event_sender: None,
1566            update_ext: UpdateFlags::empty(),
1567            update_widgets: UpdateDeliveryList::new_any(),
1568            info_widgets: UpdateDeliveryList::new_any(),
1569            layout_widgets: UpdateDeliveryList::new_any(),
1570            render_widgets: UpdateDeliveryList::new_any(),
1571            render_update_widgets: UpdateDeliveryList::new_any(),
1572
1573            pre_handlers: Mutex::new(vec![]),
1574            pos_handlers: Mutex::new(vec![]),
1575
1576            app_is_awake: false,
1577            awake_pending: false,
1578        }
1579    }
1580
1581    fn send_awake(&mut self) {
1582        if !self.app_is_awake && !self.awake_pending {
1583            self.awake_pending = true;
1584            match self.event_sender.as_ref() {
1585                Some(s) => {
1586                    if let Err(AppChannelError::Disconnected) = s.send_check_update() {
1587                        tracing::debug!("no app connected to update");
1588                    }
1589                }
1590                None => {
1591                    tracing::debug!("no app connected yet to update");
1592                }
1593            }
1594        }
1595    }
1596
1597    fn app_awake(&mut self, wake: bool) {
1598        self.awake_pending = false;
1599        self.app_is_awake = wake;
1600    }
1601}
1602
1603/// Updates that must be reacted by an app owner.
1604///
1605/// This type is public only for testing, it is the return type for test methods of [`WINDOW`].
1606#[non_exhaustive]
1607#[derive(Default)]
1608pub struct ContextUpdates {
1609    /// Events to notify.
1610    ///
1611    /// When this is not empty [`update`](Self::update) is `true`.
1612    pub events: Vec<EventUpdate>,
1613
1614    /// Update requested.
1615    ///
1616    /// When this is `true`, [`update_widgets`](Self::update_widgets)
1617    /// may contain widgets, if not then only app extensions must update.
1618    pub update: bool,
1619
1620    /// Info rebuild requested.
1621    ///
1622    /// When this is `true`, [`info_widgets`](Self::info_widgets)
1623    /// may contain widgets, if not then only app extensions must update.
1624    pub info: bool,
1625
1626    /// Layout requested.
1627    ///
1628    /// When this is `true`, [`layout_widgets`](Self::layout_widgets)
1629    /// may contain widgets, if not then only app extensions must update.
1630    pub layout: bool,
1631
1632    /// Render requested.
1633    ///
1634    /// When this is `true`, [`render_widgets`](Self::render_widgets) or [`render_update_widgets`](Self::render_update_widgets)
1635    /// may contain widgets, if not then only app extensions must update.
1636    pub render: bool,
1637
1638    /// Update targets.
1639    ///
1640    /// When this is not empty [`update`](Self::update) is `true`.
1641    pub update_widgets: WidgetUpdates,
1642
1643    /// Info rebuild targets.
1644    ///
1645    /// When this is not empty [`info`](Self::info) is `true`.
1646    pub info_widgets: InfoUpdates,
1647
1648    /// Layout targets.
1649    ///
1650    /// When this is not empty [`layout`](Self::layout) is `true`.
1651    pub layout_widgets: LayoutUpdates,
1652
1653    /// Full render targets.
1654    ///
1655    /// When this is not empty [`render`](Self::render) is `true`.
1656    pub render_widgets: RenderUpdates,
1657
1658    /// Render update targets.
1659    ///
1660    /// When this is not empty [`render`](Self::render) is `true`.
1661    pub render_update_widgets: RenderUpdates,
1662}
1663
1664impl fmt::Debug for ContextUpdates {
1665    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1666        if f.alternate() {
1667            f.debug_struct("ContextUpdates")
1668                .field("update", &self.update)
1669                .field("info", &self.info)
1670                .field("layout", &self.layout)
1671                .field("render", &self.render)
1672                .field("events", &self.events)
1673                .field("update_widgets", &self.update_widgets)
1674                .field("info_widgets", &self.info_widgets)
1675                .field("layout_widgets", &self.layout_widgets)
1676                .field("render_widgets", &self.render_widgets)
1677                .field("render_update_widgets", &self.render_update_widgets)
1678                .finish()
1679        } else {
1680            write!(f, "ContextUpdates: ")?;
1681            let mut sep = "";
1682            if !self.events.is_empty() {
1683                write!(f, "{sep}events[")?;
1684                for e in &self.events {
1685                    write!(f, "{sep}{}", e.event.name())?;
1686                    sep = ", ";
1687                }
1688                write!(f, "]")?;
1689            }
1690            if self.update {
1691                write!(f, "{sep}update")?;
1692                sep = ", ";
1693            }
1694            if self.info {
1695                write!(f, "{sep}info")?;
1696                sep = ", ";
1697            }
1698            if self.layout {
1699                write!(f, "{sep}layout")?;
1700                sep = ", ";
1701            }
1702            if self.render {
1703                write!(f, "{sep}render")?;
1704                sep = ", ";
1705            }
1706            if sep.is_empty() {
1707                write!(f, "<none>")?;
1708            }
1709            Ok(())
1710        }
1711    }
1712}
1713impl ContextUpdates {
1714    /// If has events, update, layout or render was requested.
1715    pub fn has_updates(&self) -> bool {
1716        !self.events.is_empty() || self.update || self.info || self.layout || self.render
1717    }
1718}
1719impl std::ops::BitOrAssign for ContextUpdates {
1720    fn bitor_assign(&mut self, rhs: Self) {
1721        self.events.extend(rhs.events);
1722        self.update |= rhs.update;
1723        self.update_widgets.extend(rhs.update_widgets);
1724        self.info |= rhs.info;
1725        self.info_widgets.extend(rhs.info_widgets);
1726        self.layout |= rhs.layout;
1727        self.layout_widgets.extend(rhs.layout_widgets);
1728        self.render |= rhs.render;
1729        self.render_widgets.extend(rhs.render_widgets);
1730        self.render_update_widgets.extend(rhs.render_update_widgets);
1731    }
1732}
1733impl std::ops::BitOr for ContextUpdates {
1734    type Output = Self;
1735
1736    fn bitor(mut self, rhs: Self) -> Self {
1737        self |= rhs;
1738        self
1739    }
1740}
1741
1742bitflags::bitflags! {
1743    #[derive(Clone, Copy, Debug, bytemuck::NoUninit)]
1744    #[repr(transparent)]
1745    pub(crate) struct UpdateFlags: u8 {
1746        const REINIT = 0b1000_0000;
1747        const INFO = 0b0001_0000;
1748        const UPDATE = 0b0000_0001;
1749        const LAYOUT = 0b0000_0010;
1750        const RENDER = 0b0000_0100;
1751        const RENDER_UPDATE = 0b0000_1000;
1752    }
1753}
1754
1755/// Represents an [`on_pre_update`](UPDATES::on_pre_update) or [`on_update`](UPDATES::on_update) handler.
1756///
1757/// Drop all clones of this handle to drop the binding, or call [`perm`](Self::perm) to drop the handle
1758/// but keep the handler alive for the duration of the app.
1759#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1760#[repr(transparent)]
1761#[must_use = "dropping the handle unsubscribes update handler"]
1762pub struct OnUpdateHandle(Handle<()>);
1763impl OnUpdateHandle {
1764    fn new() -> (HandleOwner<()>, OnUpdateHandle) {
1765        let (owner, handle) = Handle::new(());
1766        (owner, OnUpdateHandle(handle))
1767    }
1768
1769    /// Create a handle to nothing, the handle always in the *unsubscribed* state.
1770    ///
1771    /// Note that `Option<OnUpdateHandle>` takes up the same space as `OnUpdateHandle` and avoids an allocation.
1772    pub fn dummy() -> Self {
1773        OnUpdateHandle(Handle::dummy(()))
1774    }
1775
1776    /// Drops the handle but does **not** unsubscribe.
1777    ///
1778    /// The handler stays in memory for the duration of the app or until another handle calls [`unsubscribe`](Self::unsubscribe)
1779    pub fn perm(self) {
1780        self.0.perm();
1781    }
1782
1783    /// If another handle has called [`perm`](Self::perm).
1784    ///
1785    /// If `true` the handler will stay active until the app exits, unless [`unsubscribe`](Self::unsubscribe) is called.
1786    pub fn is_permanent(&self) -> bool {
1787        self.0.is_permanent()
1788    }
1789
1790    /// Drops the handle and forces the handler to drop.
1791    pub fn unsubscribe(self) {
1792        self.0.force_drop()
1793    }
1794
1795    /// If another handle has called [`unsubscribe`](Self::unsubscribe).
1796    ///
1797    /// The handler is already dropped or will be dropped in the next app update, this is irreversible.
1798    pub fn is_unsubscribed(&self) -> bool {
1799        self.0.is_dropped()
1800    }
1801
1802    /// Create a weak handle.
1803    pub fn downgrade(&self) -> WeakOnUpdateHandle {
1804        WeakOnUpdateHandle(self.0.downgrade())
1805    }
1806}
1807
1808/// Weak [`OnUpdateHandle`].
1809#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1810pub struct WeakOnUpdateHandle(WeakHandle<()>);
1811impl WeakOnUpdateHandle {
1812    /// New weak handle that does not upgrade.
1813    pub fn new() -> Self {
1814        Self(WeakHandle::new())
1815    }
1816
1817    /// Gets the strong handle if it is still subscribed.
1818    pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1819        self.0.upgrade().map(OnUpdateHandle)
1820    }
1821}
1822
1823/// Identify node and app-extension operations that can be requested.
1824#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1825pub enum UpdateOp {
1826    /// Updates the target.
1827    ///
1828    /// Causes [`AppExtension::update_preview`], [`AppExtension::update_ui`] and [`AppExtension::update`].
1829    ///
1830    /// Causes [`UiNode::update`] or [`UiNodeOp::Update`] for the target widget and all ancestors.
1831    ///
1832    /// [`UiNodeOp::Update`]: crate::widget::node::UiNodeOp::Update
1833    Update,
1834    /// Rebuilds info for the target.
1835    ///
1836    /// Causes [`AppExtension::info`].
1837    ///
1838    /// Causes [`UiNode::info`] or [`UiNodeOp::Info`] for the target widget and all ancestors.
1839    ///
1840    /// [`Update`]: UpdateOp::Render
1841    /// [`UiNodeOp::Info`]: crate::widget::node::UiNodeOp::Info
1842    Info,
1843    /// Layouts the target.
1844    ///
1845    /// Causes [`AppExtension::layout`].
1846    ///
1847    /// Causes an [`UiNode::layout`] or [`UiNodeOp::Layout`] for the target widget and all ancestors.
1848    ///
1849    /// [`UiNodeOp::Layout`]: crate::widget::node::UiNodeOp::Layout
1850    Layout,
1851    /// Render the target.
1852    ///
1853    /// Causes [`AppExtension::render`].
1854    ///
1855    /// Causes [`UiNode::render`] or [`UiNodeOp::Render`] for the target widget and all ancestors.
1856    ///
1857    /// [`UiNodeOp::Render`]: crate::widget::node::UiNodeOp::Render
1858    Render,
1859    /// Update frame bindings of the target.
1860    ///
1861    /// Causes [`AppExtension::render`].
1862    ///
1863    /// Causes [`UiNode::render_update`] or [`UiNodeOp::RenderUpdate`] for the target widget and all ancestors.
1864    ///
1865    /// This OP is upgraded to [`Render`] if any other widget requests a full render in the same window.
1866    ///
1867    /// [`Render`]: UpdateOp::Render
1868    /// [`UiNodeOp::RenderUpdate`]: crate::widget::node::UiNodeOp::RenderUpdate
1869    RenderUpdate,
1870}
1871
1872/// Arguments for an [`on_pre_update`](UPDATES::on_pre_update), [`on_update`](UPDATES::on_update) or [`run`](UPDATES::run) handler.
1873#[derive(Debug, Clone, Copy)]
1874#[non_exhaustive]
1875pub struct UpdateArgs {
1876    /// Number of times the handler was called.
1877    pub count: usize,
1878}
1879
1880struct UpdateHandler {
1881    handle: HandleOwner<()>,
1882    count: usize,
1883    handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1884}