@@ -155,9 +155,11 @@ impl Element for AnyView {
let layout_id = window.request_layout(root_style, None, cx);
(layout_id, None)
} else {
- let mut element = (self.render)(self, window, cx);
- let layout_id = element.request_layout(window, cx);
- (layout_id, Some(element))
+ window.with_rendered_view(self.entity_id(), |window| {
+ let mut element = (self.render)(self, window, cx);
+ let layout_id = element.request_layout(window, cx);
+ (layout_id, Some(element))
+ })
}
}
@@ -197,12 +199,16 @@ impl Element for AnyView {
let refreshing = mem::replace(&mut window.refreshing, true);
let prepaint_start = window.prepaint_index();
- let (mut element, accessed_entities) = cx.detect_accessed_entities(|cx| {
- let mut element = (self.render)(self, window, cx);
- element.layout_as_root(bounds.size.into(), window, cx);
- element.prepaint_at(bounds.origin, window, cx);
- element
- });
+ let (mut element, accessed_entities) =
+ window.with_rendered_view(self.entity_id(), |window| {
+ cx.detect_accessed_entities(|cx| {
+ let mut element = (self.render)(self, window, cx);
+ element.layout_as_root(bounds.size.into(), window, cx);
+ element.prepaint_at(bounds.origin, window, cx);
+ element
+ })
+ });
+
let prepaint_end = window.prepaint_index();
window.refreshing = refreshing;
@@ -223,7 +229,10 @@ impl Element for AnyView {
)
} else {
let mut element = element.take().unwrap();
- element.prepaint(window, cx);
+ window.with_rendered_view(self.entity_id(), |window| {
+ element.prepaint(window, cx);
+ });
+
Some(element)
}
}
@@ -247,7 +256,9 @@ impl Element for AnyView {
if let Some(element) = element {
let refreshing = mem::replace(&mut window.refreshing, true);
- element.paint(window, cx);
+ window.with_rendered_view(self.entity_id(), |window| {
+ element.paint(window, cx);
+ });
window.refreshing = refreshing;
} else {
window.reuse_paint(element_state.paint_range.clone());
@@ -612,6 +612,7 @@ pub struct Window {
pub(crate) root: Option<AnyView>,
pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
+ pub(crate) rendered_entity_stack: Vec<EntityId>,
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
pub(crate) element_opacity: Option<f32>,
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
@@ -895,6 +896,7 @@ impl Window {
root: None,
element_id_stack: SmallVec::default(),
text_style_stack: Vec::new(),
+ rendered_entity_stack: Vec::new(),
element_offset_stack: Vec::new(),
content_mask_stack: Vec::new(),
element_opacity: None,
@@ -971,27 +973,6 @@ impl ContentMask<Pixels> {
}
impl Window {
- /// Indicate that a view has changed, which will invoke any observers and also mark the window as dirty.
- /// If this view or any of its ancestors are *cached*, notifying it will cause it or its ancestors to be redrawn.
- /// Note that this method will always cause a redraw, the entire window is refreshed if view_id is None.
- pub(crate) fn notify(
- &mut self,
- notify_effect: bool,
- entity_id: Option<EntityId>,
- cx: &mut App,
- ) {
- let Some(view_id) = entity_id else {
- self.refresh();
- return;
- };
-
- self.mark_view_dirty(view_id);
-
- if notify_effect {
- self.invalidator.invalidate_view(view_id, cx);
- }
- }
-
fn mark_view_dirty(&mut self, view_id: EntityId) {
// Mark ancestor views as dirty. If already in the `dirty_views` set, then all its ancestors
// should already be dirty.
@@ -1300,8 +1281,8 @@ impl Window {
///
/// If called from within a view, it will notify that view on the next frame. Otherwise, it will refresh the entire window.
pub fn request_animation_frame(&self) {
- let parent_id = self.parent_view_id();
- self.on_next_frame(move |window, cx| window.notify(true, parent_id, cx));
+ let entity = self.current_view();
+ self.on_next_frame(move |_, cx| cx.notify(entity));
}
/// Spawn the future returned by the given closure on the application thread pool.
@@ -1534,6 +1515,7 @@ impl Window {
pub fn draw(&mut self, cx: &mut App) {
self.invalidate_entities();
cx.entities.clear_accessed();
+ debug_assert!(self.rendered_entity_stack.is_empty());
self.invalidator.set_dirty(false);
self.requested_autoscroll = None;
@@ -1596,6 +1578,7 @@ impl Window {
.retain(&(), |listener| listener(&event, self, cx));
}
+ debug_assert!(self.rendered_entity_stack.is_empty());
self.record_entities_accessed(cx);
self.reset_cursor_style(cx);
self.refreshing = false;
@@ -2074,14 +2057,14 @@ impl Window {
let (task, is_first) = cx.fetch_asset::<A>(source);
task.clone().now_or_never().or_else(|| {
if is_first {
- let parent_id = self.parent_view_id();
+ let entity = self.current_view();
self.spawn(cx, {
let task = task.clone();
|mut cx| async move {
task.await;
- cx.on_next_frame(move |window, cx| {
- window.notify(true, parent_id, cx);
+ cx.on_next_frame(move |_, cx| {
+ cx.notify(entity);
});
}
})
@@ -2690,12 +2673,12 @@ impl Window {
Ok(())
}
- #[must_use]
/// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
/// layout is being requested, along with the layout ids of any children. This method is called during
/// calls to the [`Element::request_layout`] trait method and enables any element to participate in layout.
///
/// This method should only be called as part of the request_layout or prepaint phase of element drawing.
+ #[must_use]
pub fn request_layout(
&mut self,
style: Style,
@@ -2826,9 +2809,21 @@ impl Window {
self.next_frame.dispatch_tree.set_view_id(view_id);
}
- /// Get the last view id for the current element
- pub fn parent_view_id(&self) -> Option<EntityId> {
- self.next_frame.dispatch_tree.parent_view_id()
+ /// Get the entity ID for the currently rendering view
+ pub fn current_view(&self) -> EntityId {
+ self.invalidator.debug_assert_paint_or_prepaint();
+ self.rendered_entity_stack.last().copied().unwrap()
+ }
+
+ pub(crate) fn with_rendered_view<R>(
+ &mut self,
+ id: EntityId,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ self.rendered_entity_stack.push(id);
+ let result = f(self);
+ self.rendered_entity_stack.pop();
+ result
}
/// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the