As pointed out on another site, the problem was caused by me setting the styleMask as .borderless without .titled, which prevents the window from becoming key or main according to this.
Here's my updated code that works in Swift 5.5:
import Cocoa
class ViewController: NSViewController {
var externalDisplay: NSScreen?
var fullScreenWindow: NSWindow?
var fullScreenView: NSView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
@IBAction func showExternalDisplayButtonClicked(sender: Any?) {
// Open the external display window if one is present
if NSScreen.screens.count > 1 {
externalDisplay = NSScreen.screens.last
let mask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable, .borderless]
fullScreenWindow = NSWindow(contentRect: externalDisplay!.frame, styleMask: mask, backing: .buffered, defer: true, screen: externalDisplay)
fullScreenWindow!.level = .normal
fullScreenWindow!.isOpaque = false
fullScreenWindow!.hidesOnDeactivate = false
fullScreenWindow!.backgroundColor = .red
let viewRect = NSRect(x: 0, y: 0, width: externalDisplay!.frame.width, height: externalDisplay!.frame.height)
fullScreenView = NSView(frame: viewRect)
fullScreenWindow!.contentView = fullScreenView
fullScreenView?.window?.toggleFullScreen(self)
}
}
}