Dominik Palo
Dominik Palo

Reputation: 3121

Determine external screen connected to the MacBook computer using NSScreen

I need to show a window on the external screen (e.g. monitor connected to the Macbook). But I don't know how to distinguish between internal MacBook screen and external one. Calling of NSScreen.screens() returns list of all screens and in my case screen with index 0 is my connected external screen and screen with index 1 is my internal (built in) MacBook screen. But documentation says:

The screen at index 0 in the returned array corresponds to the primary screen of the user’s system.

So why is my connected screen marked as primary? Is external screen on all systems is marked as primary => can I suppose that on all systems with connected external screen is this screen on 0 position?

Also, OS X dock is visible only on my internal screen and I thought that dock is by default visible on the primary screen, but that is not true.

Is there a way to reliable determine the correct external screen?

Upvotes: 3

Views: 2209

Answers (2)

Aaron Brager
Aaron Brager

Reputation: 66302

July 2022 Update: Updated the below code to remove the guard statement since NSScreen.screens no longer returns an optional.

To expand on werediver's answer, here's one implementation:

extension NSScreen {
    class func externalScreens() -> [NSScreen] {
        let description: NSDeviceDescriptionKey = NSDeviceDescriptionKey(rawValue: "NSScreenNumber")
        return screens.filter {
            guard let deviceID = $0.deviceDescription[description] as? NSNumber else { return false }
            print(deviceID)
            return CGDisplayIsBuiltin(deviceID.uint32Value) == 0
        }
    }
}

Usage is simple:

let externalScreens = NSScreen.externalScreens()

You might want to adjust the behavior in the guard statements' else blocks depending on your needs.

Upvotes: 6

werediver
werediver

Reputation: 4757

There is a note in the beginning of NSScreen Class Reference page:

NOTE

The NSScreen class is for getting information about the available displays only. If you need additional information or want to change the attributes relating to a display, you must use Quartz Services. For more information, see Quartz Display Services Reference.

From Quartz Display Services Reference we can learn that the main screen is not necessary the built-in one. From CGMainDisplayID() description:

The main display is the display with its screen location at (0,0) in the global display coordinate space. In a system without display mirroring, the display with the menu bar is typically the main display.

If mirroring is enabled and the menu bar appears on more than one display, this function provides a reliable way to find the main display.

In case of hardware mirroring, the drawable display becomes the main display. In case of software mirroring, the display with the highest resolution and deepest pixel depth typically becomes the main display.

So, if you can use Quartz Display Services directly, use CGDisplayIsBuiltin() function to determine whether the display is built-in or not.

Upvotes: 3

Related Questions