Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSViewController slow to register mouse events?

Tags:

macos

swift

I've been working on a small image uploading menubar app for OS X. I've created custom NSView subclass for the uploaded items.

Here's what it looks like by default:

Ravioli - not hovered

Mouse events are handled by the view's NSViewController in the following way:

import Cocoa

class MenuItemController: NSViewController {

    private var trackingArea: NSTrackingArea?

    override func mouseEntered(theEvent: NSEvent) {
        if let v = self.view as? MenuItemView {
            v.shouldHighlight = true
            v.needsDisplay = true
        }
    }

    override func mouseExited(theEvent: NSEvent) {
        if let v = self.view as? MenuItemView {
            v.shouldHighlight = false
            v.needsDisplay = true
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        if (trackingArea == nil) {
            trackingArea = NSTrackingArea(rect: self.view.bounds, options: [.ActiveAlways, .MouseEnteredAndExited], owner: self, userInfo: nil)
            self.view.addTrackingArea(trackingArea!)
        }

        /* rest of the code... */
    }

}

It works fine until I move my cursor fast over the items. It seems like the mouseExited() event is not called, and the view remains with a blue background (mouse is actually on the Quit button):

Ravioli bug

I also tried moving the mouse handling into the NSView, but with same results. I appreciate any input! Thanks!

like image 780
Zoltan Avatar asked Jan 11 '16 20:01

Zoltan


1 Answers

In my opinion, Apple has had bugs in this area.

Assuming you update your tracking area according to apple docs, adding this additional fix might fix your problem... it fixes it for me in many cases. I verify in mouseMoved / mouseEntered routine that the mouse cursor is still within my views frame, and if not, call mouseExited: myself.

- (void) adjustTrackingArea
{   
   if ( trackingArea )
   {
      [self removeTrackingArea:trackingArea];
      [trackingArea release];
   }

   // determine the tracking options
   NSTrackingAreaOptions trackingOptions = // NSTrackingEnabledDuringMouseDrag | // don't track during drag
   NSTrackingMouseMoved |
   NSTrackingMouseEnteredAndExited |
   //NSTrackingActiveInActiveApp | NSTrackingActiveInKeyWindow | NSTrackingActiveWhenFirstResponder |
   NSTrackingActiveAlways;
   NSRect theRect = [self visibleRect];
   trackingArea = [[NSTrackingArea alloc]
                   initWithRect: theRect
                   options: trackingOptions
                   owner: self
                   userInfo: nil];
   [self addTrackingArea:trackingArea];
}


- (void)resetCursorRects
{
   [self adjustTrackingArea];
}
- (void)mouseEntered:(NSEvent *)ev
{
   [self setNeedsDisplay:YES];
   // make sure current mouse cursor location remains under the mouse cursor
   NSPoint cursorPt = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:NULL];

   // apple bug!!!
   //NSPoint cursorPt2 = [self convertPointFromBase:[ev locationInWindow]]; 
   //if ( cursorPt.x != cursorPt2.x )
   //   NSLog( @"hello old cursorPt" );
   NSRect r = [self frame];
   if ( cursorPt.x > NSMaxX( r ) || cursorPt.x < 0 )
   {
      [self mouseExited:ev];
      //cursorPt.x = [self convertPointFromBase:[ev locationInWindow]];
      //if ( cursorPt.x > NSMaxX( r ) || cursorPt.x < r.origin.x )
      return;
   }

   ... your custom stuff here ...
}

- (void)mouseExited:(NSEvent *)theEvent
{
   if ( isTrackingCursor == NO )
      return;

   [[NSCursor arrowCursor] set];
   isTrackingCursor = NO;
   [self setNeedsDisplay:YES];   
}

- (void)mouseMoved:(NSEvent *)theEvent
{
   [self mouseEntered:theEvent];
}
like image 199
Keith Knauber Avatar answered Dec 29 '22 15:12

Keith Knauber