as I open the pop-up menu and move the mouse before that opened, MouseEntered Event and MouseExited Event are called when mouse moved.
The following trackingAreas options are inclued in the view in pop-up area.
- NSTrackingInVisibleRect, NSTrackingMouseEnteredAndExited, NSTrackingMouseMoved, NSTrackingActiveInKeyWindow
LocationInWindow of MouseExitedEvent seem to be incorrect.
This problems does not occur in the following cases.
- Do not move the mouse until the popup is fully opened.
- Left mouse button down on pop-up area.
- Move the mouse out of the pop-up area.
This issue occurs in Sonoma(MacOS14.0) and later.
I would like to know if this is a code issue or a bug in the OS Version.
AppDelegate.h
#import <Cocoa/Cocoa.h>
@interface ViewInPopup : NSView {
NSString* resultStr;
NSUInteger enteredCount;
NSPoint lastEnteredPos;
NSUInteger exitedCount;
NSPoint lastExitedPos;
NSUInteger movedCount;
NSPoint lastMovedPos;
NSTrackingArea* trackingArea;
}
@end
@interface AppDelegate : NSObject <NSApplicationDelegate> {
NSMenu* myMenu;
ViewInPopup* viewInPopup;
}
- (IBAction)onClickButton:(id)sender;
@end
AppDelegate.mm
#import "AppDelegate.h"
@interface ViewInPopup ()
- (void)showResult:(NSEvent*)event;
@end
@implementation ViewInPopup
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
[self setWantsLayer:TRUE];
[[self layer] setBackgroundColor:[NSColor redColor].CGColor];
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
[resultStr drawInRect:[self bounds] withAttributes:nil];
}
- (void)updateTrackingAreas
{
if (trackingArea) {
[self removeTrackingArea:trackingArea];
}
NSTrackingAreaOptions options = NSTrackingInVisibleRect | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow;
trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
[self addTrackingArea:trackingArea];
[super updateTrackingAreas];
}
- (void)mouseEntered:(NSEvent *)event
{
[self showResult:event];
[super mouseEntered:event];
}
- (void)mouseExited:(NSEvent *)event
{
[self showResult:event];
[super mouseExited:event];
}
- (void)mouseMoved:(NSEvent *)event
{
[self showResult:event];
[super mouseMoved:event];
}
- (void)showResult:(NSEvent*)event
{
NSString* eventTypeStr = @"";
switch (event.type) {
case NSEventTypeMouseEntered:
eventTypeStr = @"Entered";
[[self layer] setBackgroundColor:[NSColor redColor].CGColor];
if (enteredCount >= NSUIntegerMax) {
enteredCount = 0;
} else {
enteredCount++;
}
lastEnteredPos = event.locationInWindow;
break;
case NSEventTypeMouseExited:
eventTypeStr = @"Exited";
[[self layer] setBackgroundColor:[NSColor blueColor].CGColor];
if (exitedCount >= NSUIntegerMax) {
exitedCount = 0;
} else {
exitedCount++;
}
lastExitedPos = event.locationInWindow;
break;
case NSEventTypeMouseMoved:
eventTypeStr = @"Moved";
[[self layer] setBackgroundColor:[NSColor greenColor].CGColor];
if (movedCount >= NSUIntegerMax) {
movedCount = 0;
} else {
movedCount++;
}
lastMovedPos = event.locationInWindow;
break;
default:
return;
}
resultStr = [NSString stringWithFormat:@"LastEventType:%@\n\nEnteredCount:%ld\nLastEnteredPosition:(%f, %f)\n\nExitedCount:%ld\nLastExitedPosition:(%f %f)\n\nMovedCount:%ld\nLastMovedPosition:(%f, %f)", eventTypeStr, enteredCount, lastEnteredPos.x, lastEnteredPos.y, exitedCount, lastExitedPos.x, lastExitedPos.y, movedCount, lastMovedPos.x, lastMovedPos.y];
[self setNeedsDisplay:YES];
}
@end
@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
myMenu = [[NSMenu alloc] init];
NSMenuItem* item = [[NSMenuItem alloc] init];
[myMenu addItem:item];
viewInPopup = [[ViewInPopup alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)];
[item setView:viewInPopup];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}
- (IBAction)onClickButton:(id)sender
{
[myMenu popUpMenuPositioningItem:nil atLocation:NSZeroPoint inView:(NSView*)sender];
}
@end