1use std::{
4 collections::{HashMap, hash_map},
5 fmt, mem,
6 sync::Arc,
7 task::Waker,
8};
9
10use parking_lot::Mutex;
11use zng_app_context::app_local;
12use zng_handle::{Handle, HandleOwner, WeakHandle};
13use zng_task::channel::ChannelError;
14use zng_unique_id::IdSet;
15use zng_var::{VARS, VARS_APP};
16
17use crate::{
18 AppEventSender, LoopTimer, async_hn_once,
19 handler::{AppWeakHandle, Handler, HandlerExt as _},
20 hn_once,
21 timer::TIMERS_SV,
22 widget::{
23 WIDGET, WidgetId,
24 info::{InteractionPath, WidgetInfo, WidgetInfoTree, WidgetPath},
25 node::UiNode,
26 },
27 window::{WINDOW, WindowId},
28};
29
30pub struct UpdateDeliveryList {
32 windows: IdSet<WindowId>,
33 widgets: IdSet<WidgetId>,
34 search: IdSet<WidgetId>,
35 search_root: bool,
36}
37impl fmt::Debug for UpdateDeliveryList {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 f.debug_struct("UpdateDeliveryList")
40 .field("windows", &self.windows)
41 .field("widgets", &self.widgets)
42 .field("search", &self.search)
43 .finish_non_exhaustive()
44 }
45}
46impl Default for UpdateDeliveryList {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51impl UpdateDeliveryList {
52 pub fn new() -> Self {
54 Self {
55 windows: IdSet::default(),
56 widgets: IdSet::default(),
57 search: IdSet::default(),
58 search_root: false,
59 }
60 }
61
62 pub(crate) fn insert_updates_root(&mut self, window_id: WindowId, root_id: WidgetId) {
63 self.windows.insert(window_id);
64 self.widgets.insert(root_id);
65 }
66
67 pub fn insert_wgt(&mut self, wgt: &impl WidgetPathProvider) {
69 for w in wgt.widget_and_ancestors() {
70 self.widgets.insert(w);
71 }
72 self.windows.insert(wgt.window_id());
73 }
74
75 pub fn insert_window(&mut self, id: WindowId) {
77 self.windows.insert(id);
78 self.search_root = true;
79 }
80
81 pub fn search_widget(&mut self, widget_id: WidgetId) {
83 self.search.insert(widget_id);
84 }
85
86 pub fn has_pending_search(&mut self) -> bool {
88 self.search_root || !self.search.is_empty()
89 }
90
91 pub fn fulfill_search<'a, 'b>(&'a mut self, windows: impl Iterator<Item = &'b WidgetInfoTree>) {
93 for window in windows {
94 if self.search_root && self.windows.contains(&window.window_id()) {
95 self.widgets.insert(window.root().id());
96 }
97
98 self.search.retain(|w| {
99 if let Some(w) = window.get(*w) {
100 for w in w.widget_and_ancestors() {
101 self.widgets.insert(w);
102 }
103 self.windows.insert(w.window_id());
104 false
105 } else {
106 true
107 }
108 });
109 }
110 self.search.clear();
111 self.search_root = true;
112 }
113
114 fn extend_unchecked(&mut self, other: UpdateDeliveryList) {
116 if self.windows.is_empty() {
117 self.windows = other.windows;
118 } else {
119 self.windows.extend(other.windows);
120 }
121
122 if self.widgets.is_empty() {
123 self.widgets = other.widgets;
124 } else {
125 self.widgets.extend(other.widgets);
126 }
127
128 if self.search.is_empty() {
129 self.search = other.search;
130 } else {
131 self.search.extend(other.search);
132 }
133 }
134
135 pub fn enter_window(&self, window_id: WindowId) -> bool {
137 self.windows.contains(&window_id)
138 }
139
140 pub fn enter_widget(&self, widget_id: WidgetId) -> bool {
142 self.widgets.contains(&widget_id)
143 }
144
145 pub fn windows(&self) -> &IdSet<WindowId> {
147 &self.windows
148 }
149
150 pub fn widgets(&self) -> &IdSet<WidgetId> {
152 &self.widgets
153 }
154
155 #[must_use = "use `search_all` to request search"]
157 pub fn search_widgets(&mut self) -> &IdSet<WidgetId> {
158 &self.search
159 }
160
161 #[must_use = "use `search_widget` to request search"]
163 pub fn search_root(&mut self) -> bool {
164 self.search_root
165 }
166}
167
168pub trait WidgetPathProvider {
170 type WidgetIter<'s>: Iterator<Item = WidgetId>
172 where
173 Self: 's;
174
175 fn window_id(&self) -> WindowId;
177 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_>;
179}
180impl WidgetPathProvider for WidgetInfo {
181 type WidgetIter<'s> = std::iter::Map<crate::widget::info::iter::Ancestors, fn(WidgetInfo) -> WidgetId>;
182
183 fn window_id(&self) -> WindowId {
184 self.tree().window_id()
185 }
186
187 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
188 fn wgt_to_id(wgt: WidgetInfo) -> WidgetId {
189 wgt.id()
190 }
191 self.self_and_ancestors().map(wgt_to_id)
192 }
193}
194impl WidgetPathProvider for WidgetPath {
195 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
196
197 fn window_id(&self) -> WindowId {
198 self.window_id()
199 }
200
201 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
202 self.widgets_path().iter().copied().rev()
203 }
204}
205impl WidgetPathProvider for InteractionPath {
206 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
207
208 fn window_id(&self) -> WindowId {
209 WidgetPath::window_id(self)
210 }
211
212 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
213 self.widgets_path().iter().copied().rev()
214 }
215}
216
217#[derive(Debug, Default)]
219pub struct InfoUpdates {
220 delivery_list: UpdateDeliveryList,
221}
222impl InfoUpdates {
223 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
225 Self { delivery_list }
226 }
227
228 pub fn delivery_list(&self) -> &UpdateDeliveryList {
230 &self.delivery_list
231 }
232
233 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
235 &mut self.delivery_list
236 }
237
238 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
240 where
241 H: FnOnce() -> R,
242 {
243 if self.delivery_list.enter_window(window_id) {
244 Some(handle())
245 } else {
246 None
247 }
248 }
249
250 pub fn extend(&mut self, other: InfoUpdates) {
252 self.delivery_list.extend_unchecked(other.delivery_list)
253 }
254}
255
256#[derive(Debug, Default)]
258pub struct WidgetUpdates {
259 pub(crate) delivery_list: UpdateDeliveryList,
260}
261impl WidgetUpdates {
262 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
264 Self { delivery_list }
265 }
266
267 pub fn delivery_list(&self) -> &UpdateDeliveryList {
269 &self.delivery_list
270 }
271
272 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
274 &mut self.delivery_list
275 }
276
277 pub fn with_window<H, R>(&self, handle: H) -> Option<R>
279 where
280 H: FnOnce() -> R,
281 {
282 if self.delivery_list.enter_window(WINDOW.id()) {
283 Some(handle())
284 } else {
285 None
286 }
287 }
288
289 pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
291 where
292 H: FnOnce() -> R,
293 {
294 if WIDGET.take_update(UpdateFlags::UPDATE) || self.delivery_list.enter_widget(WIDGET.id()) {
295 Some(handle())
296 } else {
297 None
298 }
299 }
300
301 pub fn extend(&mut self, other: WidgetUpdates) {
303 self.delivery_list.extend_unchecked(other.delivery_list)
304 }
305}
306
307#[derive(Debug, Default)]
309pub struct LayoutUpdates {
310 pub(crate) delivery_list: UpdateDeliveryList,
311}
312impl LayoutUpdates {
313 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
315 Self { delivery_list }
316 }
317
318 pub fn delivery_list(&self) -> &UpdateDeliveryList {
320 &self.delivery_list
321 }
322
323 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
325 &mut self.delivery_list
326 }
327
328 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
330 where
331 H: FnOnce() -> R,
332 {
333 if self.delivery_list.enter_window(window_id) {
334 Some(handle())
335 } else {
336 None
337 }
338 }
339
340 pub fn extend(&mut self, other: LayoutUpdates) {
342 self.delivery_list.extend_unchecked(other.delivery_list)
343 }
344}
345
346#[derive(Debug, Default)]
348pub struct RenderUpdates {
349 delivery_list: UpdateDeliveryList,
350}
351impl RenderUpdates {
352 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
354 Self { delivery_list }
355 }
356
357 pub fn delivery_list(&self) -> &UpdateDeliveryList {
359 &self.delivery_list
360 }
361
362 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
364 &mut self.delivery_list
365 }
366
367 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
369 where
370 H: FnOnce() -> R,
371 {
372 if self.delivery_list.enter_window(window_id) {
373 Some(handle())
374 } else {
375 None
376 }
377 }
378
379 pub fn extend(&mut self, other: RenderUpdates) {
381 self.delivery_list.extend_unchecked(other.delivery_list)
382 }
383}
384
385pub trait UpdatesTraceUiNodeExt {
389 fn instrument<S: Into<String>>(self, tag: S) -> UiNode
391 where
392 Self: Sized;
393}
394impl UpdatesTraceUiNodeExt for UiNode {
395 fn instrument<S: Into<String>>(self, tag: S) -> UiNode {
396 let tag = tag.into();
397 self.trace(move |op| UpdatesTrace::custom_span(&tag, op.mtd_name()))
398 }
399}
400
401pub fn updates_trace_span(tag: &'static str) -> tracing::span::EnteredSpan {
405 UpdatesTrace::custom_span(tag, "")
406}
407
408pub fn updates_trace_event(tag: &str) {
412 UpdatesTrace::log_custom(tag)
413}
414
415pub(crate) struct UpdatesTrace {
416 context: Mutex<UpdateContext>,
417 trace: Arc<Mutex<Vec<UpdateTrace>>>,
418
419 widgets_stack: Mutex<Vec<(WidgetId, String)>>,
420 node_parents_stack: Mutex<Vec<String>>,
421 tags_stack: Mutex<Vec<String>>,
422}
423impl tracing::subscriber::Subscriber for UpdatesTrace {
424 fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
425 metadata.target() == Self::UPDATES_TARGET
426 }
427
428 fn new_span(&self, span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
429 match span.metadata().name() {
430 "property" | "intrinsic" => {
431 let name = visit_str(|v| span.record(v), "name");
432 let mut ctx = self.context.lock();
433
434 if let Some(p) = ctx.node_parent.replace(name) {
435 self.node_parents_stack.lock().push(p);
436 }
437 if let Some(p) = ctx.tag.replace(String::new()) {
438 self.tags_stack.lock().push(p);
439 }
440
441 tracing::span::Id::from_u64(1)
442 }
443 "widget" => {
444 let id = visit_u64(|v| span.record(v), "raw_id").unwrap();
445 if id == 0 {
446 panic!()
447 }
448 let id = WidgetId::from_raw(id);
449
450 let name = visit_str(|v| span.record(v), "name");
451
452 let mut ctx = self.context.lock();
453 if let Some(p) = ctx.widget.replace((id, name)) {
454 self.widgets_stack.lock().push(p);
455 }
456
457 if let Some(p) = ctx.node_parent.replace(String::new()) {
458 self.node_parents_stack.lock().push(p);
459 }
460
461 if let Some(p) = ctx.tag.replace(String::new()) {
462 self.tags_stack.lock().push(p);
463 }
464
465 tracing::span::Id::from_u64(2)
466 }
467 "Window" => {
468 let id = visit_u64(|v| span.record(v), "raw_id").unwrap() as u32;
469 if id == 0 {
470 panic!()
471 }
472 let id = WindowId::from_raw(id);
473
474 let mut ctx = self.context.lock();
475 ctx.window_id = Some(id);
476
477 if let Some(p) = ctx.tag.replace(String::new()) {
478 self.tags_stack.lock().push(p);
479 }
480
481 tracing::span::Id::from_u64(3)
482 }
483 "tag" => {
484 let tag = visit_str(|v| span.record(v), "tag");
485 let mut ctx = self.context.lock();
486 if let Some(p) = ctx.tag.replace(tag) {
487 self.tags_stack.lock().push(p);
488 }
489 tracing::span::Id::from_u64(5)
490 }
491 _ => tracing::span::Id::from_u64(u64::MAX),
492 }
493 }
494
495 fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
496
497 fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
498
499 fn event(&self, event: &tracing::Event<'_>) {
500 let action = match visit_str(|v| event.record(v), "kind").as_str() {
501 "var" => UpdateAction::Var {
502 type_name: visit_str(|v| event.record(v), "type_name"),
503 },
504 "request" => UpdateAction::Update,
505 "info" => UpdateAction::Info,
506 "layout" => UpdateAction::Layout,
507 "render" => UpdateAction::Render,
508 "custom" => UpdateAction::Custom {
509 tag: visit_str(|v| event.record(v), "tag"),
510 },
511 _ => return,
512 };
513
514 let ctx = self.context.lock().clone();
515 let entry = UpdateTrace { ctx, action };
520 self.trace.lock().push(entry);
521 }
522
523 fn enter(&self, _span: &tracing::span::Id) {}
524
525 fn exit(&self, span: &tracing::span::Id) {
526 let mut ctx = self.context.lock();
527 if span == &tracing::span::Id::from_u64(1) {
528 ctx.node_parent = self.node_parents_stack.lock().pop();
529 ctx.tag = self.tags_stack.lock().pop();
530 } else if span == &tracing::span::Id::from_u64(2) {
531 ctx.widget = self.widgets_stack.lock().pop();
532 ctx.node_parent = self.node_parents_stack.lock().pop();
533 ctx.tag = self.tags_stack.lock().pop();
534 } else if span == &tracing::span::Id::from_u64(3) {
535 ctx.window_id = None;
536 ctx.tag = self.tags_stack.lock().pop();
537 } else if span == &tracing::span::Id::from_u64(4) {
538 ctx.app_extension = None;
539 ctx.tag = self.tags_stack.lock().pop();
540 } else if span == &tracing::span::Id::from_u64(5) {
541 ctx.tag = self.tags_stack.lock().pop();
542 }
543 }
544}
545impl UpdatesTrace {
546 const UPDATES_TARGET: &'static str = "zng-updates";
547
548 fn new() -> Self {
549 UpdatesTrace {
550 context: Mutex::new(UpdateContext::default()),
551 trace: Arc::new(Mutex::new(Vec::with_capacity(100))),
552 widgets_stack: Mutex::new(Vec::with_capacity(100)),
553 node_parents_stack: Mutex::new(Vec::with_capacity(100)),
554 tags_stack: Mutex::new(Vec::new()),
555 }
556 }
557
558 pub fn window_span(id: WindowId) -> tracing::span::EnteredSpan {
562 tracing::debug_span!(target: UpdatesTrace::UPDATES_TARGET, "Window", %id, raw_id = id.get() as u64).entered()
563 }
564
565 #[cfg(feature = "trace_widget")]
569 pub fn widget_span(id: WidgetId, name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
570 tracing::debug_span!(target: UpdatesTrace::UPDATES_TARGET, "widget", %id, raw_id = id.get(), name, %node_mtd).entered()
571 }
572
573 #[cfg(feature = "trace_wgt_item")]
577 pub fn property_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
578 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "property", name, %node_mtd).entered()
579 }
580
581 #[cfg(feature = "trace_wgt_item")]
585 pub fn intrinsic_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
586 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "intrinsic", name, %node_mtd).entered()
587 }
588
589 pub fn custom_span(name: &str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
593 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "tag", %name, %node_mtd).entered()
594 }
595
596 pub fn log_update() {
600 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
601 kind = "update"
602 });
603 }
604
605 pub fn log_info() {
609 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
610 kind = "info"
611 });
612 }
613
614 pub fn log_layout() {
618 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
619 kind = "layout"
620 });
621 }
622
623 pub fn log_render() {
627 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
628 kind = "render"
629 });
630 }
631
632 pub fn log_custom(tag: &str) {
636 tracing::event!(
637 target: UpdatesTrace::UPDATES_TARGET,
638 tracing::Level::TRACE,
639 { kind = "custom", %tag }
640 );
641 }
642
643 pub fn log_var(type_name: &str) {
647 tracing::event!(
648 target: UpdatesTrace::UPDATES_TARGET,
649 tracing::Level::TRACE,
650 { kind = "var", type_name = pretty_type_name::pretty_type_name_str(type_name) }
651 );
652 }
653
654 pub fn collect_trace<R>(trace: &mut Vec<UpdateTrace>, action: impl FnOnce() -> R) -> R {
656 let tracer = UpdatesTrace::new();
657 let result = Arc::clone(&tracer.trace);
658 let r = tracing::subscriber::with_default(tracer, action);
659 trace.extend(Arc::try_unwrap(result).unwrap().into_inner());
660
661 r
662 }
663
664 pub fn format_trace(trace: Vec<UpdateTrace>) -> String {
666 let mut frequencies = HashMap::with_capacity(50);
667 for t in trace {
668 match frequencies.entry(t) {
669 hash_map::Entry::Vacant(e) => {
670 e.insert(1);
671 }
672 hash_map::Entry::Occupied(mut e) => {
673 *e.get_mut() += 1;
674 }
675 }
676 }
677 let mut frequencies: Vec<_> = frequencies.into_iter().collect();
678 frequencies.sort_by_key(|(_, c)| -c);
679
680 let mut trace = String::new();
681 for (t, c) in frequencies.into_iter().take(20) {
682 use std::fmt::Write;
683 let _ = writeln!(&mut trace, "{t} ({c} times)");
684 }
685 trace
686 }
687}
688#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
689struct UpdateContext {
690 app_extension: Option<String>,
691 window_id: Option<WindowId>,
692 widget: Option<(WidgetId, String)>,
693 node_parent: Option<String>,
694 tag: Option<String>,
695}
696impl fmt::Display for UpdateContext {
697 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698 if let Some(e) = &self.app_extension {
699 write!(f, "{}", e.rsplit("::").next().unwrap())?;
700 } else {
701 write!(f, "<unknown>")?;
702 }
703 if let Some(w) = self.window_id {
704 write!(f, "//{w}")?;
705 }
706 if let Some((id, name)) = &self.widget {
707 write!(f, "/../{name}#{id}")?;
708 }
709 if let Some(p) = &self.node_parent
710 && !p.is_empty()
711 {
712 write!(f, "//{p}")?;
713 }
714 if let Some(t) = &self.tag
715 && !t.is_empty()
716 {
717 write!(f, "//{t}")?;
718 }
719 Ok(())
720 }
721}
722
723#[derive(Debug, PartialEq, Eq, Hash)]
724pub(crate) struct UpdateTrace {
725 ctx: UpdateContext,
726 action: UpdateAction,
727}
728impl fmt::Display for UpdateTrace {
729 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730 write!(f, "{} {}", self.ctx, self.action)
731 }
732}
733#[derive(Debug, PartialEq, Eq, Hash)]
734enum UpdateAction {
735 Info,
736 Update,
737 Layout,
738 Render,
739 Var { type_name: String },
740 Custom { tag: String },
741}
742impl fmt::Display for UpdateAction {
743 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744 match self {
745 UpdateAction::Info => write!(f, "info"),
746 UpdateAction::Update => write!(f, "update"),
747 UpdateAction::Layout => write!(f, "layout"),
748 UpdateAction::Render => write!(f, "render"),
749 UpdateAction::Var { type_name } => write!(f, "update {type_name}"),
750 UpdateAction::Custom { tag } => write!(f, "{tag}"),
751 }
752 }
753}
754
755fn visit_str(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> String {
756 struct Visitor<'a> {
757 name: &'a str,
758 result: String,
759 }
760 impl tracing::field::Visit for Visitor<'_> {
761 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
762 if field.name() == self.name {
763 self.result = format!("{value:?}");
764 }
765 }
766 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
767 if field.name() == self.name {
768 value.clone_into(&mut self.result);
769 }
770 }
771 }
772
773 let mut visitor = Visitor {
774 name,
775 result: String::new(),
776 };
777 record(&mut visitor);
778 visitor.result
779}
780fn visit_u64(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> Option<u64> {
781 struct Visitor<'a> {
782 name: &'a str,
783 result: Option<u64>,
784 }
785 impl tracing::field::Visit for Visitor<'_> {
786 fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
787 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
788 if field.name() == self.name {
789 self.result = Some(value)
790 }
791 }
792 }
793
794 let mut visitor = Visitor { name, result: None };
795 record(&mut visitor);
796 visitor.result
797}
798
799pub struct UPDATES;
801impl UPDATES {
802 pub(crate) fn init(&self, event_sender: AppEventSender) {
803 UPDATES_SV.write().event_sender = Some(event_sender);
804 }
805
806 #[must_use]
807 #[cfg(any(test, doc, feature = "test_util"))]
808 pub(crate) fn apply(&self) -> ContextUpdates {
809 self.apply_updates() | self.apply_info() | self.apply_layout_render()
810 }
811
812 #[must_use]
813 pub(crate) fn apply_updates(&self) -> ContextUpdates {
814 VARS_APP.apply_updates();
815
816 let (update, update_widgets) = UPDATES.take_update();
817
818 ContextUpdates {
819 update,
820 update_widgets,
821 info: false,
822 info_widgets: InfoUpdates::default(),
823 layout: false,
824 layout_widgets: LayoutUpdates::default(),
825 render: false,
826 render_widgets: RenderUpdates::default(),
827 render_update_widgets: RenderUpdates::default(),
828 }
829 }
830 #[must_use]
831 pub(crate) fn apply_info(&self) -> ContextUpdates {
832 let (info, info_widgets) = UPDATES.take_info();
833
834 ContextUpdates {
835 update: false,
836 update_widgets: WidgetUpdates::default(),
837 info,
838 info_widgets,
839 layout: false,
840 layout_widgets: LayoutUpdates::default(),
841 render: false,
842 render_widgets: RenderUpdates::default(),
843 render_update_widgets: RenderUpdates::default(),
844 }
845 }
846 #[must_use]
847 pub(crate) fn apply_layout_render(&self) -> ContextUpdates {
848 let (layout, layout_widgets) = UPDATES.take_layout();
849 let (render, render_widgets, render_update_widgets) = UPDATES.take_render();
850
851 ContextUpdates {
852 update: false,
853 update_widgets: WidgetUpdates::default(),
854 info: false,
855 info_widgets: InfoUpdates::default(),
856 layout,
857 layout_widgets,
858 render,
859 render_widgets,
860 render_update_widgets,
861 }
862 }
863
864 pub(crate) fn on_app_awake(&self) {
865 UPDATES_SV.write().app_awake(true);
866 }
867
868 pub(crate) fn on_app_sleep(&self) {
869 UPDATES_SV.write().app_awake(false);
870 }
871
872 pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
874 TIMERS_SV.write().next_deadline(timer);
875 VARS_APP.next_deadline(timer);
876 }
877
878 pub(crate) fn update_timers(&self, timer: &mut LoopTimer) {
880 TIMERS_SV.write().apply_updates(timer);
881 VARS_APP.update_animations(timer);
882 }
883
884 #[must_use]
886 pub(crate) fn has_pending_updates(&self) -> bool {
887 UPDATES_SV.read().update_ext.intersects(UpdateFlags::UPDATE | UpdateFlags::INFO)
888 || VARS_APP.has_pending_updates()
889 || TIMERS_SV.read().has_pending_updates()
890 }
891
892 #[must_use]
893 pub(crate) fn has_pending_layout_or_render(&self) -> bool {
894 UPDATES_SV
895 .read()
896 .update_ext
897 .intersects(UpdateFlags::LAYOUT | UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE)
898 }
899
900 pub fn sender(&self) -> AppEventSender {
902 UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
903 }
904
905 pub fn waker(&self, also_update: Option<WidgetId>) -> Waker {
907 UPDATES_SV.read().event_sender.as_ref().unwrap().waker(also_update)
908 }
909
910 pub(crate) fn update_flags_root(&self, flags: UpdateFlags, window_id: WindowId, root_id: WidgetId) {
911 if flags.is_empty() {
912 return;
913 }
914
915 let mut u = UPDATES_SV.write();
916 if flags.contains(UpdateFlags::UPDATE) {
917 u.update_widgets.insert_updates_root(window_id, root_id);
918 }
919 if flags.contains(UpdateFlags::INFO) {
920 u.info_widgets.insert_updates_root(window_id, root_id);
921 }
922 if flags.contains(UpdateFlags::LAYOUT) {
923 u.layout_widgets.insert_updates_root(window_id, root_id);
924 }
925
926 if flags.contains(UpdateFlags::RENDER) {
927 u.render_widgets.insert_updates_root(window_id, root_id);
928 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
929 u.render_update_widgets.insert_updates_root(window_id, root_id);
930 }
931
932 u.update_ext |= flags;
933 }
934
935 pub(crate) fn update_flags(&self, flags: UpdateFlags, target: WidgetId) {
936 if flags.is_empty() {
937 return;
938 }
939
940 let mut u = UPDATES_SV.write();
941
942 if flags.contains(UpdateFlags::UPDATE) {
943 u.update_widgets.search_widget(target);
944 }
945 if flags.contains(UpdateFlags::INFO) {
946 u.info_widgets.search_widget(target);
947 }
948 if flags.contains(UpdateFlags::LAYOUT) {
949 u.layout_widgets.search_widget(target);
950 }
951
952 if flags.contains(UpdateFlags::RENDER) {
953 u.render_widgets.search_widget(target);
954 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
955 u.render_update_widgets.search_widget(target);
956 }
957
958 u.update_ext |= flags;
959 }
960
961 pub fn update_op(&self, op: UpdateOp, target: WidgetId) -> &Self {
963 match op {
964 UpdateOp::Update => self.update(target),
965 UpdateOp::Info => self.update_info(target),
966 UpdateOp::Layout => self.layout(target),
967 UpdateOp::Render => self.render(target),
968 UpdateOp::RenderUpdate => self.render_update(target),
969 }
970 }
971
972 pub fn update_op_window(&self, op: UpdateOp, target: WindowId) -> &Self {
974 match op {
975 UpdateOp::Update => self.update_window(target),
976 UpdateOp::Info => self.update_info_window(target),
977 UpdateOp::Layout => self.layout_window(target),
978 UpdateOp::Render => self.render_window(target),
979 UpdateOp::RenderUpdate => self.render_update_window(target),
980 }
981 }
982
983 pub fn update(&self, target: WidgetId) -> &Self {
987 UpdatesTrace::log_update();
988 self.update_internal(target)
989 }
990 pub(crate) fn update_internal(&self, target: WidgetId) -> &UPDATES {
992 let mut u = UPDATES_SV.write();
993 u.update_ext.insert(UpdateFlags::UPDATE);
994 u.send_awake();
995 u.update_widgets.search_widget(target);
996 self
997 }
998
999 pub fn update_window(&self, target: WindowId) -> &Self {
1001 let mut u = UPDATES_SV.write();
1002 u.update_ext.insert(UpdateFlags::UPDATE);
1003 u.send_awake();
1004 u.update_widgets.insert_window(target);
1005 self
1006 }
1007
1008 pub fn update_app(&self) {
1010 let mut u = UPDATES_SV.write();
1011 u.update_ext.insert(UpdateFlags::UPDATE);
1012 u.send_awake();
1013 }
1014
1015 pub fn update_info(&self, target: WidgetId) -> &Self {
1019 UpdatesTrace::log_info();
1020 let mut u = UPDATES_SV.write();
1021 u.update_ext.insert(UpdateFlags::INFO);
1022 u.send_awake();
1023 u.info_widgets.search_widget(target);
1024 self
1025 }
1026
1027 pub fn update_info_window(&self, target: WindowId) -> &Self {
1029 UpdatesTrace::log_info();
1030 let mut u = UPDATES_SV.write();
1031 u.update_ext.insert(UpdateFlags::INFO);
1032 u.send_awake();
1033 u.info_widgets.insert_window(target);
1034 self
1035 }
1036
1037 pub fn layout(&self, target: WidgetId) -> &Self {
1041 UpdatesTrace::log_layout();
1042 let mut u = UPDATES_SV.write();
1043 u.update_ext.insert(UpdateFlags::LAYOUT);
1044 u.send_awake();
1045 u.layout_widgets.search_widget(target);
1046 self
1047 }
1048
1049 pub fn layout_window(&self, target: WindowId) -> &Self {
1051 UpdatesTrace::log_layout();
1052 let mut u = UPDATES_SV.write();
1053 u.update_ext.insert(UpdateFlags::LAYOUT);
1054 u.send_awake();
1055 u.layout_widgets.insert_window(target);
1056 self
1057 }
1058
1059 pub fn render(&self, target: WidgetId) -> &Self {
1066 UpdatesTrace::log_render();
1067 let mut u = UPDATES_SV.write();
1068 u.update_ext.insert(UpdateFlags::RENDER);
1069 u.send_awake();
1070 u.render_widgets.search_widget(target);
1071 self
1072 }
1073
1074 pub fn render_window(&self, target: WindowId) -> &Self {
1076 UpdatesTrace::log_render();
1077 let mut u = UPDATES_SV.write();
1078 u.update_ext.insert(UpdateFlags::RENDER);
1079 u.send_awake();
1080 u.render_widgets.insert_window(target);
1081 self
1082 }
1083
1084 pub fn render_update(&self, target: WidgetId) -> &Self {
1090 UpdatesTrace::log_render();
1091 let mut u = UPDATES_SV.write();
1092 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1093 u.send_awake();
1094 u.render_update_widgets.search_widget(target);
1095 self
1096 }
1097
1098 pub fn render_update_window(&self, target: WindowId) -> &Self {
1100 UpdatesTrace::log_render();
1101 let mut u = UPDATES_SV.write();
1102 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1103 u.send_awake();
1104 u.render_update_widgets.insert_window(target);
1105 self
1106 }
1107
1108 pub fn is_pending_render(&self, window_id: WindowId) -> bool {
1110 let u = UPDATES_SV.read();
1111 u.render_widgets.enter_window(window_id) || u.render_update_widgets.enter_window(window_id)
1112 }
1113
1114 pub fn run<F: Future<Output = ()> + Send + 'static>(&self, future: impl IntoFuture<Output = (), IntoFuture = F>) -> OnUpdateHandle {
1120 let future = future.into_future();
1121 self.run_hn_once(async_hn_once!(|_| future.await))
1122 }
1123
1124 pub fn run_hn_once(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1131 let mut u = UPDATES_SV.write();
1132 u.update_ext.insert(UpdateFlags::UPDATE);
1133 u.send_awake();
1134 Self::push_handler(u.pre_handlers.get_mut(), true, handler.into_once(), true)
1135 }
1136
1137 pub fn on_pre_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1152 let u = UPDATES_SV.read();
1153 Self::push_handler(&mut u.pre_handlers.lock(), true, handler, false)
1154 }
1155
1156 pub fn on_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1171 let u = UPDATES_SV.read();
1172 Self::push_handler(&mut u.pos_handlers.lock(), false, handler, false)
1173 }
1174
1175 pub fn once_update(&self, debug_name: &'static str, u: impl FnOnce() + Send + 'static) {
1179 VARS.modify(debug_name, u);
1180 }
1181
1182 pub fn once_next_update(&self, debug_name: &'static str, u: impl FnOnce() + Send + 'static) {
1186 self.run_hn_once(hn_once!(|_| {
1187 UPDATES.once_update(debug_name, u);
1188 }))
1189 .perm();
1190 }
1191
1192 fn push_handler(
1193 entries: &mut Vec<UpdateHandler>,
1194 is_preview: bool,
1195 mut handler: Handler<UpdateArgs>,
1196 force_once: bool,
1197 ) -> OnUpdateHandle {
1198 let (handle_owner, handle) = OnUpdateHandle::new();
1199 entries.push(UpdateHandler {
1200 handle: handle_owner,
1201 count: 0,
1202 handler: Box::new(move |args, handle| {
1203 handler.app_event(handle.clone_boxed(), is_preview, args);
1204 if force_once {
1205 handle.unsubscribe();
1206 }
1207 }),
1208 });
1209 handle
1210 }
1211
1212 pub(crate) fn on_pre_updates(&self) {
1213 let _s = tracing::trace_span!("UPDATES.on_pre_updates");
1214 let mut handlers = mem::take(UPDATES_SV.write().pre_handlers.get_mut());
1215 Self::retain_updates(&mut handlers);
1216
1217 let mut u = UPDATES_SV.write();
1218 handlers.append(u.pre_handlers.get_mut());
1219 *u.pre_handlers.get_mut() = handlers;
1220 }
1221
1222 pub(crate) fn on_updates(&self) {
1223 let _s = tracing::trace_span!("UPDATES.on_updates");
1224 let mut handlers = mem::take(UPDATES_SV.write().pos_handlers.get_mut());
1225 Self::retain_updates(&mut handlers);
1226
1227 let mut u = UPDATES_SV.write();
1228 handlers.append(u.pos_handlers.get_mut());
1229 *u.pos_handlers.get_mut() = handlers;
1230 }
1231
1232 fn retain_updates(handlers: &mut Vec<UpdateHandler>) {
1233 handlers.retain_mut(|e| {
1234 !e.handle.is_dropped() && {
1235 e.count = e.count.wrapping_add(1);
1236 (e.handler)(&UpdateArgs { count: e.count }, &e.handle.weak_handle());
1237 !e.handle.is_dropped()
1238 }
1239 });
1240 }
1241
1242 pub(super) fn take_update(&self) -> (bool, WidgetUpdates) {
1244 let mut u = UPDATES_SV.write();
1245
1246 let ext = u.update_ext.contains(UpdateFlags::UPDATE);
1247 u.update_ext.remove(UpdateFlags::UPDATE);
1248
1249 (
1250 ext,
1251 WidgetUpdates {
1252 delivery_list: mem::take(&mut u.update_widgets),
1253 },
1254 )
1255 }
1256
1257 pub(super) fn take_info(&self) -> (bool, InfoUpdates) {
1259 let mut u = UPDATES_SV.write();
1260
1261 let ext = u.update_ext.contains(UpdateFlags::INFO);
1262 u.update_ext.remove(UpdateFlags::INFO);
1263
1264 (
1265 ext,
1266 InfoUpdates {
1267 delivery_list: mem::take(&mut u.info_widgets),
1268 },
1269 )
1270 }
1271
1272 pub(super) fn take_layout(&self) -> (bool, LayoutUpdates) {
1274 let mut u = UPDATES_SV.write();
1275
1276 let ext = u.update_ext.contains(UpdateFlags::LAYOUT);
1277 u.update_ext.remove(UpdateFlags::LAYOUT);
1278
1279 (
1280 ext,
1281 LayoutUpdates {
1282 delivery_list: mem::take(&mut u.layout_widgets),
1283 },
1284 )
1285 }
1286
1287 pub(super) fn take_render(&self) -> (bool, RenderUpdates, RenderUpdates) {
1289 let mut u = UPDATES_SV.write();
1290
1291 let ext = u.update_ext.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1292 u.update_ext.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1293
1294 (
1295 ext,
1296 RenderUpdates {
1297 delivery_list: mem::take(&mut u.render_widgets),
1298 },
1299 RenderUpdates {
1300 delivery_list: mem::take(&mut u.render_update_widgets),
1301 },
1302 )
1303 }
1304}
1305
1306app_local! {
1307 static UPDATES_SV: UpdatesService = UpdatesService::new();
1308}
1309struct UpdatesService {
1310 event_sender: Option<AppEventSender>,
1311
1312 update_ext: UpdateFlags,
1313 update_widgets: UpdateDeliveryList,
1314 info_widgets: UpdateDeliveryList,
1315 layout_widgets: UpdateDeliveryList,
1316 render_widgets: UpdateDeliveryList,
1317 render_update_widgets: UpdateDeliveryList,
1318
1319 pre_handlers: Mutex<Vec<UpdateHandler>>,
1320 pos_handlers: Mutex<Vec<UpdateHandler>>,
1321
1322 app_is_awake: bool,
1323 awake_pending: bool,
1324}
1325impl UpdatesService {
1326 fn new() -> Self {
1327 Self {
1328 event_sender: None,
1329 update_ext: UpdateFlags::empty(),
1330 update_widgets: UpdateDeliveryList::new(),
1331 info_widgets: UpdateDeliveryList::new(),
1332 layout_widgets: UpdateDeliveryList::new(),
1333 render_widgets: UpdateDeliveryList::new(),
1334 render_update_widgets: UpdateDeliveryList::new(),
1335
1336 pre_handlers: Mutex::new(vec![]),
1337 pos_handlers: Mutex::new(vec![]),
1338
1339 app_is_awake: false,
1340 awake_pending: false,
1341 }
1342 }
1343
1344 fn send_awake(&mut self) {
1345 if !self.app_is_awake && !self.awake_pending {
1346 self.awake_pending = true;
1347 match self.event_sender.as_ref() {
1348 Some(s) => {
1349 if let Err(ChannelError::Disconnected { .. }) = s.send_update_app() {
1350 tracing::debug!("no app connected to update");
1351 }
1352 }
1353 None => {
1354 tracing::debug!("no app connected yet to update");
1355 }
1356 }
1357 }
1358 }
1359
1360 fn app_awake(&mut self, wake: bool) {
1361 self.awake_pending = false;
1362 self.app_is_awake = wake;
1363 }
1364}
1365
1366#[non_exhaustive]
1370#[derive(Default)]
1371pub struct ContextUpdates {
1372 pub update: bool,
1377
1378 pub info: bool,
1383
1384 pub layout: bool,
1389
1390 pub render: bool,
1395
1396 pub update_widgets: WidgetUpdates,
1400
1401 pub info_widgets: InfoUpdates,
1405
1406 pub layout_widgets: LayoutUpdates,
1410
1411 pub render_widgets: RenderUpdates,
1415
1416 pub render_update_widgets: RenderUpdates,
1420}
1421
1422impl fmt::Debug for ContextUpdates {
1423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1424 if f.alternate() {
1425 f.debug_struct("ContextUpdates")
1426 .field("update", &self.update)
1427 .field("info", &self.info)
1428 .field("layout", &self.layout)
1429 .field("render", &self.render)
1430 .field("update_widgets", &self.update_widgets)
1431 .field("info_widgets", &self.info_widgets)
1432 .field("layout_widgets", &self.layout_widgets)
1433 .field("render_widgets", &self.render_widgets)
1434 .field("render_update_widgets", &self.render_update_widgets)
1435 .finish()
1436 } else {
1437 write!(f, "ContextUpdates: ")?;
1438 let mut sep = "";
1439 if self.update {
1440 write!(f, "{sep}update")?;
1441 sep = ", ";
1442 }
1443 if self.info {
1444 write!(f, "{sep}info")?;
1445 sep = ", ";
1446 }
1447 if self.layout {
1448 write!(f, "{sep}layout")?;
1449 sep = ", ";
1450 }
1451 if self.render {
1452 write!(f, "{sep}render")?;
1453 sep = ", ";
1454 }
1455 if sep.is_empty() {
1456 write!(f, "<none>")?;
1457 }
1458 Ok(())
1459 }
1460 }
1461}
1462impl ContextUpdates {
1463 pub fn has_updates(&self) -> bool {
1465 self.update || self.info || self.layout || self.render
1466 }
1467}
1468impl std::ops::BitOrAssign for ContextUpdates {
1469 fn bitor_assign(&mut self, rhs: Self) {
1470 self.update |= rhs.update;
1471 self.update_widgets.extend(rhs.update_widgets);
1472 self.info |= rhs.info;
1473 self.info_widgets.extend(rhs.info_widgets);
1474 self.layout |= rhs.layout;
1475 self.layout_widgets.extend(rhs.layout_widgets);
1476 self.render |= rhs.render;
1477 self.render_widgets.extend(rhs.render_widgets);
1478 self.render_update_widgets.extend(rhs.render_update_widgets);
1479 }
1480}
1481impl std::ops::BitOr for ContextUpdates {
1482 type Output = Self;
1483
1484 fn bitor(mut self, rhs: Self) -> Self {
1485 self |= rhs;
1486 self
1487 }
1488}
1489
1490bitflags::bitflags! {
1491 #[derive(Clone, Copy, Debug, bytemuck::NoUninit)]
1492 #[repr(transparent)]
1493 pub(crate) struct UpdateFlags: u8 {
1494 const REINIT = 0b1000_0000;
1495 const INFO = 0b0001_0000;
1496 const UPDATE = 0b0000_0001;
1497 const LAYOUT = 0b0000_0010;
1498 const RENDER = 0b0000_0100;
1499 const RENDER_UPDATE = 0b0000_1000;
1500 }
1501}
1502
1503#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1508#[repr(transparent)]
1509#[must_use = "dropping the handle unsubscribes update handler"]
1510pub struct OnUpdateHandle(Handle<()>);
1511impl OnUpdateHandle {
1512 fn new() -> (HandleOwner<()>, OnUpdateHandle) {
1513 let (owner, handle) = Handle::new(());
1514 (owner, OnUpdateHandle(handle))
1515 }
1516
1517 pub fn dummy() -> Self {
1521 OnUpdateHandle(Handle::dummy(()))
1522 }
1523
1524 pub fn perm(self) {
1528 self.0.perm();
1529 }
1530
1531 pub fn is_permanent(&self) -> bool {
1535 self.0.is_permanent()
1536 }
1537
1538 pub fn unsubscribe(self) {
1540 self.0.force_drop()
1541 }
1542
1543 pub fn is_unsubscribed(&self) -> bool {
1547 self.0.is_dropped()
1548 }
1549
1550 pub fn downgrade(&self) -> WeakOnUpdateHandle {
1552 WeakOnUpdateHandle(self.0.downgrade())
1553 }
1554}
1555
1556#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1558pub struct WeakOnUpdateHandle(WeakHandle<()>);
1559impl WeakOnUpdateHandle {
1560 pub fn new() -> Self {
1562 Self(WeakHandle::new())
1563 }
1564
1565 pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1567 self.0.upgrade().map(OnUpdateHandle)
1568 }
1569}
1570
1571#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1573pub enum UpdateOp {
1574 Update,
1584 Info,
1591 Layout,
1597 Render,
1603 RenderUpdate,
1612}
1613
1614#[derive(Debug, Clone, Copy)]
1616#[non_exhaustive]
1617pub struct UpdateArgs {
1618 pub count: usize,
1620}
1621
1622struct UpdateHandler {
1623 handle: HandleOwner<()>,
1624 count: usize,
1625 handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1626}