Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Popover NSStatusItem

I'm playing around with an idea and basically I want a NSStatusItem with a NSPopoverController. I read about all the problem people had but I just want to try it. Is there a clean way to do it by now? All the versions I've seen are at least 1 year old and suuuuper hacky.

This was my approach so far but if I click my app in the statusbar nothing happens...

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];

    //[self.statusItem setView:view];
    [self.statusItem setTitle:@"Test"];
    [self.statusItem setHighlightMode:YES];
    [self.statusItem setAction:@selector(activatePopover:)];

}


-(IBAction)activatePopover:(id)sender
{
    BOOL isEnabled = NO;

    if (isEnabled) {
        [self.popover showRelativeToRect:NSMakeRect(0, 0, 50, 50) ofView:statusItem.view preferredEdge:NSMinYEdge];

    } else {
        [self.popover close];
    }
}

Any ideas how to get this running?

Thanks

like image 783
Constantin Jacob Avatar asked Jan 11 '23 17:01

Constantin Jacob


2 Answers

This will not work without using a custom view on the status item. If you don't set a custom view, the view property will be empty (it only returns custom views, not whatever view NSStatusItem uses internally when you just use setTitle).

Unfortunately, as per Apple's docs, you'll need to provide your own view and handle clicks yourself if you want to use NSPopover.

I haven't seen a complete example that encompasses correct handling of this (the default implementation of status items does rather a lot which you will have to do all manually), and also fixes popover wonkynesses:

  • NSPopover, by default, won't become the key window (some controls won't work), unless you overwrite canBecomeKeyWindow of NSPopover's window
  • Correctly dismissing menus of other status items (you can call popUpStatusItemMenu with an empty menu to correctly focus your status item)
  • Drawing the highlighted background with drawStatusBarBackgroundInRect
  • Reacting to both left and right mouse clicks
  • Using NSRunningApplication.currentApplication.activateWithOptions to make sure all windows of your status item become active (otherwise your popover will, erratically, not be the receiver of keyboard input)
  • Dismissing the NSPopover with NSEvent.addGlobalMonitorForEventsMatchingMask (the built-in dismissal mechanism popovers come with doesn't work with status items)
  • Removing the status item on termination with NSStatusBar.systemStatusBar.removeStatusItem

I hope to have a blog post about this out sometime soon (note: I'm using RubyMotion, not Objective-C), that explains all these issues and hopefully provides an easier base to create menulets. I'll update this comment if I write that post.

like image 146
thomasfuchs Avatar answered Feb 11 '23 03:02

thomasfuchs


Code:

-(void)initializeStatusBarItem
{
    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
    NSImage* image = [NSImage imageNamed:@"image"];
//    [image setTemplate:YES];
    self.statusItem.button.image = image;
    self.statusItem.highlightMode = NO;
    self.statusItem.button.action = @selector(statusBarItemDidClick:);
}

- (void)statusBarItemDidClick:(NSStatusBarButton *)sender{
    MainViewController *mainView = [[MainViewController alloc] init];
    self.popoverView = [[NSPopover alloc] init];
    [self.popoverView setContentViewController:mainView];
    self.popoverView.contentSize = CGSizeMake(300, 400);
    self.popoverView.behavior = NSPopoverBehaviorTransient;
    [self.popoverView showRelativeToRect:sender.bounds ofView:sender preferredEdge:NSMaxYEdge];
}
like image 29
wanglin Avatar answered Feb 11 '23 04:02

wanglin