14

I'm working on an OS X application that displays custom windows on all available spaces of all the connected displays. I can get an array of the available display objects by calling [NSScreen screens].

What I'm currently missing is a way of telling if the user connects a display to or disconnects a screen from their system.

I have searched the Cocoa documentation for notifications that deal with a scenario like that without much luck, and I refuse to believe that there isn't some sort of system notification that gets posted when changing the number of displays connected to the system.

Any suggestions on how to solve this problem?

Gabor
  • 278
  • 4
  • 14

2 Answers2

16

There are several ways to achieve that:
You could implement applicationDidChangeScreenParameters: in your app delegate (the method is part of the NSApplicationDelegateProtocol).
Another way is to listen for the NSApplicationDidChangeScreenParametersNotification sent by the default notification center [NSNotificationCenter defaultCenter].

Whenever your delegate method is called or you receive the notification, you can iterate over [NSScreen screens] and see if a display got connected or removed (you have to maintain a display list you can check against at program launch).

A non-Cocoa approach would be via Core Graphics Display services:
You have to implement a reconfiguration function and register it with CGDisplayRegisterReconfigurationCallback(CGDisplayReconfigurationCallBack cb, void* obj);

In your reconfiguration function you can query the state of the affected display. E.g.:

void DisplayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void* userInfo)
{
    if(display == someDisplayYouAreInterestedIn)
    {
        if(flags & kCGDisplaySetModeFlag)
        {
            ...
        }
        if(flags & kCGDisplayRemoveFlag)
        {
            ...
        }
        if(flags & kCGDisplayDisabledFlag)
        {
           ...
        }
    }
    if(flags & kCGDisplaySetModeFlag || flags & kCGDisplayDisabledFlag || flags & kCGDisplayRemoveFlag)
    {
        ...
    }
}
Thomas Zoechling
  • 34,177
  • 3
  • 81
  • 112
  • Thank you for your comment. What would be the benefit of using Core Graphics Display services over the Cocoa notification and my Cocoa methods? It seems to me that it adds an extra layer of complexity without any obvious gains. – Gabor Aug 04 '13 at 13:08
  • The only benefit would be that the reconfiguration callback already contains some state information (delivered as CGDisplayChangeSummaryFlags) so you don't have to compare all NSScreen details yourself when the reconfiguration happens. The Cocoa notification or the delegate method are fine too of course. – Thomas Zoechling Aug 04 '13 at 13:17
3

in swift 3.0:

let nc = NotificationCenter.default
    nc.addObserver(self,
                   selector: #selector(screenDidChange),
                   name: NSNotification.Name.NSApplicationDidChangeScreenParameters,
                   object: nil)

NC call back:

final func screenDidChange(notification: NSNotification){
    let userInfo = notification.userInfo
    print(userInfo)
}
ingconti
  • 10,876
  • 3
  • 61
  • 48
  • Evidently the NSApplicationDidChangeScreenParameters notification was removed in Sometime before Swift 5.5.1. Any other reasonable ways of detecting when an external display is connected/disconnected on a Mac? – SouthernYankee65 Nov 24 '21 at 19:01
  • 1
    For reference in the future for anyone coming across this, [here](https://stackoverflow.com/q/70103282/9607863) is @SouthernYankee65 's new question about this. – George Nov 24 '21 at 23:02