First, the reason why button.bounds.offsetBy(dx: 0.0, dy: -20.0)
didn't work is because those coordinate fell outside the "window" of the status bar item which is the status bar itself. So anything outside of it was cropped.
I solved this problem by collecting information here and there:
- Create an invisible window.
- Find the coordinates in the screen of the status bar item and position the invisible window under it.
- Show the
NSPopover
in relation to the invisible window and not the status bar item.
The red thing is the invisible window (for demonstration purposes).
Swift 4 (Xcode 9.2)
// Create a window
let invisibleWindow = NSWindow(contentRect: NSMakeRect(0, 0, 20, 5), styleMask: .borderless, backing: .buffered, defer: false)
invisibleWindow.backgroundColor = .red
invisibleWindow.alphaValue = 0
if let button = statusBarItem.button {
// 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)
// position and show the NSPopover
mainPopover.show(relativeTo: invisibleWindow.contentView!.frame, of: invisibleWindow.contentView!, preferredEdge: NSRectEdge.minY)
NSApp.activate(ignoringOtherApps: true)
}
I was trying to use show(relativeTo: invisibleWindow.frame ...)
and the popup wasn't showing up because NSWindow
is not an NSView
. For the popup to be displayed a view has to be passed.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…