Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw an NSWindow over the entire screen, from corner to corner, including the menu bar and dock

I want to draw an NSWindow for an overlay application that completely covers the users screen - from corner to corner. I've got a borderloss, non activating panel that takes over the entire page.

import Foundation
import AppKit
import SwiftUI

class FullScreenPanel: NSPanel {
  override func constrainFrameRect(_ frameRect: NSRect, to screen: NSScreen?) -> NSRect {
    return frameRect
  }

}
final class Panel: FullScreenPanel, NSWindowDelegate {
  init(contentRect: NSRect, backing: NSWindow.BackingStoreType, defer flag: Bool) {
    super.init(
      contentRect: contentRect,
      styleMask: [.borderless, .nonactivatingPanel],
      backing: backing,
      defer: flag
    )

    self.level = .mainMenu + 3
    self.collectionBehavior.insert(.fullScreenAuxiliary) // Allows the panel to appear in a fullscreen space
    self.collectionBehavior.insert(.canJoinAllSpaces)
    self.titleVisibility = .hidden
    self.titlebarAppearsTransparent = true
    self.isMovable = false
    self.isMovableByWindowBackground = false
    self.isReleasedWhenClosed = false
    self.isOpaque = false
    self.delegate = self
  }

  func windowDidResignKey(_ notification: Notification) {
    DispatchQueue.main.async {
      appDelegate?.hideWindow()
    }
  }
}

I'm instantiating this with the NSScreen.main.frame CGRect

mainWindow = Panel(
    contentRect: NSScreen.main!.frame,
        backing: .buffered, defer: false)

However, when the window shows up, it still shows up under the menu bar. The constrainFrameRect function shows that somewhere internally the y value of the frame goes from 0 to to -44.

The window should also not trigger the native fullscreen effect, where it becomes a new "Desktop" that you can swipe between.

like image 571
JonLuca Avatar asked Oct 17 '25 00:10

JonLuca


1 Answers

  1. I think that you use NSPanel class incorrectly. Official Documentation for NSPanel:

    NSPanel

    A special kind of window that typically performs a function that is auxiliary to the main window.

    Your window is probably main (Because it takes up the whole screen and is the only visible one), so the NSPanel is not necessary, just use generic NSWindow.

  2. Use an NSWindowController for better code organisation.

  3. Use

    NSApplication.shared.presentationOptions = [.hideDock, .hideMenuBar]
    

    to hide the dock and menu bar completely and

    NSApplication.shared.presentationOptions = [.autoHideDock, .autoHideMenuBar]
    

    to make them appear when you hover over the position where they have been by default.

Warning! This code might block your whole screen. Consider adding an exit button or a shortcut (In the current version you can use Cmd + Tab to focus on another window). In the worst case you must reboot your computer by holding down the power button.

Code:

class FullScreenWindowController: NSWindowController {
    let viewController = FullScreenViewController()

    init() {
        super.init(window: NSWindow(contentViewController: viewController))
        
        // Remove the window header
        window?.styleMask = .borderless
        
        window?.setFrame(window!.screen!.frame, display: true)
        
        // Dock and Menu Bar are completely inaccessible
        // NSApplication.shared.presentationOptions = [.hideDock, .hideMenuBar]
        
        // Dock and Menu Bar will automatically hide when not needed
        NSApplication.shared.presentationOptions = [.autoHideDock, .autoHideMenuBar]
        
        window?.makeKeyAndOrderFront(self)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

To use the above class, just create an instance of it:

let fullScreenWindowController = FullScreenWindowController()

Also I used this view controller:

class FullScreenViewController: NSViewController {
    override func loadView() {
        let label = NSTextField(labelWithString: "Full Screen Window")
        label.font = .systemFont(ofSize: 48)
        view = label
    }
}
like image 164
Rocket Nikita Avatar answered Oct 19 '25 14:10

Rocket Nikita



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!