Switch PopUp windows to use the NSTrackingArea API and add support for the mouseExited event
Co-authored-by: Antonio <antonio@zed.dev>
This commit is contained in:
parent
8af1294ba5
commit
310d867aab
5 changed files with 75 additions and 11 deletions
|
@ -178,6 +178,21 @@ impl MouseMovedEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct MouseExitedEvent {
|
||||||
|
pub position: Vector2F,
|
||||||
|
pub pressed_button: Option<MouseButton>,
|
||||||
|
pub modifiers: Modifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for MouseExitedEvent {
|
||||||
|
type Target = Modifiers;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
KeyDown(KeyDownEvent),
|
KeyDown(KeyDownEvent),
|
||||||
|
@ -186,6 +201,7 @@ pub enum Event {
|
||||||
MouseDown(MouseButtonEvent),
|
MouseDown(MouseButtonEvent),
|
||||||
MouseUp(MouseButtonEvent),
|
MouseUp(MouseButtonEvent),
|
||||||
MouseMoved(MouseMovedEvent),
|
MouseMoved(MouseMovedEvent),
|
||||||
|
MouseExited(MouseExitedEvent),
|
||||||
ScrollWheel(ScrollWheelEvent),
|
ScrollWheel(ScrollWheelEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +213,7 @@ impl Event {
|
||||||
Event::ModifiersChanged { .. } => None,
|
Event::ModifiersChanged { .. } => None,
|
||||||
Event::MouseDown(event) | Event::MouseUp(event) => Some(event.position),
|
Event::MouseDown(event) | Event::MouseUp(event) => Some(event.position),
|
||||||
Event::MouseMoved(event) => Some(event.position),
|
Event::MouseMoved(event) => Some(event.position),
|
||||||
|
Event::MouseExited(event) => Some(event.position),
|
||||||
Event::ScrollWheel(event) => Some(event.position),
|
Event::ScrollWheel(event) => Some(event.position),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
keymap_matcher::Keystroke,
|
keymap_matcher::Keystroke,
|
||||||
platform::{Event, NavigationDirection},
|
platform::{Event, NavigationDirection},
|
||||||
KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
|
KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
|
||||||
MouseMovedEvent, ScrollDelta, ScrollWheelEvent, TouchPhase,
|
MouseExitedEvent, MouseMovedEvent, ScrollDelta, ScrollWheelEvent, TouchPhase,
|
||||||
};
|
};
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
|
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
|
||||||
|
@ -221,6 +221,16 @@ impl Event {
|
||||||
modifiers: read_modifiers(native_event),
|
modifiers: read_modifiers(native_event),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
NSEventType::NSMouseExited => window_height.map(|window_height| {
|
||||||
|
Self::MouseExited(MouseExitedEvent {
|
||||||
|
position: vec2f(
|
||||||
|
native_event.locationInWindow().x as f32,
|
||||||
|
window_height - native_event.locationInWindow().y as f32,
|
||||||
|
),
|
||||||
|
pressed_button: None,
|
||||||
|
modifiers: read_modifiers(native_event),
|
||||||
|
})
|
||||||
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,14 @@ const NSNormalWindowLevel: NSInteger = 0;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
const NSPopUpWindowLevel: NSInteger = 101;
|
const NSPopUpWindowLevel: NSInteger = 101;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
|
const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
const NSTrackingMouseMoved: NSUInteger = 0x02;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
const NSTrackingActiveAlways: NSUInteger = 0x80;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
const NSTrackingInVisibleRect: NSUInteger = 0x200;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4;
|
const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -164,6 +172,10 @@ unsafe fn build_classes() {
|
||||||
sel!(mouseMoved:),
|
sel!(mouseMoved:),
|
||||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(mouseExited:),
|
||||||
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseDragged:),
|
sel!(mouseDragged:),
|
||||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
|
@ -470,8 +482,6 @@ impl Window {
|
||||||
native_window.setTitlebarAppearsTransparent_(YES);
|
native_window.setTitlebarAppearsTransparent_(YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
native_window.setAcceptsMouseMovedEvents_(YES);
|
|
||||||
|
|
||||||
native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable);
|
native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable);
|
||||||
native_view.setWantsBestResolutionOpenGLSurface_(YES);
|
native_view.setWantsBestResolutionOpenGLSurface_(YES);
|
||||||
|
|
||||||
|
@ -494,8 +504,25 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
match options.kind {
|
match options.kind {
|
||||||
WindowKind::Normal => native_window.setLevel_(NSNormalWindowLevel),
|
WindowKind::Normal => {
|
||||||
|
native_window.setLevel_(NSNormalWindowLevel);
|
||||||
|
native_window.setAcceptsMouseMovedEvents_(YES);
|
||||||
|
}
|
||||||
WindowKind::PopUp => {
|
WindowKind::PopUp => {
|
||||||
|
// Use a tracking area to allow receiving MouseMoved events even when
|
||||||
|
// the window or application aren't active, which is often the case
|
||||||
|
// e.g. for notification windows.
|
||||||
|
let tracking_area: id = msg_send![class!(NSTrackingArea), alloc];
|
||||||
|
let _: () = msg_send![
|
||||||
|
tracking_area,
|
||||||
|
initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.))
|
||||||
|
options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect
|
||||||
|
owner: native_view
|
||||||
|
userInfo: nil
|
||||||
|
];
|
||||||
|
let _: () =
|
||||||
|
msg_send![native_view, addTrackingArea: tracking_area.autorelease()];
|
||||||
|
|
||||||
native_window.setLevel_(NSPopUpWindowLevel);
|
native_window.setLevel_(NSPopUpWindowLevel);
|
||||||
let _: () = msg_send![
|
let _: () = msg_send![
|
||||||
native_window,
|
native_window,
|
||||||
|
@ -965,7 +992,6 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||||
|
|
||||||
let window_height = window_state_borrow.content_size().y();
|
let window_height = window_state_borrow.content_size().y();
|
||||||
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
||||||
|
|
||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
match &event {
|
match &event {
|
||||||
Event::MouseMoved(
|
Event::MouseMoved(
|
||||||
|
|
|
@ -360,6 +360,21 @@ impl Presenter {
|
||||||
self.last_mouse_moved_event = Some(event.clone());
|
self.last_mouse_moved_event = Some(event.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Event::MouseExited(event) => {
|
||||||
|
// When the platform sends a MouseExited event, synthesize
|
||||||
|
// a MouseMoved event whose position is outside the window's
|
||||||
|
// bounds so that hover and cursor state can be updated.
|
||||||
|
return self.dispatch_event(
|
||||||
|
Event::MouseMoved(MouseMovedEvent {
|
||||||
|
position: event.position,
|
||||||
|
pressed_button: event.pressed_button,
|
||||||
|
modifiers: event.modifiers,
|
||||||
|
}),
|
||||||
|
event_reused,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Event::ScrollWheel(e) => mouse_events.push(MouseEvent::ScrollWheel(MouseScrollWheel {
|
Event::ScrollWheel(e) => mouse_events.push(MouseEvent::ScrollWheel(MouseScrollWheel {
|
||||||
region: Default::default(),
|
region: Default::default(),
|
||||||
platform_event: e.clone(),
|
platform_event: e.clone(),
|
||||||
|
|
|
@ -31,18 +31,14 @@ use futures::{
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions,
|
actions,
|
||||||
color::Color,
|
|
||||||
elements::*,
|
elements::*,
|
||||||
geometry::{
|
geometry::vector::Vector2F,
|
||||||
rect::RectF,
|
|
||||||
vector::{vec2f, Vector2F},
|
|
||||||
},
|
|
||||||
impl_actions, impl_internal_actions,
|
impl_actions, impl_internal_actions,
|
||||||
keymap_matcher::KeymapContext,
|
keymap_matcher::KeymapContext,
|
||||||
platform::{CursorStyle, WindowOptions},
|
platform::{CursorStyle, WindowOptions},
|
||||||
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
|
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
|
||||||
MouseButton, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, SizeConstraint,
|
MouseButton, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, SizeConstraint,
|
||||||
Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowBounds, WindowKind,
|
Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
|
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue