Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show NSPopover when the application starts

I am using Pyobjc to create a NSStatusItem. When it is clicked, I am showing an NSPopOver. This is working fine. However, my requirement is to show the popover as soon as the application starts without any action by the user. Calling the callback directly in finishLaunching is not working. Is there any way to achieve this? It will be good enough even if can just simulate the click on NSStatusView.

class TestApp(NSApplication):

    def finishLaunching(self):
        # Make statusbar item
        statusbar = NSStatusBar.systemStatusBar()
        self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
        self.statusitem.setTarget_(self)
        self.statusitem.setAction_('statusItemClicked:')
        self.icon = NSImage.alloc().initByReferencingFile_('app-icon.png')
        self.icon.setScalesWhenResized_(True)
        self.icon.setSize_((20, 20))
        self.statusitem.setImage_(self.icon)
        self.statusitem.setHighlightMode_(1)

        # self.statusItemClicked_(None)

    def statusItemClicked_(self, notification):
        self.viewController = SimpleXibDemoController.alloc().initWithWindowNibName_("Login")

        # Show the window
        self.viewController.showWindow_(self.viewController)
        rect = self.statusitem.valueForKey_('button').frame()
        self.viewController.popover.showRelativeToRect_ofView_preferredEdge_(rect, self.statusitem.valueForKey_('button'), NSMaxYEdge)
like image 260
Pradeep Vairamani Avatar asked Oct 21 '22 04:10

Pradeep Vairamani


2 Answers

I finally got a somewhat sketchy solution. I have a method which positions the popover like so:

- (IBAction)showPopover:(id)sender {
    [popover showRelativeToRect:self.statusItemView.bounds ofView:self.statusItemView preferredEdge:NSMinYEdge];
}

In applicationDidFinishLaunching, or finishLaunching in your case, instead of calling the method directly I called it with performSelector instead:

[self performSelector:@selector(showPopover:) withObject:self afterDelay:0];

Even setting the delay to 0 works, which I do not know why, and it now positions the popover correctly.

Edit: This seems to only work situationally. Even by creating a view controller and calling it from viewDidAppear, the popover only gets positioned half of the time.

Edit 2: I added a window controller to the status item's window, and overrode windowDidLoad. However as it turned out, the window is loaded before I can even set the controller's window so windowDidLoad is not called.

like image 198
Luke Avatar answered Nov 09 '22 17:11

Luke


You have to wait until the view appears to present the NSPopover. Override viewDidAppear in your NSViewController subclass and present it there. (Or override loadView if your minimum deployment target is less than OS X Yosemite.)

like image 41
Aaron Brager Avatar answered Nov 09 '22 16:11

Aaron Brager