Custom NSStatusItem and NSView not reliably receive NSTrackingEvents

I have an application only for the status bar in which I am trying to show a panel on mouseOver. I have a custom status element (and its associated view) that is connected and working, but the tracking rectangle only receives events for every dozens or so launches. It makes me think that a race condition is happening somewhere, but I can’t find it. In my view, the status bar position:

- (id)initWithStatusItem:(NSStatusItem *)statusItem { CGFloat itemWidth = [statusItem length]; CGFloat itemHeight = [[NSStatusBar systemStatusBar] thickness]; NSRect itemRect = NSMakeRect(0.0, 0.0, itemWidth, itemHeight); NSLog(@"itemRect: %@", NSStringFromRect(itemRect)); if ((self = [super initWithFrame:itemRect])) { _statusItem = statusItem; _statusItem.view = self; NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways; NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:itemRect options:options owner:self userInfo:nil]; [self addTrackingArea:trackingArea]; [self.window setIgnoresMouseEvents:NO]; [self.window setAcceptsMouseMovedEvents:YES]; self.wantsLayer = YES; } return self; } - (void)mouseEntered:(NSEvent *)theEvent { [[NSNotificationCenter defaultCenter] postNotificationName:UAStatusItemMouseEnteredNotification object:nil]; } - (void)mouseExited:(NSEvent *)theEvent { [[NSNotificationCenter defaultCenter] postNotificationName:UAStatusItemMouseExitedNotification object:nil]; } 

In most launches, the application does not respond to mouse tracking events, but each so often the mouseEntered: and mouseExited: called properly, they completely confuse me. What is going on here and what am I doing wrong?






EDIT 07/17/2012

I changed the code based on @Streams answer, but saw the same problem:

 - (id)initWithStatusItem:(NSStatusItem *)statusItem { CGFloat itemWidth = [statusItem length]; CGFloat itemHeight = [[NSStatusBar systemStatusBar] thickness]; NSRect itemRect = NSMakeRect(0.0, 0.0, itemWidth, itemHeight); NSLog(@"itemRect: %@", NSStringFromRect(itemRect)); if ((self = [super initWithFrame:itemRect])) { _statusItem = statusItem; _statusItem.view = self; [self updateTrackingAreas]; [self.window setIgnoresMouseEvents:NO]; [self.window setAcceptsMouseMovedEvents:YES]; self.wantsLayer = YES; } return self; } - (void)updateTrackingAreas { if (self.trackingArea) [self removeTrackingArea:self.trackingArea]; [super updateTrackingAreas]; self.trackingArea = [[NSTrackingArea alloc] initWithRect:CGRectZero options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways owner:self userInfo:nil]; [self addTrackingArea:self.trackingArea]; } 






EDIT 07/18/2012

Here is a simple example sample project that uses the well-known github project (written by @Stream) to show the problem. It cannot reliably receive mouseover events, if at all.

+2
source share
2 answers

I opened a DTS request for Apple to take a look at this. Here's the answer:

... you use full screen in Xcode when starting the application. I did not do this [before], but now I can reproduce the problem. From the fact that I can say this only when your application starts from full screen mode in Xcode. Your users will not run the application in this way. This is a problem with AppKit full screen mode, and not necessarily with code.

+2
source

I believe that you should only manage tracking areas in -[NSView updateTrackingAreas] . For instance:

 - (void)updateTrackingAreas { if (_trackingArea) { [self removeTrackingArea:_trackingArea]; } [super updateTrackingAreas]; NSTrackingAreaOptions options = (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways); _trackingArea = [[NSTrackingArea alloc] initWithRect:CGRectZero options:options owner:self userInfo:nil]; [self addTrackingArea:_trackingArea]; } 
0
source

All Articles