From b8ad3a56f745c927d05e8d3a40b4531ab6467504 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Sun, 29 Dec 2024 22:39:19 +0200 Subject: [PATCH] Invalidate tooltips when mouse leaves element's hitbox (cherry-pick #22488) (#22489) Cherry-picked Invalidate tooltips when mouse leaves element's hitbox (#22488) Closes https://github.com/zed-industries/zed/issues/21657 In case of the task rerun button tooltip from https://github.com/zed-industries/zed/blob/f6dabadaf79bd29c89c8d55a1e9f1d33236f736e/crates/terminal_view/src/terminal_view.rs#L1051-L1070 , the actual button element is not styled as invisible, only its parent. Zed won't render such element since it's parent is hidden, but will consider it "visible" all the time its `paint` is called, spawning a task with the delay, that will create the tooltip: https://github.com/zed-industries/zed/blob/f6dabadaf79bd29c89c8d55a1e9f1d33236f736e/crates/gpui/src/elements/div.rs#L1949-L1959 When the parent is hidden, the child won't be painted anymore, and no mouse listeners will be able to detect this fact and hide the tooltip. Hence, check such cases separately, during `prepaint`, and invalidate the tooltips that are not valid anymore. We cannot use `hitbox.is_hovered(cx)` as it's not really hovered during prepaint, so a mouse position check is used instead. Release Notes: - Fixed tooltips getting stuck Co-authored-by: Kirill Bulatov --- crates/gpui/src/elements/div.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 3f826ca00790bea20cce77fb54f8a6e2ee91e91f..28c0969498cbc6fc75f42fabcaa250481b29d249 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -1417,6 +1417,19 @@ impl Interactivity { None }; + let invalidate_tooltip = hitbox + .as_ref() + .map_or(true, |hitbox| !hitbox.bounds.contains(&cx.mouse_position())); + if invalidate_tooltip { + if let Some(active_tooltip) = element_state + .as_ref() + .and_then(|state| state.active_tooltip.as_ref()) + { + *active_tooltip.borrow_mut() = None; + self.tooltip_id = None; + } + } + let scroll_offset = self.clamp_scroll_position(bounds, &style, cx); let result = f(&style, scroll_offset, hitbox, cx); (result, element_state)