Allow an NSWindow (NSPanel) to float above full screen apps
Asked Answered
X

3

15

I'm trying to add a little window that provides "quick input" from any place in the system to the main app.

The user could hit a hotkey, the window pops up, and floats above all other windows.

For the most part, this isn't much of a problem. I can configure an NSWindow to be:

level = Int(CGWindowLevelKey.TornOffMenuWindowLevelKey.rawValue)
collectionBehavior = .CanJoinAllSpaces

I can also make it an NSPanel with NSNonactivatingPanelMask option set.

The only problem is: how can I make it so that the window can pop up on the screen even if the user is on a space containing a full screen app?

I know this is possible when the app is LSUIElement=true (an app without a position in the Dock), but mine isn't.

Xylo answered 24/3, 2016 at 16:57 Comment(1)
how did you know this only works when LSUIElement=true ? Is it documented somewhere ? I spend a day with different configurations until I reach the same conclusion, it only works with LSUIElement=true. Is there a way of getting this same behaviour to work with LSUIElement=false ?Merla
X
24

Okay, I had the right idea, the tricky part is how all the options interact with each other. Here's what works:

  • NSPanel, not NSWindow
  • style mask: [.borderless, .nonactivatingPanel]

And these properties:

panel.level = .mainMenu
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]

Swift 4.2 Code

Create and show a panel using these settings. Then you can drag the panel onto a fullscreen app (dual monitor setup).

let panel2 = NSPanel(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.titled, .nonactivatingPanel], backing: .buffered, defer: true)
panel2.level = .mainMenu
panel2.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
panel2.orderFrontRegardless()

Floating NSPanel above fullscreen macOS app

Switching to borderless will prevent the user from moving your window.

let panel2 = NSPanel(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: true)
panel2.level = .mainMenu
panel2.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
panel2.orderFrontRegardless()
Xylo answered 24/3, 2016 at 17:12 Comment(2)
how to draw NSpaned on the desktop? How to display it? How to use in instead of NSWindow?Maugham
As of macOS Sonoma 14.5 this is still the correct and working answer, however raising the window level up to .mainMenu or using the .fullScreenAuxiliary collection behavior option doesn't seem necessary (at least on the mentioned OS version during my tests). I found that the key window properties to allow a window to float above another app's full-screen space for LSUIElement=0 are: 1. styleMask contains .nonactivatingPanel (NSPanel only!) 2. collectionBehavior contains .canJoinAllSpaces (automatic ordering above the space) or .transient (requires manual ordering)Melendez
A
2

And the Swift 4.0 translation is this.. I am still testing this, but it seems to be working.

self.view.window?.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.mainMenuWindow)))
self.view.window?.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
Achitophel answered 2/3, 2018 at 18:4 Comment(1)
doesn't work for me - macos 12.5.1 (21G83)Maugham
R
0

The Swift 3.0 version of your self-answer is

window.level = Int(CGWindowLevelForKey(.mainMenuWindow))
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
Retsina answered 2/5, 2017 at 1:45 Comment(1)
doesn't work for me - macos 12.5.1 (21G83)Maugham

© 2022 - 2024 — McMap. All rights reserved.