Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSTackingRect on a custom View in a NSMenuItem does not always fire a mouseExited event

I have subclassed NSView and create an NSTrackingArea using the following:

-(void)setUpTrackingArea
{
    if(trackingArea != nil)
    {
        [self removeTrackingArea:trackingArea];
    }

    int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag);
    trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] options:opts owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];

    NSLog(@"update tracking area %@", trackingArea);

    NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
    mouseLocation = [self convertPoint: mouseLocation   fromView: nil];

    if (NSPointInRect(mouseLocation, [self bounds]))
    {
        [self mouseEntered: nil];
    }
    else
    {
        [self mouseExited: nil];
    }

}

I am also overriding:

- (void)mouseEntered:(NSEvent *)theEvent
- (void)mouseExited:(NSEvent *)theEvent

to set a highlight property which then calls

[self setNeedsDisplay:YES];

which calls drawrect to highlight the menu view as you would expect a menu to.

The problem is the mouse exited event does not always seem to fire leaving some custom views highlighted after the mouse has moved away.

Any ideas what I am doing wrong?

I have created a demo project which presents this issue.

see https://github.com/antokne/APGCustomMenuItemView

Thants.

like image 529
Ants Avatar asked Oct 23 '13 03:10

Ants


1 Answers

I had the same problem some time ago; the reason was that as soon as you have a tracking area with both the "enter/exit" AND "always" options being set, it stops working reliably. My - admittedly very crude - solution was to create two tracking areas on top of each other like so:

NSTrackingArea *mouseOverTracker = [[NSTrackingArea alloc] initWithRect:self.view.bounds options:(NSTrackingActiveAlways|NSTrackingMouseMoved) owner:self userInfo:nil];
NSTrackingArea *mouseOverTracker2 = [[NSTrackingArea alloc] initWithRect:self.view.bounds options:(NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways) owner:self userInfo:nil];
[self.view addTrackingArea:mouseOverTracker];
[self.view addTrackingArea:mouseOverTracker2];

That worked for me.

Cheers!

like image 106
Thorsten Karrer Avatar answered Sep 28 '22 10:09

Thorsten Karrer