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