Devapploper
Devapploper

Reputation: 6192

Call Action when NSStatusBarButton is right-clicked

I am searching for a way to detect whenever the NSStatusBarButton is right-clicked (using Swift) and call an action.

I am currently setting it up this way:

let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)

func applicationDidFinishLaunching(aNotification: NSNotification) {
    // Insert code here to initialize your application
    if let button = statusItem.button {
        button.image = NSImage(named: "myImage")
        button.alternateImage = NSImage(named: "myImage")
        button.action = Selector("myAction")
    }
}

I thought of using the button.rightMouseDown(<#theEvent: NSEvent#>) (Because there is no such "alternateAction") but unfortunately I did not manage to come up with something due to the fact that I just started programming Mac apps.

Update:

While searching for a way to do this I saw some threads telling to subclass a NSView but I don't se how this should work (This could be because I am really new to programming and don't even know how to "subclass"). Still I thought there was some easier way to use this since nearly every statusBar App that I know rects on right-clicks.

Upvotes: 7

Views: 2803

Answers (3)

H.B.
H.B.

Reputation: 55

The swift version of commanda's answer (subclassing an NSView and implementing mouseDown).

NSView Subclass:

class RightMouseHandlerView: NSView {

    var onRightMouseDown: (()->())? = nil

    override func rightMouseDown(with event: NSEvent) {
        super.rightMouseDown(with: event)

        if onRightMouseDown != nil {
            onRightMouseDown!()
        }
    }
}

Then adding it to the status bar button and setting the code block:

statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

if let button = statusItem.button {
    let rmhView = RightMouseHandlerView(frame: statusItem.button!.frame)
    rmhView.rightMouseDown = {
        // Do something when right mouse down on button
    }
    button.addSubview(rmView)
}

Upvotes: 0

commanda
commanda

Reputation: 4881

I had the same problem as you with the accepted answer's method: it didn't work for buttonMask 0x2, only buttonMask 0x1. Regular NSButtons (but not NSStatusBarButtons) can handle NSClickGestureRecognizers, so perhaps that's what the answerer was thinking. Another solution I found suggested was to set the NSStatusItem's view to an instance of your own custom subclass of NSView, but as of OS X v10.10, getting or setting view is deprecated, so I didn't want to do that.

I solved this by adding a custom subclass of NSView as a subview of the NSStatusItem's button. My NSView implements -rightMouseUp: to receive the right mouse up event and then just passes that event to a block given to it by my class that wants to handle the right mouse click event.

Here's my custom subclass:

#import <Cocoa/Cocoa.h>

@interface TTRightClickDetector : NSView

@property (copy) void (^onRightMouseClicked)(NSEvent *);

@end

#import "TTRightClickDetector.h"

And the implementation:

@implementation TTRightClickDetector

- (void)rightMouseUp:(NSEvent *)theEvent
{
    if(self.onRightMouseClicked)
    {
        self.onRightMouseClicked(theEvent);
    }
}

@end

And here's how I use it:

self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
NSStatusBarButton *button = self.statusItem.button;
button.image = [NSImage imageNamed:@"image"];
button.action = @selector(leftMouseClicked:);

TTRightClickDetector *rightClickDetector = [[TTRightClickDetector alloc] initWithFrame:button.frame];
rightClickDetector.onRightMouseClicked = ^(NSEvent *event){
    [self rightMouseClicked];
};
[button addSubview:rightClickDetector];

Upvotes: 2

Code Different
Code Different

Reputation: 93161

You can subclass and override the mouseDown method, but since Mac OS X 10.10 (Yosemite), there has been an easier way: NSGestureRecognizer and its subclasses:

func applicationDidFinishLaunching(aNotification: NSNotification) {
    // Insert code here to initialize your application
    if let button = statusItem.button {
        button.image = NSImage(named: "myImage")
        button.alternateImage = NSImage(named: "myImage")
        button.action = Selector("myAction")

        // Add right click functionality
        let gesture = NSClickGestureRecognizer()
        gesture.buttonMask = 0x2 // right mouse
        gesture.target = self
        gesture.action = "myRightClickAction:"
        button.addGestureRecognizer(gesture)
    }
}

func myRightClickAction(sender: NSGestureRecognizer) {
    if let button = sender.view as? NSButton {
        // Handle your right click event here
    }
}

Upvotes: 4

Related Questions