NSPopover application does not always appear where it should
Asked Answered
A

2

6

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?

Armor answered 19/9, 2017 at 12:8 Comment(1)
Have you got any luck fixing the problem? I'm fighting it for about 2 days and still no progress :(Rosariarosario
C
2

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

Collar answered 10/1, 2018 at 14:12 Comment(2)
[NSMenu menuBarVisible] always returns true, even when an application is full screen and the Status bar is closed.Armor
Oh weird, we've had good luck with that method returning a reliable state for the menubar visibility.Collar
A
2

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)
    }
}
Azalea answered 5/3, 2019 at 19:53 Comment(1)
Nice! I'm glad this at least fixes the issue sometimes. If you don't open the app first via the status bar (and instead do it programmatically while the status bar is hidden), this doesn't work!Deegan

© 2022 - 2024 — McMap. All rights reserved.