gpui: Fix bug on `on_hover` callbacks (#46371) (cherry-pick to stable) (#46831)

zed-zippy[bot] and Danilo Leal created

Cherry-pick of #46371 to stable

----
Tackling this as I noticed a bug in the agent panel where the button to
delete a thread, which appeared only on hover, stopped showing up. PRs
#43324 and #45437 fixed stuff in applying hover styles through
`.hover()` but broke the `.on_hover()` callback. Problem was that both
methods were sharing the same `element_state.hover_state` but running at
different phases. The solution here was to add a new independent state
field for the hover listener (`hover_listener_state`) while the hover
style method keeps using `hover_state`.

Release Notes:

- Agent: Fixed a bug where the button to delete a thread stopped showing
up.

Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>

Change summary

crates/gpui/src/elements/div.rs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

Detailed changes

crates/gpui/src/elements/div.rs 🔗

@@ -2177,8 +2177,8 @@ impl Interactivity {
                 if phase == DispatchPhase::Capture && hovered != was_hovered {
                     if let Some(hover_state) = &hover_state {
                         hover_state.borrow_mut().element = hovered;
+                        cx.notify(current_view);
                     }
-                    cx.notify(current_view);
                 }
             });
         }
@@ -2377,7 +2377,7 @@ impl Interactivity {
             if let Some(hover_listener) = self.hover_listener.take() {
                 let hitbox = hitbox.clone();
                 let was_hovered = element_state
-                    .hover_state
+                    .hover_listener_state
                     .get_or_insert_with(Default::default)
                     .clone();
                 let has_mouse_down = element_state
@@ -2394,8 +2394,8 @@ impl Interactivity {
                         && hitbox.is_hovered(window);
                     let mut was_hovered = was_hovered.borrow_mut();
 
-                    if is_hovered != was_hovered.element {
-                        was_hovered.element = is_hovered;
+                    if is_hovered != *was_hovered {
+                        *was_hovered = is_hovered;
                         drop(was_hovered);
 
                         hover_listener(&is_hovered, window, cx);
@@ -2727,6 +2727,7 @@ pub struct InteractiveElementState {
     pub(crate) focus_handle: Option<FocusHandle>,
     pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
     pub(crate) hover_state: Option<Rc<RefCell<ElementHoverState>>>,
+    pub(crate) hover_listener_state: Option<Rc<RefCell<bool>>>,
     pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
     pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
     pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,