I am working on a dockless application (LSUIElement true). The application pops up a menu when the user clicks on the corresponding NSStatusItem, or when a keyboard shortcut is used.
My problem is that all methods to pop up a menu programmatically hang whenever the user switches to another application (using ⌘-TAB) without dismissing the menu first. I have tried popUpMenuPositioningItem:atLocation:inView:, popUpContextMenu:withEvent:forView:, and the corresponding method on NSStatusItem (popUpStatusItemMenu:).
If the user dismisses the menu with the ESC key everything works fine, but if the user switches to a different application, the above-mentioned methods never return (they seem to run synchronously and return when the menu is dismissed). The application does not crash, and there are a couple of tricks to regain control (invoking exposé, or clicking on any NSStatusItem which pops up a menu).
The problem disappears if the application has a dock icon (i.e. setting LSUIElement to false).
This is the code popping up the menu when the keyboard shortcut is used:
[mainMenu popUpMenuPositioningItem:[mainMenu itemAtIndex:0]
atLocation:[NSEvent mouseLocation]
inView:nil];
And this is the code popping up the menu when the NSStatusItem is clicked:
- (void)mouseDown:(NSEvent *)event
{
[statusItem popUpStatusItemMenu:[statusItem menu]];
}
The mouseDown: method is in the custom NSView attached to the NSStatusItem.
Any idea on how to fix this?
Thanks for your help.
The problem is also linked to the application being activated (I use [NSApp activateIgnoringOtherApps:YES]; before showing the menu, or in some cases it is not possible to navigate the menu with the keyboard).
It appears that the problem is due to the application activation and popUpMenu happening in the same event cycle. I have found a workaround, described in more details in this post.
Is summary, you need to activate the application first (using [NSApp activateIgnoringOtherApps:YES];), and pop up the menu after, making sure this happens in a new event cycle: you can achieve this using a NSTimer to trigger the menu.
- (void) someMethod {
// Some code
[NSApp activateIgnoringOtherApps:YES];
[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(showMenu) userInfo:nil repeats:NO];
//Some other code
}
- (void) showMenu {
// This will show the menu at the current mouse position
[aMenu popUpMenuPositioningItem:[mainMenu itemAtIndex:0] atLocation:[NSEvent mouseLocation] inView:nil];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With