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

Issue:
Cursor disapears in chromeless window example
#### Following these steps:

1 - Run the window example.
2 - Click "Chrome" button.
3- Move mouse pointer slowly from outside the window into the window from the top.

#### I saw this happen:

Cursor turns into resize then disappears.

#### I expected this to happen:

Cursor turn into resize then move.



Discussion / hints:
Problem caused because the title widget is inside the border, so the cursor does not leave the border, so the cursor binding for it is still active, so when the event handler in the example sets the cursor the border binding overrides the title.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef101e77f..a92db34ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,6 +69,8 @@ fn version_0_5() -> impl UiNode {
 * Add `ContextualizedVar::new_value`.
 * **Breaking** `SCROLL.scroll_*` methods now return contextual vars, not values.
 * Fix panic on window move in Wayland.
+* Fix minimize command removing maximized state from restore.
+* Fix issue when parent widget's cursor can override child's cursor when the parent cursor var updates.
 
 # 0.4.0
 
diff --git a/crates/zng-view/src/window.rs b/crates/zng-view/src/window.rs
index c02626129..60a40f16b 100644
--- a/crates/zng-view/src/window.rs
+++ b/crates/zng-view/src/window.rs
@@ -462,7 +462,9 @@ impl Window {
 
         win.set_enabled_buttons(cfg.enabled_buttons);
 
-        win.set_system_shutdown_warn(cfg.system_shutdown_warn);
+        if !cfg.system_shutdown_warn.is_empty() {
+            win.set_system_shutdown_warn(cfg.system_shutdown_warn);
+        }
 
         if win.ime_area.is_some() {
             win.window.set_ime_allowed(true);
diff --git a/crates/zng-wgt-input/src/misc.rs b/crates/zng-wgt-input/src/misc.rs
index dd68c4225..cc6a4026e 100644
--- a/crates/zng-wgt-input/src/misc.rs
+++ b/crates/zng-wgt-input/src/misc.rs
@@ -1,3 +1,8 @@
+use std::sync::{
+    atomic::{AtomicBool, Ordering},
+    Arc,
+};
+
 use zng_ext_input::mouse::{ClickMode, WidgetInfoBuilderMouseExt as _, MOUSE_HOVERED_EVENT};
 use zng_ext_window::WINDOW_Ext as _;
 use zng_wgt::prelude::*;
@@ -6,6 +11,10 @@ pub use zng_view_api::window::CursorIcon;
 
 pub use zng_ext_window::CursorImg;
 
+context_local! {
+    static CHILD_SETS: AtomicBool = AtomicBool::new(false);
+}
+
 /// Sets the [`CursorIcon`] displayed when hovering the widget.
 ///
 /// This cursor is only used if [`cursor_img`] is not set on the widget, or the cursor image cannot be shown.
@@ -19,19 +28,39 @@ pub use zng_ext_window::CursorImg;
 pub fn cursor(child: impl UiNode, cursor: impl IntoVar<Option<CursorIcon>>) -> impl UiNode {
     let cursor = cursor.into_var();
     let mut hovered_binding = None;
+    let mut child_sets_ctx = None::<Arc<AtomicBool>>;
 
-    match_node(child, move |_, op| {
-        let mut restore = false;
+    match_node(child, move |c, op| {
+        let mut unbind_restore = false;
         match op {
             UiNodeOp::Init => {
                 WIDGET.sub_event(&MOUSE_HOVERED_EVENT);
             }
             UiNodeOp::Deinit => {
-                restore = true;
+                unbind_restore = true;
+                child_sets_ctx = None;
             }
             UiNodeOp::Event { update } => {
                 if let Some(args) = MOUSE_HOVERED_EVENT.on(update) {
+                    let mut bind = false;
                     if args.is_over() {
+                        if child_sets_ctx.is_none() {
+                            child_sets_ctx = Some(Arc::new(AtomicBool::new(false)));
+                        }
+
+                        // if a child also sets cursor, it will flag our context.
+                        CHILD_SETS.with_context(&mut child_sets_ctx, || c.event(update));
+
+                        if !child_sets_ctx.as_ref().unwrap().swap(false, Ordering::Relaxed) {
+                            // no descendant sets cursor, it is ours.
+                            bind = true;
+                        }
+
+                        // flag parent context.
+                        CHILD_SETS.get().store(true, Ordering::Relaxed);
+                    }
+
+                    if bind {
                         if hovered_binding.is_none() {
                             // we are not already set, setup binding.
 
@@ -44,7 +73,7 @@ pub fn cursor(child: impl UiNode, cursor: impl IntoVar<Option<CursorIcon>>) -> i
                             hovered_binding = Some(cursor.bind(&c));
                         }
                     } else {
-                        restore = true;
+                        unbind_restore = true;
                     }
                 }
             }
@@ -52,7 +81,7 @@ pub fn cursor(child: impl UiNode, cursor: impl IntoVar<Option<CursorIcon>>) -> i
         }
 
         // restore to default, if not set to other value already
-        if restore && hovered_binding.is_some() {
+        if unbind_restore && hovered_binding.is_some() {
             hovered_binding = None;
             let value = cursor.get();
             WINDOW.vars().cursor().modify(move |c| {


Test patch: