As of OS X 10.10 most of NSStatusItem has been deprecated in favour of the button
property, which consists of an NSStatusBarButton. It should work like a normal button but unfortunately the cell
and setCell
methods in NSStatusButton have also been deprecated. As a result of this I'm struggling to find a way to keep the button highlighted after it's clicked (Normally the button is highlighted on mouse down, and unhighlighted on mouse up. I want to keep it highlighted after mouse up).
Calling [NSStatusButton setHighlighted:]
in its action doesn't work because it seems to unhighlight itself once the mouse is up. On the other hand, using a delay to call it on the next loop i.e. [self performSelector: withDelay:]
causes the highlight to flash in a rather unsightly way. It works, but doesn't look nice.
Setting the button type to NSToggleButton
removes the highlight entirely and instead highlights the template image which was odd.
Those were the only methods I could think of. Is there anyway to override this NSButtonCell mouseUp behaviour?
TL;DR: Any
NSButton
instance (withNSImage
that hastemplate=YES
) insideNSStatusItem
property visually looks exactly likeNSStatusBarButton
. You can control theirhighlight
property as you want.If you want to control highlight of your
NSStatusItem
manually and at the same time get all appearance benefits from usingNSStatusBarButton
you can use slightly different approach. You can create your ownNSButton
instance which has its own propertyhighlight
that is completely under your control. Then you have to createNSImage
instance and set itstemplate
property toYES
. Then you have to add thisbutton
to[NSStatusItem view]
(yes, which issoftly deprecated
) or even as subview to system created[NSStatusItem button]
. After this you have to draw background ofNSStatusItem
manually with[NSStatusItem drawStatusBarBackgroundInRect:withHighlight:]
(which is also deprecated, oh).With this approach, you can combine full control of look and feel of your
NSStatusItem
and get automatic styling of button's image.If you schedule the highlighting of the button in for a subsequent execution on the main thread everything seems to work out. This does work on El Capitan as well.
This does work, but you might notice a little flicker due to the button state being changed from ON to OFF and then ON again. The OFF happens because of the popover display. So, to fix that, just move the appPopover.showRelativeToRect() call inside the dispatch_async() block, right after setting the button highlighted.
I added a subview to the status item, and inside that view I added event handlers for mouseDown etc. which called [[statusItem button] highlight:true]. As it turns out setHighlighted: doesn't do the same thing as highlight:.
EDIT: As of El Capitan this method no longer works, and neither does
statusItem.button.highlight = true
eitherSwift 3 version of Manfred Urban's answer. Works on El Capitan.
Don't forget to set the buttons highlight property to false again if appropriate.
One idea is swizzling
isHighlighted
ofNSStatusBarButtonCell
and return an arbitrary value. https://gist.github.com/questbeat/3244601c8dc779484076But the problem is whether Apple's review team allows this approach or not...
Luke’s answer is great. I’m just sharing my implementation based on that.