1
votes

I have a video playing app where an NSView is shown, tracked to the mouse coordinates, to show the time position when the user hovers over a certain area.

This works perfectly 70% of the time, however it frequently doesn't fire at all. The times when this is most likely to occur seem to be when bringing the mouse inside the view for the first time and after hovering the mouse outside of the area and then back inside again.

The code inside the NSView subclass is as follows:

- (void)viewDidMoveToWindow
{
    if ([self window]) {
        [self resetTrackingRect];
    }
}

- (void)clearTrackingRect
{
    if (rolloverTrackingRectTag > 0)
    {
        [self removeTrackingRect:rolloverTrackingRectTag];
        rolloverTrackingRectTag = 0;
    }
}

- (void)resetTrackingRect
{
    [self clearTrackingRect];
    rolloverTrackingRectTag = [self addTrackingRect:[self visibleRect]
                                          owner:self userData:NULL assumeInside:NO];
}

- (void)resetCursorRects
{
    [super resetCursorRects];
    [self resetTrackingRect];
}

- (void)mouseEntered:(NSEvent *)theEvent
{
    // Only ask for mouse move events when inside rect because they are expensive
    [[self window] setAcceptsMouseMovedEvents:YES];
    [[self window] makeFirstResponder:self];

    // Tells the observer to show the time view
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MWTimelineHover" object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:theEvent,@"event",nil]];
}

- (void)mouseExited:(NSEvent *)theEvent
{
    [[self window] setAcceptsMouseMovedEvents:NO];
    [[self window] resignFirstResponder];

    // Tells the observer to hide the time view
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MWTimelineHoverLeave" object:self];
}

- (void)mouseMoved:(NSEvent *)theEvent
{
    [super mouseMoved:theEvent];

    // Tells the observer to show the time view
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MWTimelineHover" object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:theEvent,@"event",nil]];
}

Note: on the occasions when it stalls, mouseExited is not called and the view has not lost firstResponder status. I am also not dragging the mouse, simply moving it normally.

1

1 Answers

3
votes

You need to use NSTrackingArea. Here is reference NSTrackingArea Class Reference.

- (void)commonInit {
    CGRect rect = CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height);
    NSTrackingAreaOptions options = NSTrackingActiveInKeyWindow | NSTrackingMouseMoved | NSTrackingInVisibleRect;
    _trackingArea = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nil];
    [self addTrackingArea:_trackingArea];
}

Hope it helps you.