2
votes

I'm doing first steps in programming for Mac. I had only little experience of iOS development. I need to build very simple app, sitting in menu bar. I wanted it a little custom to decided to use NSWindow and attach it to the NSStatusItem.

My AppDelegate looks so:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application

    float width = 30.0;
    float height = [[NSStatusBar systemStatusBar] thickness];
    NSRect viewFrame = NSMakeRect(0, 0, width, height);
    statusItem = [[NSStatusItem alloc] init];
    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:30];
    [statusItem setView:[[TSStatusBarItem alloc] initWithFrame:viewFrame]];


}

- (void)buttonClicked:(int)posx posy:(int)posy {
    [_window setLevel:kCGMaximumWindowLevelKey];
    opened = !opened;
    NSLog(@"Window is shown: %i", opened);

    [_window setFrameTopLeftPoint:NSMakePoint(posx, posy)];

    if(opened == YES) {
        _window.isVisible = YES;
    } else {
        _window.isVisible = NO;
    }

}

It's code of TSStatusBarItem

- (void)drawRect:(NSRect)rect
{
    // Drawing code here.

    if (clicked) {
        [[NSColor selectedMenuItemColor] set];
        NSRectFill(rect);
    }

    NSImageView *subview = [[NSImageView alloc] initWithFrame:CGRectMake(3, 0, 20, 20)];
    [subview setImage:[NSImage imageNamed:@"icon.png"]];
    [self addSubview:subview];


}

- (void)mouseDown:(NSEvent *)event
{

    NSRect frame = [[self window]frame];
    NSPoint pt = NSMakePoint(NSMinX(frame), NSMinY(frame));
    NSLog(@"X: %f and Y: %f", pt.x, pt.y);

    [self setNeedsDisplay:YES];
    clicked = !clicked;

    [appDelegate buttonClicked:pt.x posy:pt.y];


}

Window shows and hides pretty well, but only if I click on StatusItem. I would like to add behavior of hiding window, when user clicks outside or when selects another item in menu bar (just similar working to typical NSMenu application).

How to do it? If you have any idea how to simplify my code (sorry, I'm newbie in Mac coding) - let's say please.

2
Why do you add a new image view every time draw rect is called? I recommend adding that part of your code to the ini t method, or drawing the image programmatically. ;)Tanner Silva
@TannerSilva - Thanks! I did so.Konrad Kolasa
Also, do you have an NSMenu appear when the status item is clicked?Tanner Silva
@TannerSilva No. I just 'open' NSWindow and move to the point of NSStatusItem.Konrad Kolasa
Ok. I was thinking you could make your AppDelegate a NSMenuDelegate, which would notify you when the status menu closed.Tanner Silva

2 Answers

4
votes

Register for NSWindowDidResignKeyNotification or NSWindowDidResignMainNotification to get notified in case the window looses focus:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    SEL theSelector = @selector(closeWindow); 
    NSNotificationCenter* theCenter = [NSNotificationCenter defaultCenter]; 
    NSWindow* theWindow = [self window]; 
    [theCenter addObserver:self selector:theSelector name:NSWindowDidResignKeyNotification object:theWindow]; 
    [theCenter addObserver:self selector:theSelector name:NSWindowDidResignMainNotification object:theWindow]; 
}

Now the following is executed in case the window looses focus:

-(void)closeWindow
{
    [[self window] close];
}

Alternatively use NSPanel which hides automatically in case focus is lost.

1
votes
-(void)applicationDidResignActive:(NSNotification *)notification
{
    [self window] close];
}

Try it This will work only if your app is in focus. And in order to make it focused... Try this too - :

[NSApp activateIgnoringOtherApps:YES];