Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T06:45:27.849Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

deferred.rs

207 lines · 6.9 KB · rust
1use crate::{
2    AnyElement, App, Bounds, Element, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
3    Pixels, Window,
4};
5
6/// Builds a `Deferred` element, which delays the layout and paint of its child.
7pub fn deferred(child: impl IntoElement) -> Deferred {
8    Deferred {
9        child: Some(child.into_any_element()),
10        priority: 0,
11    }
12}
13
14/// An element which delays the painting of its child until after all of
15/// its ancestors, while keeping its layout as part of the current element tree.
16pub struct Deferred {
17    child: Option<AnyElement>,
18    priority: usize,
19}
20
21impl Deferred {
22    /// Sets the `priority` value of the `deferred` element, which
23    /// determines the drawing order relative to other deferred elements,
24    /// with higher values being drawn on top.
25    pub fn with_priority(mut self, priority: usize) -> Self {
26        self.priority = priority;
27        self
28    }
29}
30
31impl Element for Deferred {
32    type RequestLayoutState = ();
33    type PrepaintState = ();
34
35    fn id(&self) -> Option<crate::ElementId> {
36        None
37    }
38
39    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
40        None
41    }
42
43    fn request_layout(
44        &mut self,
45        _id: Option<&GlobalElementId>,
46        _inspector_id: Option<&InspectorElementId>,
47        window: &mut Window,
48        cx: &mut App,
49    ) -> (LayoutId, ()) {
50        let layout_id = self.child.as_mut().unwrap().request_layout(window, cx);
51        (layout_id, ())
52    }
53
54    fn prepaint(
55        &mut self,
56        _id: Option<&GlobalElementId>,
57        _inspector_id: Option<&InspectorElementId>,
58        _bounds: Bounds<Pixels>,
59        _request_layout: &mut Self::RequestLayoutState,
60        window: &mut Window,
61        _cx: &mut App,
62    ) {
63        let child = self.child.take().unwrap();
64        let element_offset = window.element_offset();
65        window.defer_draw(child, element_offset, self.priority, None)
66    }
67
68    fn paint(
69        &mut self,
70        _id: Option<&GlobalElementId>,
71        _inspector_id: Option<&InspectorElementId>,
72        _bounds: Bounds<Pixels>,
73        _request_layout: &mut Self::RequestLayoutState,
74        _prepaint: &mut Self::PrepaintState,
75        _window: &mut Window,
76        _cx: &mut App,
77    ) {
78    }
79}
80
81impl IntoElement for Deferred {
82    type Element = Self;
83
84    fn into_element(self) -> Self::Element {
85        self
86    }
87}
88
89impl Deferred {
90    /// Sets a priority for the element. A higher priority conceptually means painting the element
91    /// on top of deferred draws with a lower priority (i.e. closer to the viewer).
92    pub fn priority(mut self, priority: usize) -> Self {
93        self.priority = priority;
94        self
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use crate::{
101        Context, Entity, StyleRefinement, TestAppContext, Window, anchored, deferred, div, point,
102        prelude::*, px, size,
103    };
104
105    /// A stand-in for a dock panel hosting a popover (deferred draw) whose
106    /// content opens another popover (a deferred draw created while
107    /// prepainting the first one's content).
108    struct PanelView;
109
110    impl Render for PanelView {
111        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
112            div().key_context("Panel").size_full().child(
113                deferred(
114                    anchored().position(point(px(10.), px(10.))).child(
115                        div().key_context("Popover").w(px(200.)).h(px(200.)).child(
116                            deferred(
117                                anchored().position(point(px(30.), px(30.))).child(
118                                    div()
119                                        .key_context("NestedMenu")
120                                        .debug_selector(|| "NESTED_MENU".into())
121                                        .w(px(50.))
122                                        .h(px(50.)),
123                                ),
124                            )
125                            .with_priority(2),
126                        ),
127                    ),
128                )
129                .with_priority(1),
130            )
131        }
132    }
133
134    struct RootView {
135        panel: Entity<PanelView>,
136    }
137
138    impl Render for RootView {
139        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
140            div().key_context("Root").size_full().child(
141                self.panel
142                    .clone()
143                    .cached(StyleRefinement::default().size_full()),
144            )
145        }
146    }
147
148    /// Regression test for a crash with nested deferred draws (e.g. a popover
149    /// menu inside a popover hosted by a cached dock panel). Prepaint indices
150    /// recorded during the deferred draw rounds must index the same
151    /// `deferred_draws` vector that `reuse_prepaint` slices on the next frame;
152    /// previously they were measured against a transient per-round vector, so
153    /// reusing the panel's subtree grafted the wrong deferred draws and
154    /// panicked in the dispatch tree.
155    #[gpui::test]
156    fn test_nested_deferred_draws_with_reused_views(cx: &mut TestAppContext) {
157        let window = cx.open_window(size(px(800.), px(600.)), |_, cx| {
158            let panel = cx.new(|_| PanelView);
159            RootView { panel }
160        });
161        cx.run_until_parked();
162
163        let menu_bounds = window
164            .update(cx, |_, window, _| {
165                window
166                    .rendered_frame
167                    .debug_bounds
168                    .get("NESTED_MENU")
169                    .copied()
170            })
171            .unwrap()
172            .expect("NESTED_MENU debug bounds not found");
173        assert_eq!(menu_bounds.size, size(px(50.), px(50.)));
174
175        // Re-render only the root view; the panel is cached, so its subtree -
176        // including both deferred draw records - is reused from the previous
177        // frame.
178        window.update(cx, |_, _, cx| cx.notify()).unwrap();
179        cx.run_until_parked();
180
181        // Reuse the subtree a second time, exercising ranges that were
182        // themselves recorded during a reused frame.
183        window.update(cx, |_, _, cx| cx.notify()).unwrap();
184        cx.run_until_parked();
185
186        // Re-render the panel itself again to prove the popovers still draw.
187        window
188            .update(cx, |root, _, cx| {
189                root.panel.update(cx, |_, cx| cx.notify());
190            })
191            .unwrap();
192        cx.run_until_parked();
193
194        window
195            .update(cx, |_, window, _| {
196                assert_eq!(window.rendered_frame.deferred_draws.len(), 2);
197                assert!(
198                    window
199                        .rendered_frame
200                        .debug_bounds
201                        .contains_key("NESTED_MENU")
202                );
203            })
204            .unwrap();
205    }
206}
207
Served at tenant.openagents/omega Member data and write actions are omitted.