Skip to content

Commit bf44e6a

Browse files
[osx] Use NSTrackingInVisibleRect for mouse movement tracking (#21996)
* [osx] Use NSTrackingInVisibleRect for tracking mouse movement * nit: comment * Update native/Avalonia.Native/src/OSX/AvnView.mm Co-authored-by: Max Katz <maxkatz6@outlook.com> --------- Co-authored-by: Max Katz <maxkatz6@outlook.com>
1 parent 5d25bd6 commit bf44e6a

1 file changed

Lines changed: 25 additions & 18 deletions

File tree

native/Avalonia.Native/src/OSX/AvnView.mm

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,17 @@ -(AvnView*) initWithParent: (TopLevelImpl*) parent
8080
[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
8181

8282
_parent = parent;
83-
_area = nullptr;
83+
84+
// NSTrackingInVisibleRect makes AppKit follow the visible bounds of the view.
85+
// Because of this, the tracking area does not need to change on resize.
86+
// Do not remove and add the area again on each live-resize tick.
87+
// If you do, AppKit queues synthetic enter and exit events with stale locations.
88+
// These events corrupt the pointer position after a resize and force it to the top left.
89+
NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved |
90+
NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag | NSTrackingInVisibleRect;
91+
_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:options owner:self userInfo:nullptr];
92+
[self addTrackingArea:_area];
93+
8494
_lastPixelSize.Height = 100;
8595
_lastPixelSize.Width = 100;
8696
[self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]];
@@ -128,25 +138,12 @@ -(void)setFrameSize:(NSSize)newSize
128138
{
129139
[super setFrameSize:newSize];
130140

131-
if(_area != nullptr)
132-
{
133-
[self removeTrackingArea:_area];
134-
_area = nullptr;
135-
}
136-
137141
auto parent = _parent.tryGet();
138142
if (parent == nullptr)
139143
{
140144
return;
141145
}
142146

143-
NSRect rect = NSZeroRect;
144-
rect.size = newSize;
145-
146-
NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag;
147-
_area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr];
148-
[self addTrackingArea:_area];
149-
150147
parent->UpdateCursor();
151148

152149
auto fsize = [self convertSizeToBacking: [self frame].size];
@@ -258,8 +255,12 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
258255
return;
259256
}
260257

261-
NSPoint eventLocation = [event locationInWindow];
262-
258+
// AppKit synthesizes enter and exit events for the tracked geometry.
259+
// They can have stale locations. Use the current pointer location instead.
260+
NSPoint eventLocation = event.type == NSEventTypeMouseEntered || event.type == NSEventTypeMouseExited
261+
? [[self window] mouseLocationOutsideOfEventStream]
262+
: [event locationInWindow];
263+
263264
auto viewLocation = [self convertPoint:NSMakePoint(0, 0) toView:nil];
264265

265266
auto localPoint = NSMakePoint(eventLocation.x - viewLocation.x, viewLocation.y - eventLocation.y);
@@ -392,7 +393,10 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
392393
parent->TopLevelEvents->RawMouseEvent(type, pointerType, timestamp, modifiers, point, delta, pressure, xTilt, yTilt);
393394
}
394395

395-
[super mouseMoved:event];
396+
// This handler is shared by all mouse event types. Only real mouse-moved
397+
// events must continue up the responder chain as mouseMoved:
398+
if (event.type == NSEventTypeMouseMoved)
399+
[super mouseMoved:event];
396400
}
397401

398402
- (BOOL) resignFirstResponder
@@ -560,7 +564,10 @@ - (void)swipeWithEvent:(NSEvent *)event
560564

561565
- (void)mouseEntered:(NSEvent *)event
562566
{
563-
[self mouseEvent:event withType:Move];
567+
// If the pointer is not inside the view, the enter event is false. Ignore it.
568+
NSPoint location = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil];
569+
if (NSPointInRect(location, self.bounds))
570+
[self mouseEvent:event withType:Move];
564571
[super mouseEntered:event];
565572
}
566573

0 commit comments

Comments
 (0)