10

I am a .Net developer who need to port a small project into Mac, so I know next to nothing about Objective C. In fact the code below was just a bunch of grasping at straws and shooting in the dark.

Trying to build a Status Menu program that opens one or another window depending on if it is a left-click or a right-click/ctrl+click. Here is what I have, and it works for left-click only (obviously):

-(void) awakeFromNib{

    NSBundle *bundle = [NSbundle mainBundle];

    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
    [statusImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"icon" ofType:@"png"]];
    [statusItem setImage:statusImage];
    [statusItem setToolTip:@"Program Name"];
    [statusItem setHighlightMode:YES];
    [statusItem setAction:@selector(openWin:)];
    [statusItem setTarget: self];
}

-(void)openWin:(id)sender{
    [self openLeftWindow:sender];
}

-(IBAction)openLeftWindow:(id)sender{
    //Code to populate Left Click Window
    [leftWindow makeKeyAndorderFront:nil];
}

-(IBAction)openRightWindow:(id)sender{
    //Code to populate Right Click Window
    [rightWindow makeKeyAndorderFront:nil];
}

It seems to me that the solution would be either an if statement in the openWin() function to determine which button is clicked (or if ctrl was held down) then run the appropriate code or to make the menu aware of both the left and right clicks. But neither of these have worked when I attempted to do so.

Thanks In Advance.

Jonathan.
  • 53,997
  • 54
  • 186
  • 290
Dan
  • 103
  • 1
  • 5
  • I'm assuming it's just a typo that both the openLeftWindow: and openRightWindow: methods do the same thing. Otherwise, this question would be useless. – ughoavgfhw Dec 30 '10 at 20:15
  • correct, they do different things. Sorry about the typo – Dan Dec 30 '10 at 20:23

3 Answers3

12

If you will be satisfied with detecting control-click and not right click, then the first block of code will do what you want. If you really need the right click detection, you will have to use a custom view instead of an image in your NSStatusItem, and the second block of code will work.

Simple Method:

- (void)openWin:(id)sender {
    NSEvent *event = [NSApp currentEvent];
    if([event modifierFlags] & NSControlKeyMask) {
        [self openRightWindow:nil];
    } else {
        [self openLeftWindow:nil];
    }
}

Custom view method:

- (void)awakeFromNib {
    ...
    statusImage = ...
    MyView *view = [MyView new];
    view.image = statusImage;
    [statusItem setView:view];
    [statusItem setToolTip:@"Program Name"];
    view target = self;
    view action = @selector(openLeftWindow:);
    view rightAction = @selector(openRightWindow:);
    [view release];
    //[statusImage release]; //If you are not using it anymore, you should release it.
}

MyView.h

#import <Cocoa/Cocoa.h>
@interface MyView : NSControl {
    NSImage *image;
    id target;
    SEL action, rightAction;
}
@property (retain) NSImage *image;
@property (assign) id target;
@property (assign) SEL action, rightAction;
@end

MyView.m

#import "MyView.h"
@implementation MyView
@synthesize image, target, action, rightAction;
- (void)mouseUp:(NSEvent *)event {
    if([event modifierFlags] & NSControlKeyMask) {
        [NSApp sendAction:self.rightAction to:self.target from:self];
    } else {
        [NSApp sendAction:self.action to:self.target from:self];
    }
}
- (void)rightMouseUp:(NSEvent *)event {
    [NSApp sendAction:self.rightAction to:self.target from:self];
}
- (void)dealloc {
    self.image = nil;
    [super dealloc];
}
- (void)drawRect:(NSRect)rect {
    [self.image drawInRect:self.bounds fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
}
@end
ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123
  • This second solution is just as I want. But the icon is not appearing in the status bar. I can click (left, right and ctrl) where the icon should be and it works great, but the icon itself is missing. – Dan Dec 30 '10 at 21:36
  • Sorry, I forgot to put the drawRect: method in. I'll add it to my post. – ughoavgfhw Dec 31 '10 at 18:58
  • 1
    After manually setting the size of the icon, this worked great! Thanks! – Dan Jan 03 '11 at 17:01
  • Hmmm... small problem now. The window it opens has links and commands to run external programs and websites. When I click on these links and buttons the icon disappears, even though if I click in the area where the icon belongs it still behaves. Almost like the problem before, but now the image is there initially but doesn't persist when I use of the links/buttons that open external content. – Dan Jan 03 '11 at 18:57
  • It sounds like the view is getting drawn over without redrawing. Try marking it as needing display whenever you handle a link or button click. – ughoavgfhw Jan 03 '11 at 19:59
  • Any hints on how that is done. I have spent the last three hours trying to figure that out. – Dan Jan 03 '11 at 23:24
  • This is brilliant, works perfectly as described. One thing i'm still struggling with is getting a nsmenu status menu to show on the right click, any ideas? – Dom Vinyard Dec 03 '12 at 22:09
  • 1
    @Atheist Assuming you are using the view approach, you can try to use the `menuForEvent:` method in your view to return a menu, but I don't know if it will work properly in a status item. If not, you will need to use the `rightMouseUp:` method and call [`popUpContextMenu:withEvent:forView:`](https://developer.apple.com/library/mac/#documentation/cocoa/reference/applicationkit/classes/nsmenu_class/reference/reference.html#//apple_ref/occ/clm/NSMenu/popUpContextMenu:withEvent:forView:) to show the menu manually. – ughoavgfhw Dec 04 '12 at 03:47
3

I would create a view and use the status items method.

-setView:

Then in the subclassed view you can detect ctrl+LMB using the following

- (void)mouseDown:(NSEvent *)theEvent
{
    [super mouseDown:theEvent];

    //Respond to the mouse click
    if ([theEvent modifierFlags] & NSCommandKeyMask) //Command + LMB
    {       
      //Do something
    }
}

I think you can figure out the rest.

David
  • 14,205
  • 20
  • 97
  • 144
1

A more simplified response (Note, only works with control + click)

Properties:

@property (strong, nonatomic) NSStatusItem *statusItem;
@property (weak) IBOutlet NSMenu *statusMenu;

In Your Application Did Load:

[self.statusItem setAction:@selector(itemClicked:)];

Clicked Function:

- (void)itemClicked:(id)sender
{
    NSEvent *event = [NSApp currentEvent];

    if([event modifierFlags] & NSControlKeyMask) {
        NSLog(@"Right Click Pressed");
        [self.statusItem popUpStatusItemMenu:self.statusMenu];

    } else {
        // Do Nothing
        NSLog(@"Left Click Pressed");
    }
}
James Marino
  • 668
  • 1
  • 9
  • 25