Repository: zng-ui/zng (language: rust)

Issue:
`WIDGET.reinit()` does not work in `Window!`
<!--
Please, make sure:

- The issue happens in the latest crate release or newer (master branch).
- The issue happens after `cargo update`.
-->

#### I tried this code:

```rust
Window! {   
    widget::on_deinit = hn!(|_| println!("Window! deinit"));
    widget::on_init = hn!(|_| println!("Window! init"));
    gesture::on_click = hn!(|_| WIDGET.reinit());
    
    child = Wgt! {
        widget::on_deinit = hn!(|_| println!("Container! deinit"));
        widget::on_init = hn!(|_| println!("Container! init"));
        gesture::on_click = hn!(|_| WIDGET.reinit());

        widget::background_color = colors::AZURE;
        layout::size = 50;
    };
    child_align = Align::CENTER;
}
```

#### Following these steps:

1 - Run.
2 - Click Window.
3 - Click Wgt.

#### I saw this happen:

Only Container! deinit/init events print.

#### I expected this to happen:

Both widgets print deinit/init.


Discussion / hints:

Fix patch:
diff --git a/crates/zng-app/src/widget.rs b/crates/zng-app/src/widget.rs
index e0b543f90..fa195f682 100644
--- a/crates/zng-app/src/widget.rs
+++ b/crates/zng-app/src/widget.rs
@@ -1111,7 +1111,7 @@ impl WIDGET {
                     // is at root, register `UPDATES`
                     UPDATES.update_flags_root(wgt_flags, window_id, ctx.id);
                     // some builders don't clear the root widget flags like they do for other widgets.
-                    ctx.flags.store(UpdateFlags::empty(), Relaxed);
+                    ctx.flags.store(wgt_flags & UpdateFlags::REINIT, Relaxed);
                 } else {
                     // used outside window
                     UPDATES.update_flags(wgt_flags, ctx.id);
diff --git a/crates/zng-ext-window/src/control.rs b/crates/zng-ext-window/src/control.rs
index 82b298f5b..f9959f356 100644
--- a/crates/zng-ext-window/src/control.rs
+++ b/crates/zng-ext-window/src/control.rs
@@ -1919,11 +1919,29 @@ impl ContentCtrl {
                 self.commands.update(&self.vars);
 
                 update_widgets.with_window(|| {
-                    WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
-                        update_widgets.with_widget(|| {
-                            self.root.update(update_widgets);
+                    if self.root_ctx.take_reinit() {
+                        // like WidgetBase, pending reinit cancels update
+                        WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+                            self.root.deinit();
+                            self.root.init();
                         });
-                    });
+                        let _ = self.root_ctx.take_reinit(); // ignore after init
+                    } else {
+                        // no pending reinit, can update
+                        WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+                            update_widgets.with_widget(|| {
+                                self.root.update(update_widgets);
+                            });
+                        });
+
+                        // update requested reinit
+                        if self.root_ctx.take_reinit() {
+                            WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+                                self.root.deinit();
+                                self.root.init();
+                            });
+                        }
+                    }
                 });
             }
 
@@ -1941,6 +1959,7 @@ impl ContentCtrl {
                     super::WINDOW_OPEN_EVENT.notify(super::WindowOpenArgs::now(WINDOW.id()));
                 });
                 self.init_state = InitState::Inited;
+                self.root_ctx.take_reinit(); // ignore reinit request (same as WidgetBase).
             }
         }
     }
@@ -1967,6 +1986,10 @@ impl ContentCtrl {
 
             WINDOWS.set_widget_tree(info.clone());
 
+            if self.root_ctx.is_pending_reinit() {
+                WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
+            }
+
             Some(info)
         } else {
             None
@@ -1993,11 +2016,26 @@ impl ContentCtrl {
                 return;
             }
 
+            if self.root_ctx.take_reinit() {
+                WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+                    self.root.deinit();
+                    self.root.init();
+                });
+                let _ = self.root_ctx.take_reinit(); // ignore after init
+            }
+
             WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
                 update.with_widget(|| {
                     self.root.event(update);
                 })
             });
+
+            if self.root_ctx.take_reinit() {
+                WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+                    self.root.deinit();
+                    self.root.init();
+                });
+            }
         });
     }
 
@@ -2041,7 +2079,7 @@ impl ContentCtrl {
 
         self.layout_pass = self.layout_pass.next();
 
-        WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
+        let final_size = WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
             let metrics = LayoutMetrics::new(scale_factor, size, root_font_size)
                 .with_screen_ppi(screen_ppi)
                 .with_direction(DIRECTION_VAR.get());
@@ -2071,7 +2109,13 @@ impl ContentCtrl {
 
                 final_size
             })
-        })
+        });
+
+        if self.root_ctx.is_pending_reinit() {
+            WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
+        }
+
+        final_size
     }
 
     pub fn render(
@@ -2110,6 +2154,10 @@ impl ContentCtrl {
                 frame.finalize(&WINDOW.info())
             });
 
+            if self.root_ctx.is_pending_reinit() {
+                WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
+            }
+
             self.clear_color = frame.clear_color;
 
             let capture = self.take_frame_capture();
@@ -2150,6 +2198,10 @@ impl ContentCtrl {
                 self.clear_color = c;
             }
 
+            if self.root_ctx.is_pending_reinit() {
+                WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
+            }
+
             let capture = self.take_frame_capture();
 
             if let Some(renderer) = renderer {


Test patch: