EDIT NOTE: This answer unfortunately doesn't provide a solution for detecting full screen in a different app, which is what the OP was asking. I'm leaving it because it does answer the question for detecting in in the same app going full screen - for example in a generic library that needs to know to automatically update keyEquivalents and title for an explicitly added "Enter Full Screen" menu item rather than Apple's automatically added menu item.
Although this question is quite old now, I've had to detect full screen mode in Swift recently. While it's not as simple as querying some flag in NSWindow
, as we would hope for, there is an easy and reliable solution that has been available since macOS 10.7.
Whenever a window is about to enter full screen mode NSWindow
sends a willEnterFullScreenNotification
notification, and when it is about to exit full screen mode, it sends willExitFullScreenNotification
. So you add an observer for those notifications. In the following code, I use them to set a global boolean flag.
import Cocoa
/*
Since notification closures can be run concurrently, we need to guard against
races on the Boolean flag. We could use DispatchSemaphore, but it's kind
over-kill for guarding a simple read/write to a boolean variable.
os_unfair_lock is appropriate for nanosecond-level contention. If the wait
could be milliseconds or longer, DispatchSemaphore is the thing to use.
This extension is just to make using it easier and safer to use.
*/
extension os_unfair_lock
{
mutating func withLock<R>(block: () throws -> R) rethrows -> R
{
os_unfair_lock_lock(&self)
defer { os_unfair_lock_unlock(&self) }
return try block()
}
}
fileprivate var fullScreenLock = os_unfair_lock()
public fileprivate(set) var isFullScreen: Bool = false
// Call this function in the app delegate's applicationDidFinishLaunching method
func initializeFullScreenDetection()
{
_ = NotificationCenter.default.addObserver(
forName: NSWindow.willEnterFullScreenNotification,
object: nil,
queue: nil)
{ _ in
fullScreenLock.withLock { isFullScreen = true }
}
_ = NotificationCenter.default.addObserver(
forName: NSWindow.willExitFullScreenNotification,
object: nil,
queue: nil)
{ _ in
fullScreenLock.withLock { isFullScreen = false }
}
}
Since observer closures can be run concurrently, I use os_unfair_lock
to guard races on the _isFullScreen
property. You could use DispatchSemaphore
, though it's a bit heavy weight for just guarding a Boolean flag. Back when the question was first asked, OSSpinLock
would have been the equivalent, but it's been deprecated since 10.12.
Just make sure to call initializeFullScreenDetection()
in your application delegate's applicationDidFinishLaunching()
method.