Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSPopover application does not always appear where it should

I am working on an NSPopover application. I am using raywenderlich tutorial as a starting place.

The issue I am having is that when the popover opens and the system status bar is closed (such as when using multiple full-screen apps on a laptop) the popover shows in the bottom left of the screen.

Is there a way to force the system status bar to open and stay open while the popover is open?

like image 340
datinc Avatar asked Sep 19 '17 12:09

datinc


2 Answers

We had a similar issue, and ended up detecting when the system menubar was minimized:

[NSMenu menuBarVisible]

As far as keeping your window visible, you might look into sharing your window style on the fly using NSBorderlessWindowMask | NSNonactivatingPanelMask

like image 180
theeagle Avatar answered Nov 04 '22 21:11

theeagle


The problem is that when the status bar isn't visible the statusItem / button has a weird position so it's in the left side of the screen.

A possibly solution to this could be to save the position when the popover is first opened and keep showing it relative to that point. In this answer they place the popover relative to an invisible window. This we need because when we display the popover relative to the statusItem / button, the position is weird if the status is not visible.

So if you save the window as a variable and show the popover relative to this you will end up with something like this:

static let popover = NSPopover()
var invisibleWindow: NSWindow!

func showPopover(sender: Any?) {
    if let button = AppDelegate.statusItem.button {
        if (invisibleWindow == nil) {
            invisibleWindow = NSWindow(contentRect: NSMakeRect(0, 0, 20, 1), styleMask: .borderless, backing: .buffered, defer: false)
            invisibleWindow.backgroundColor = .red
            invisibleWindow.alphaValue = 0

            // find the coordinates of the statusBarItem in screen space
            let buttonRect:NSRect = button.convert(button.bounds, to: nil)
            let screenRect:NSRect = button.window!.convertToScreen(buttonRect)

            // calculate the bottom center position (10 is the half of the window width)
            let posX = screenRect.origin.x + (screenRect.width / 2) - 10
            let posY = screenRect.origin.y

            // position and show the window
            invisibleWindow.setFrameOrigin(NSPoint(x: posX, y: posY))
            invisibleWindow.makeKeyAndOrderFront(self)
        }

        AppDelegate.popover.show(relativeTo: invisibleWindow.contentView!.frame, of: invisibleWindow.contentView!, preferredEdge: NSRectEdge.minY)
        NSApp.activate(ignoringOtherApps: true)
    }
}
like image 2
Under_Koen Avatar answered Nov 04 '22 22:11

Under_Koen