0

I'm trying to get a display name from CGDirectDisplayID in pure C++ (or C.)

I can do it in Objective-C++, similar to this:

#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <IOKit/graphics/IOGraphicsLib.h>
#import <Cocoa/Cocoa.h>

#include <string>


bool getDisplayNameForDispID(CGDirectDisplayID dispID,
                             std::string& strOutName)
{
    bool bRes = false;
    
    strOutName.clear();
    
    NSArray *screens = [NSScreen screens];

    for (NSScreen *screen in screens)
    {
        NSDictionary* screenDictionary = [screen deviceDescription];
        if(screenDictionary)
        {
            NSNumber* screenID = [screenDictionary objectForKey:@"NSScreenNumber"];
            if(screenID)
            {
                CGDirectDisplayID aID = [screenID unsignedIntValue];
                
                if(aID == dispID)
                {
                    //Got it
                    NSString* pName = [screen localizedName];
                    
                    strOutName.assign([pName UTF8String], [pName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);

                    bRes = true;
                    
                    break;
                }
            }
        }
    }    

    return bRes;
}

but I don't want to bring this slow Objective-C code into my project just to do this little thing. There must be a way to do it in low-level C.

PS. I know that there's this whole thread dedicated to it. Please note that none of the solutions there work for macOS Ventura as CGDisplayIOServicePort is deprecated and simply returns 0 and any subsequent calls do thing.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • 2
    *There must be a way to do it in low-level C.* The API is an Objective-C API. The way to do it in low-level C is by wrapping a C API thunk routine that is written in Objective-C to access the operating system's Objective-C API. – Eljay May 13 '23 at 10:47
  • Note that as far as I'm aware, `CGDisplayIOServicePort` returns `IO_OBJECT_NULL` or a valid `io_service_t` object handle depending on underlying *hardware* rather than software version. (NULL: Apple Silicon, Sidecar, USB displays, etc.; handle to `IOFramebuffer`: displays connected to GPUs that ship with Intel based Macs) Not that this makes the call any more reliable - just don't expect to be able to use the "old" approach based on OS version. – pmdj May 13 '23 at 12:39
  • @pmdj yeah, there's some internal voodoo going on there for sure. Btw, is there a way to RE those Obj-C calls to check what C calls they are making internally? – c00000fd May 13 '23 at 16:48
  • Objective-C isn't some thin wrapper over "more fundamental" C system libraries. You'd have to disassemble the `NSScreen` code in `AppKit.framework` to work out what it's doing. (likely talking directly to WindowServer via Mach messages or via the private `CGS` APIs, although [none of the reasonably well known ones](https://gist.github.com/rjw57/5495406) seem to be about display names.) – pmdj May 13 '23 at 19:35
  • 2
    If you really can't live with a small Objective-C(++) file that wraps the Objective-C code in a C(++) function, the easiest approach may be to [make raw Objective-C calls from C](https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend?language=objc). At least `NSScreen` is an official, documented, supported API, unlike any implementation details you might unearth by reverse engineering. – pmdj May 13 '23 at 19:36

0 Answers0