From 5ee06c30b56569ed3b273271baa1f3103180263a Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 02:28:49 -0400 Subject: [PATCH] Share held-root ancestor answers within committed geometry reads --- src/textual/_compositor.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 5460d60912..8dc03857de 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -1679,10 +1679,25 @@ def deferred_regions(self, roots: Iterable[Widget]) -> tuple[Region, ...]: return () regions: set[Region] = set() placed: set[Widget] = set() + # This synchronous read shares parent answers only for this invocation. + # Read the original parent path, including covers and virtual widgets; + # DOM child traversal is not equivalent to committed-map membership. + membership = {} for widget, geometry in self._published_map.items(): - members = roots.intersection(widget.walk_ancestors(with_self=True)) - if members: - placed.update(members) + path = [] + for ancestor in widget.walk_ancestors(with_self=True): + if ancestor in membership: + held = membership[ancestor] + break + path.append(ancestor) + else: + held = False + for ancestor in reversed(path): + if ancestor in roots: + placed.add(ancestor) + held = True + membership[ancestor] = held + if held: if region := geometry.visible_region.intersection(self.size.region): regions.add(region) for root in roots - placed: