Merge branch 'main' into add-cursor-position-to-feedback-editor

Joseph Lyons created

Change summary

crates/gpui/src/app.rs                        |  9 +++++
crates/gpui/src/platform.rs                   |  1 
crates/gpui/src/platform/mac/event.rs         |  2 +
crates/gpui/src/platform/mac/platform.rs      |  4 +
crates/gpui/src/platform/mac/status_item.rs   |  4 ++
crates/gpui/src/platform/mac/window.rs        | 37 +++++++++++++++++++-
crates/gpui/src/platform/test.rs              |  4 ++
crates/gpui/src/presenter.rs                  | 11 +++++
crates/gpui/src/presenter/event_dispatcher.rs |  1 
crates/workspace/src/workspace.rs             |  1 
10 files changed, 68 insertions(+), 6 deletions(-)

Detailed changes

crates/gpui/src/app.rs 🔗

@@ -21,6 +21,7 @@ use std::{
 use anyhow::{anyhow, Context, Result};
 use lazy_static::lazy_static;
 use parking_lot::Mutex;
+use pathfinder_geometry::vector::Vector2F;
 use postage::oneshot;
 use smallvec::SmallVec;
 use smol::prelude::*;
@@ -865,6 +866,14 @@ impl MutableAppContext {
         }
     }
 
+    pub fn is_topmost_window_for_position(&self, window_id: usize, position: Vector2F) -> bool {
+        self.presenters_and_platform_windows
+            .get(&window_id)
+            .map_or(false, |(_, window)| {
+                window.is_topmost_for_position(position)
+            })
+    }
+
     pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
         self.cx.windows.keys().cloned()
     }

crates/gpui/src/platform.rs 🔗

@@ -145,6 +145,7 @@ pub trait Window {
     fn present_scene(&mut self, scene: Scene);
     fn appearance(&self) -> Appearance;
     fn on_appearance_changed(&mut self, callback: Box<dyn FnMut()>);
+    fn is_topmost_for_position(&self, position: Vector2F) -> bool;
 }
 
 #[derive(Debug)]

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

@@ -125,6 +125,7 @@ impl Event {
                         button,
                         position: vec2f(
                             native_event.locationInWindow().x as f32,
+                            // MacOS screen coordinates are relative to bottom left
                             window_height - native_event.locationInWindow().y as f32,
                         ),
                         modifiers: read_modifiers(native_event),
@@ -150,6 +151,7 @@ impl Event {
                         button,
                         position: vec2f(
                             native_event.locationInWindow().x as f32,
+                            // MacOS view coordinates are relative to bottom left
                             window_height - native_event.locationInWindow().y as f32,
                         ),
                         modifiers: read_modifiers(native_event),

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

@@ -699,7 +699,9 @@ impl platform::Platform for MacPlatform {
         unsafe {
             let cursor: id = match style {
                 CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor],
-                CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor],
+                CursorStyle::ResizeLeftRight => {
+                    msg_send![class!(NSCursor), resizeLeftRightCursor]
+                }
                 CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor],
                 CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
                 CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor],

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

@@ -258,6 +258,10 @@ impl platform::Window for StatusItem {
             crate::Appearance::from_native(appearance)
         }
     }
+
+    fn is_topmost_for_position(&self, _: Vector2F) -> bool {
+        true
+    }
 }
 
 impl StatusItemState {

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

@@ -17,9 +17,9 @@ use crate::{
 use block::ConcreteBlock;
 use cocoa::{
     appkit::{
-        CGPoint, NSApplication, NSBackingStoreBuffered, NSScreen, NSView, NSViewHeightSizable,
-        NSViewWidthSizable, NSWindow, NSWindowButton, NSWindowCollectionBehavior,
-        NSWindowStyleMask,
+        CGFloat, CGPoint, NSApplication, NSBackingStoreBuffered, NSScreen, NSView,
+        NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowButton,
+        NSWindowCollectionBehavior, NSWindowStyleMask,
     },
     base::{id, nil},
     foundation::{
@@ -755,6 +755,37 @@ impl platform::Window for Window {
     fn on_appearance_changed(&mut self, callback: Box<dyn FnMut()>) {
         self.0.borrow_mut().appearance_changed_callback = Some(callback);
     }
+
+    fn is_topmost_for_position(&self, position: Vector2F) -> bool {
+        let window_bounds = self.bounds();
+        let self_borrow = self.0.borrow();
+        let self_id = self_borrow.id;
+
+        unsafe {
+            let app = NSApplication::sharedApplication(nil);
+
+            // Convert back to bottom-left coordinates
+            let point = NSPoint::new(
+                position.x() as CGFloat,
+                (window_bounds.height() - position.y()) as CGFloat,
+            );
+
+            let screen_point: NSPoint =
+                msg_send![self_borrow.native_window, convertPointToScreen: point];
+            let window_number: NSInteger = msg_send![class!(NSWindow), windowNumberAtPoint:screen_point belowWindowWithWindowNumber:0];
+            let top_most_window: id = msg_send![app, windowWithWindowNumber: window_number];
+
+            let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS];
+            let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS];
+            if is_panel == YES || is_window == YES {
+                let topmost_window_id = get_window_state(&*top_most_window).borrow().id;
+                topmost_window_id == self_id
+            } else {
+                // Someone else's window is on top
+                false
+            }
+        }
+    }
 }
 
 impl WindowState {

crates/gpui/src/platform/test.rs 🔗

@@ -332,6 +332,10 @@ impl super::Window for Window {
     }
 
     fn on_appearance_changed(&mut self, _: Box<dyn FnMut()>) {}
+
+    fn is_topmost_for_position(&self, _position: Vector2F) -> bool {
+        true
+    }
 }
 
 pub fn platform() -> Platform {

crates/gpui/src/presenter.rs 🔗

@@ -316,7 +316,16 @@ impl Presenter {
                         break;
                     }
                 }
-                cx.platform().set_cursor_style(style_to_assign);
+
+                let t0 = std::time::Instant::now();
+                let is_topmost_window =
+                    cx.is_topmost_window_for_position(self.window_id, *position);
+                println!("is_topmost_window => {:?}", t0.elapsed());
+                if is_topmost_window {
+                    let t1 = std::time::Instant::now();
+                    cx.platform().set_cursor_style(style_to_assign);
+                    println!("set_cursor_style => {:?}", t1.elapsed());
+                }
 
                 if !event_reused {
                     if pressed_button.is_some() {