git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit03ed660b0643d6e0257994a9d71235368971fb27
parentb6eaacf051
authorLucas Galante <[email protected]>
date2026-07-12 16:54
refactor(widget): fold zero-override container hooks (6bc census round)

The ParametersBg deletion stranded child_added, children_cleared, and
layout_children_ctx at zero overrides — deleted with their Adapted
call sites (the calls were provable no-ops). RFC records the
remaining deliberate stored-pointer state: the registry, TI's
ControlPanel.children, and the tick-refreshed parent copies in
MenuBar/StatusBar/Dropdown (endgame: snapshot the read data, not the
pointer).

 docs/rfc-core-rebuild.md | 15 ++++++++++++++-
 src/widget/model.rs      | 21 ++-------------------
 2 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/docs/rfc-core-rebuild.md b/docs/rfc-core-rebuild.md
index c093e5d..d5ed05b 100644
--- a/docs/rfc-core-rebuild.md
+++ b/docs/rfc-core-rebuild.md
@@ -1808,9 +1808,22 @@ Constraint respected: **each crate still builds standalone** — the new core is
        with the `Element` endgame rather than warranting a standalone
        signature sweep.
     4. **`propagate_event(event, root: WidgetId)`** + the app dispatch
-       loops off `as_ptr_mut` (the big app sweep).
+       loops off `as_ptr_mut` (the big app sweep). NOTE from the
+       slice-3 census: propagate roots are live borrows at call time —
+       this slice is API honesty, not a UAF fix; weigh folding it into
+       the endgame instead of touching ~200 app sites twice.
     5. window_runner render plumbing + remaining `as_ptr` sites; then
        the `Element` + `Adapted` endgame (own design pass).
+    Stored-pointer state remaining after slices 1–3, all deliberate:
+    the `WidgetTree` registry; TI's `ControlPanel.children`; and the
+    tick-refreshed parent copies in MenuBar/StatusBar/Dropdown models
+    (`parent_changed`/`tracked_parent` — written each tick by the
+    re-parenting pattern with the live host pointer, read in ctx-less
+    popover-direction/corner-radius math). Endgame option for the
+    parent copies: snapshot the *data* read through them (parent rect,
+    radius, is-Ramp flag) at re-parent time instead of the pointer —
+    same refresh cadence, no deref of potentially-dead memory; watch
+    the one-frame rect lag on resize if reads move to snapshots.
 
 Order rationale: each phase is independently valuable and reversible, and no phase requires the
 next to compile. Phase 0 can land immediately regardless of the rest.
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 751dc41..0b87c04 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -132,13 +132,6 @@ pub trait Layout {
         Vec::new()
     }
 
-    /// A child was attached through `Element::add_child` (the adapter has already tree-linked
-    /// it and set its parent).
-    fn child_added(&mut self, _child: *mut (dyn Element + 'static)) {}
-
-    /// All children were detached through `Element::clear_children`.
-    fn children_cleared(&mut self) {}
-
     /// The parent pointer changed through `Element::set_parent` (containers that clamp their
     /// rect to the parent's keep a copy — the tree default needs a ctx that `set_rect` lacks).
     fn parent_changed(&mut self, _parent: Option<*mut (dyn Element + 'static)>) {}
@@ -155,10 +148,6 @@ pub trait Layout {
     /// ButtonStrip) parent it back to the host so legacy parent-chain styling walks work.
     fn arrange_children(&mut self, _rect: Rect, _host: *mut (dyn Element + 'static)) {}
 
-    /// Recursive child layout for the `Element::layout` pass (this one has ctx). Called after
-    /// the adapter has measured and placed the container itself, only while visible.
-    fn layout_children_ctx(&mut self, _rect: Rect, _ctx: &mut UiContext) {}
-
     /// Per-child visibility policy for the adapter's subtree plumbing (Switcher exposes only
     /// the active child). Default: every child.
     fn child_visible(&self, _child: *mut (dyn Element + 'static)) -> bool {
@@ -922,18 +911,16 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
             ctx.register_widget(c_id, child);
             ctx.tree.link(p_id, c_id);
         }
-        // …plus, for containers, the legacy container extras: parent the child back (Layer,
-        // Switcher) and record it in the model's own Vec.
+        // …plus, for containers, the legacy container extra: parent the child back (Layer,
+        // Switcher). (The model-Vec record died with ParametersBg.children — zero overrides.)
         if Layout::has_container_children(&self.inner) {
             let self_ptr = self.as_ptr_mut();
             unsafe { (*child).set_parent(Some(self_ptr), ctx) };
-            Layout::child_added(&mut self.inner, child);
         }
     }
 
     fn clear_children(&mut self, ctx: &mut UiContext) {
         ctx.clear_children_ids(self.base.id());
-        Layout::children_cleared(&mut self.inner);
     }
 
     fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
@@ -995,10 +982,6 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         self.set_rect(origin.x, origin.y, size.width, size.height);
         let host_id = self.base.id();
         Layout::register_embedded_children(&mut self.inner, host_id, ctx);
-        if Layout::has_container_children(&self.inner) && self.visible {
-            let rect = self.content_rect();
-            Layout::layout_children_ctx(&mut self.inner, rect, ctx);
-        }
     }
 
     fn prepare_text(&mut self, fs: &mut glyphon::FontSystem) {