DMGetNameByAVID deprecated in 10.4

Moderator
Posts: 3,572
Joined: 2003.06
Post: #1
I've been using it for a long time to get the name of the connected monitors. In Displays.h it says it's been deprecated in 10.4. I can't seem to find a replacement. Does anybody know what to use instead?
Quote this message in a reply
Moderator
Posts: 3,572
Joined: 2003.06
Post: #2
Since Apple seems to be tossing Display Manager in the circular file and I still haven't found a way to get the proper name ( e.g. "Apple Display" or "Studio Display 21", etc. ) of any connected displays I'll try to get by without it. I'll iterate over them as they are returned from CGGetActiveDisplayList and just label them in order as "Main Display", "Display 2", "Display 3", and so on, since CGDirectDisplay.h says the first one returned in the array is the main display. Not perfect, but I guess it'll have to suffice unless someone has a better idea...
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #3
You can get the information you want from the IOKit. I haven't quite figured it out yet, but I'll take a closer look when I get home. The function you need (IODisplayCreateInfoDictionary) is declared in /System/Library/Frameworks/IOKit.framework/Headers/graphics/IOGraphicsLib.h
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
OK, here's a little program that'll loop through your framebuffers and print the names of the displays attached to each:

Code:
#include <stdio.h>
#include <stdlib.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/graphics/IOGraphicsLib.h>

#define QUIT_IF(condition)                                               \
    if (condition)                                                       \
    {                                                                    \
        printf("%s on line %d of %s\n", #condition, __LINE__, __FILE__); \
        exit(EXIT_FAILURE);                                              \
    }

#define QUIT_ON_IOERROR(x) QUIT_IF((x) != kIOReturnSuccess)
#define QUIT_ON_NULL(x)    QUIT_IF((x) == NULL)

int main(int argc, const char *argv[])
{
    kern_return_t result;

    CFMutableDictionaryRef matching_dictionary;
    matching_dictionary = IOServiceMatching(IOFRAMEBUFFER_CONFORMSTO);
    QUIT_ON_NULL(matching_dictionary);
    
    io_iterator_t iterator;
    result = IOServiceGetMatchingServices(
        kIOMasterPortDefault,
        matching_dictionary,
        &iterator);
    QUIT_ON_IOERROR(result);
    
    io_service_t service;
    service = (io_service_t)IOIteratorNext(iterator);
    while (service != 0)
    {
        CFDictionaryRef display_dictionary;
        display_dictionary = IODisplayCreateInfoDictionary(
            service,
            kIODisplayOnlyPreferredName);
        QUIT_ON_NULL(display_dictionary);
        
        //CFShow(display_dictionary);
        
        CFDictionaryRef product_names_dictionary;
        product_names_dictionary = CFDictionaryGetValue(
            display_dictionary,
            CFSTR(kDisplayProductName));
        if (product_names_dictionary != NULL)
        {
            QUIT_IF(CFDictionaryGetCount(product_names_dictionary) != 1);
            
            CFStringRef product_name;
            CFDictionaryGetKeysAndValues(
                product_names_dictionary,
                NULL,
                (const void**)&product_name);
            QUIT_ON_NULL(product_name);
                
            CFShow(product_name);  
        }
        
        service = (io_service_t)IOIteratorNext(iterator);
    }
    
    IOObjectRelease(iterator);
}

The question now is, how to associate this information with a CGDirectDisplayID?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
... and I can't find any way to. Maybe, just maybe, by messing with undocumented CGS APIs there might be a way, but I can't find one. Fat lot of use that is Sad
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.05
Post: #6
How about CGDisplayIOServicePort? I've never used the IOKit before, but that function does take a DisplayID and returns a io_service_t

Could be helpful,
Adam Zegelin
Quote this message in a reply
Moderator
Posts: 3,572
Joined: 2003.06
Post: #7
YES! Much thanks to both of you!

Code:
- (void)printMainDisplayName
{
    CFDictionaryRef  display_dictionary, product_names_dictionary;
    io_service_t       service;
    CFStringRef        product_name;

    service = CGDisplayIOServicePort(kCGDirectMainDisplay);
    display_dictionary = IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName);
    product_names_dictionary = CFDictionaryGetValue(display_dictionary, CFSTR(kDisplayProductName));
    CFDictionaryGetKeysAndValues( product_names_dictionary, NULL, (const void**)&product_name);
    CFShow(product_name);
}

I haven't written it for multiple displays or error conditions (give me a break, I just woke up and wanted to try it out), but I can plug in CGDirectDisplayID's all day so that won't be a problem. Looks like this case is closed. Grin
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
Ah, from CGDisplayConfiguration.h. I didn't look there Sad

Excellent, case closed!

Note that if you're in Cocoa, CFStringRef == NSString*, and CFDictionaryRef == NSDictionary*, so you can write the code a bit more nicely than you have Wink
Quote this message in a reply
Moderator
Posts: 3,572
Joined: 2003.06
Post: #9
OneSadCookie Wrote:Note that if you're in Cocoa, CFStringRef == NSString*, and CFDictionaryRef == NSDictionary*, so you can write the code a bit more nicely than you have Wink
Okay, here's my attempt at making it prettier for Cocoa and more useful at the same time. Give it a display id and it'll give you a name. If any errors occur it should merely return "Unknown Display". I tested it and it seems to work great, but I don't know if the code is "correct". Wink
Code:
#import <IOKit/graphics/IOGraphicsLib.h>
- (NSString *)getDisplayNameUsingID:(CGDirectDisplayID)display
{
    NSDictionary    *displayDictionary, *productNamesDictionary;
    io_service_t    service;
    NSString        *displayName;
    
    service = CGDisplayIOServicePort(display);
    displayDictionary = (NSDictionary *)IODisplayCreateInfoDictionary(service,
                                                kIODisplayOnlyPreferredName);
    if (displayDictionary != NULL)
    {
        productNamesDictionary = [displayDictionary
                               valueForKey:@kDisplayProductName];
        if (productNamesDictionary != NULL)
            displayName = [[productNamesDictionary allValues] objectAtIndex:0];
    }
    if (displayName != NULL)
        return displayName;
    else
        return @"Unknown Display";
}
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #10
I don't think you should be autoreleasing the displayName should you?

Otherwise, looks good.
Quote this message in a reply
Moderator
Posts: 3,572
Joined: 2003.06
Post: #11
I think you're right since I didn't alloc init displayName, so I removed the autorelease. Thanks.
Quote this message in a reply
Post Reply