Fix two mouse event bugs (#2835)

Mikayla Maki created

This PR fixes two bugs we discovered in Zed's mouse event handling while
investigating an interesting and mysterious bug we we were seeing, where
spurious `MouseMoved` events would continuously be dispatched after
control-clicking.

Release Notes:

- Fixed a rendering glitch that could occur after control-clicking
certain elements.

Change summary

crates/gpui/src/app/window.rs          | 13 +++++++++----
crates/gpui/src/platform/mac/window.rs |  5 ++++-
crates/gpui/src/scene/mouse_region.rs  |  2 +-
3 files changed, 14 insertions(+), 6 deletions(-)

Detailed changes

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

@@ -52,8 +52,8 @@ pub struct Window {
     cursor_regions: Vec<CursorRegion>,
     mouse_regions: Vec<(MouseRegion, usize)>,
     last_mouse_moved_event: Option<Event>,
-    pub(crate) hovered_region_ids: HashSet<MouseRegionId>,
-    pub(crate) clicked_region_ids: HashSet<MouseRegionId>,
+    pub(crate) hovered_region_ids: Vec<MouseRegionId>,
+    pub(crate) clicked_region_ids: Vec<MouseRegionId>,
     pub(crate) clicked_region: Option<(MouseRegionId, MouseButton)>,
     mouse_position: Vector2F,
     text_layout_cache: TextLayoutCache,
@@ -678,6 +678,7 @@ impl<'a> WindowContext<'a> {
                     let mut highest_z_index = None;
                     let mouse_position = self.window.mouse_position.clone();
                     let window = &mut *self.window;
+                    let prev_hovered_regions = mem::take(&mut window.hovered_region_ids);
                     for (region, z_index) in window.mouse_regions.iter().rev() {
                         // Allow mouse regions to appear transparent to hovers
                         if !region.hoverable {
@@ -696,7 +697,11 @@ impl<'a> WindowContext<'a> {
                         // highest_z_index is set.
                         if contains_mouse && z_index == highest_z_index.unwrap() {
                             //Ensure that hover entrance events aren't sent twice
-                            if window.hovered_region_ids.insert(region.id()) {
+                            if let Err(ix) = window.hovered_region_ids.binary_search(&region.id()) {
+                                window.hovered_region_ids.insert(ix, region.id());
+                            }
+                            // window.hovered_region_ids.insert(region.id());
+                            if !prev_hovered_regions.contains(&region.id()) {
                                 valid_regions.push(region.clone());
                                 if region.notify_on_hover {
                                     notified_views.insert(region.id().view_id());
@@ -704,7 +709,7 @@ impl<'a> WindowContext<'a> {
                             }
                         } else {
                             // Ensure that hover exit events aren't sent twice
-                            if window.hovered_region_ids.remove(&region.id()) {
+                            if prev_hovered_regions.contains(&region.id()) {
                                 valid_regions.push(region.clone());
                                 if region.notify_on_hover {
                                     notified_views.insert(region.id().view_id());

crates/gpui/src/platform/mac/window.rs 🔗

@@ -1087,7 +1087,10 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
                 button: MouseButton::Left,
                 modifiers: Modifiers { ctrl: true, .. },
                 ..
-            }) => return,
+            }) => {
+                window_state_borrow.synthetic_drag_counter += 1;
+                return;
+            }
 
             _ => None,
         };

crates/gpui/src/scene/mouse_region.rs 🔗

@@ -177,7 +177,7 @@ impl MouseRegion {
     }
 }
 
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
 pub struct MouseRegionId {
     view_id: usize,
     tag: TypeId,