Skip to repository content207 lines · 6.9 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T06:45:27.849Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
deferred.rs
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