First this is not a tutorial for NSPopover . Just fix for an issue.
Apple introduced NSPopover in OS X v10.7
The NSPopover
class provides a means to display additional content related to existing content on the screen. The popover is positioned relative to the existing content.
An anchor is used to express the relation between these two units of content. A popover has an appearance that specifies its visual characteristics, as well as a behavior that determines which user interactions will cause the popover to close. …….
But it seems Apple never intended for the NSPopover to be used in a NSStatusBar menu item. Those are the little menu icons in you menu bar that when you click show you info or perform an action. This is probably why Apple has not fixed the bugs when using a popover in this way.
THE Problem
The main problem I was having was my popover was not closing when I clicked else where if I had not clicked on the popover first. I.e click the menu status item. The popover pops out. click somewhere else ( another app, finder). The popover stays open. If I then click the popover and then elsewhere it would close ok. Because it had picked up in becoming the key window after the second click.
This behaviour I discovered from a post on blog.brokenrobotllc.com was partly due to me subclassing NSWindow so the popover could become key and allow the content to become first responder. i.e the textfield. But when the popover closes we want it to revert back to it’s original behaviour. This subclass was done because in my popover is a text field. Which if the NSWindow does not become key, you will not be able to interact with it. Thats one of the other problems.
The Epiphany
As alway these things happen while in the shower and this was no exception !
The simple thought was this: ” well clearly I have to click on the popover to activate it so it can become key again ”
When put like that the fix becomes simple. I need to put in some code that when I click the menu status item. The App (popover) is activated.
I first used an NSApplescript. But then remembered I could simply use:
[[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
[iframe /blogR/activateApp.html 700 400]
And it works.. well for me at least.
Oh man – this worked!!
Swift version:
NSApplication.shared.activate(ignoringOtherApps: true)
holy crap thank u
Thank you so much!!!!!!
I just posted a new post showing how to close the popovers when entering both Mission Control or LaunchPad.
Ok so it seems it stays around when either Mission Control or LaunchPad are entered and exited. I am not sure this is a problem though. It would be interesting to see if I can figure a solution not sure I will be able to though. Where do you envisage this behaviour being an issue because if you jump to another app or space it closes..
I forgot to say thanks for your solution too btw, helped me out.
Hmm, I never been into Mission Control while a popover was showing. I will try it in a bit and get back to.
Have you managed to figure out a way to dismiss the popover when the user enters Mission Control? NSPopoverBehaviorTransient doesn’t seem to do its job in this case.
Hi Melzar,
I have not had a problem with this at all since I implemented it in the AppI wrote it for.
I did just do a test and found that I do not have any issue with delay. What I did notice was if I click outside the popover but very very close to it. It does not close. this is because I am clicking inside of its drop shadow which I guess is still part of it. But I would never click this close to it (millimetres) normally..
It worked well! Thanks!
But, I found there are some problems. according to [NSApp activateIgnoringOtherApps] documents:
there may be a time lag before the application activates – you should not assume the application will be active immediately after sending this message.
ok, when i sent the message, then i switch to other programs at once, [NSApp activateIgnoringOtherApps] don’t take effect. The problem you describe above has emerged again
Hi Max,
Glad I could help. 🙂
Worked me for too! Thanks!