Automatically reset cursor style when hit test changes (cherry-pick #9289) (#9322)

gcp-cherry-pick-bot[bot] , Antonio Scandurra , and Nathan Sobo created

Cherry-picked Automatically reset cursor style when hit test changes
(#9289)

Release Notes:

- N/A

Co-authored-by: Nathan Sobo <nathan@zed.dev>

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Nathan Sobo <nathan@zed.dev>

Change summary

crates/gpui/src/window.rs            | 38 ++++++++++++++++-------------
crates/gpui/src/window/element_cx.rs |  2 
crates/workspace/src/pane_group.rs   |  4 ---
3 files changed, 22 insertions(+), 22 deletions(-)

Detailed changes

crates/gpui/src/window.rs 🔗

@@ -956,12 +956,6 @@ impl<'a> WindowContext<'a> {
         self.window.next_frame.focus = self.window.focus;
         self.window.next_frame.window_active = self.window.active.get();
 
-        // Set the cursor only if we're the active window.
-        if self.is_window_active() {
-            let cursor_style = self.compute_cursor_style().unwrap_or(CursorStyle::Arrow);
-            self.platform.set_cursor_style(cursor_style);
-        }
-
         // Register requested input handler with the platform window.
         if let Some(input_handler) = self.window.next_frame.input_handlers.pop() {
             self.window
@@ -1017,6 +1011,8 @@ impl<'a> WindowContext<'a> {
                 .clone()
                 .retain(&(), |listener| listener(&event, self));
         }
+
+        self.reset_cursor_style();
         self.window.refreshing = false;
         self.window.draw_phase = DrawPhase::None;
         self.window.needs_present.set(true);
@@ -1031,16 +1027,20 @@ impl<'a> WindowContext<'a> {
         profiling::finish_frame!();
     }
 
-    fn compute_cursor_style(&mut self) -> Option<CursorStyle> {
-        // TODO: maybe we should have a HashMap keyed by HitboxId.
-        let request = self
-            .window
-            .next_frame
-            .cursor_styles
-            .iter()
-            .rev()
-            .find(|request| request.hitbox_id.is_hovered(self))?;
-        Some(request.style)
+    fn reset_cursor_style(&self) {
+        // Set the cursor only if we're the active window.
+        if self.is_window_active() {
+            let style = self
+                .window
+                .rendered_frame
+                .cursor_styles
+                .iter()
+                .rev()
+                .find(|request| request.hitbox_id.is_hovered(self))
+                .map(|request| request.style)
+                .unwrap_or(CursorStyle::Arrow);
+            self.platform.set_cursor_style(style);
+        }
     }
 
     /// Dispatch a given keystroke as though the user had typed it.
@@ -1175,7 +1175,11 @@ impl<'a> WindowContext<'a> {
     }
 
     fn dispatch_mouse_event(&mut self, event: &dyn Any) {
-        self.window.mouse_hit_test = self.window.rendered_frame.hit_test(self.mouse_position());
+        let hit_test = self.window.rendered_frame.hit_test(self.mouse_position());
+        if hit_test != self.window.mouse_hit_test {
+            self.window.mouse_hit_test = hit_test;
+            self.reset_cursor_style();
+        }
 
         let mut mouse_listeners = mem::take(&mut self.window.rendered_frame.mouse_listeners);
         self.with_element_context(|cx| {

crates/gpui/src/window/element_cx.rs 🔗

@@ -79,7 +79,7 @@ impl Hitbox {
     }
 }
 
-#[derive(Default)]
+#[derive(Default, Eq, PartialEq)]
 pub(crate) struct HitTest(SmallVec<[HitboxId; 8]>);
 
 pub(crate) struct DeferredDraw {

crates/workspace/src/pane_group.rs 🔗

@@ -941,8 +941,6 @@ mod element {
                         let flexes = self.flexes.clone();
                         let child_bounds = child.bounds;
                         let axis = self.axis;
-                        let handle_hitbox = handle.hitbox.clone();
-                        let was_hovered = handle_hitbox.is_hovered(cx);
                         move |e: &MouseMoveEvent, phase, cx| {
                             let dragged_handle = dragged_handle.borrow();
                             if phase.bubble() {
@@ -957,8 +955,6 @@ mod element {
                                         workspace.clone(),
                                         cx,
                                     )
-                                } else if was_hovered != handle_hitbox.is_hovered(cx) {
-                                    cx.refresh();
                                 }
                             }
                         }