Pregunta

What is the best way to get the NSScreen instance that is most likely be a projector or AirPlay display? (or even TV-Out?) I'm writing a presentation software and will need to know which screen that most likely represents the "presentation" screen.

Some options came to mind:

A. Use the second instance if there's any. Of course this will obviously won't give good results if there are more than two screens attached.

NSScreen* projectorScreen = [NSScreen mainScreen];
NSArray* screens = [NSScreen screens];
if(screens.count > 1) {
    projectorScreen = screens[1];
}

B. Use the first screen if it's not the main screen. The reason behind it is that in cases of mirroring, the first screen should be the one with the highest pixel depth.

NSScreen* projectorScreen = [NSScreen mainScreen];
NSArray* screens = [NSScreen screens];
if(screens.count > 1) {
    if(screens[0] != projectorScreen) {
        projectorScreen = screens[0];
    }
}

C. Use the lowest screen that is not the main screen. The reason is just to choose any screen that is not the main screen.

NSScreen* projectorScreen = [NSScreen mainScreen];
NSArray* screens = [NSScreen screens];
if(screens.count > 1) {
    for(NSScreen* screen in screens) {
        if(screen != projectorScreen) {
            projectorScreen = screen;
            break;
        }
    }
}

D. Use NSScreen's deviceDescription dictionary and find the biggest screen in real-world coordinates. That is divide NSDeviceSize's width and height with NSDeviceResolution and theoretically this should yield an area in square inches. However I'm not fully convinced that the OS knows the real-world size of each screen.

Any other suggestions?

Granted there isn't any 100% correct heuristics, but then again, picking the correct screen for most of the time should be sufficient.

¿Fue útil?

Solución

Looks like option (D) is the best, with some changes. Apparently OS X has a pretty good idea about the real-world size of the display and you can get it via CGDisplayScreenSize. It's then pretty straightforward to pick the largest one and assume that's the presentation screen.

Granted this doesn't accurately measure projectors, but my informal testing shows that the function returns pretty good pixel per inch values for each screen:

  • Macbook Air 13": {290, 180} mm, 126 ppi
  • Apple Cinema Display: {596, 336} mm, 109 ppi
  • An Epson Overhead Projector: {799, 450} mm, 61 ppi

(the above were converted with a constant 25.4 millimeters per inch).

Here's the code that I used:

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <ApplicationServices/ApplicationServices.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
        NSArray* screens = [NSScreen screens];
        CGFloat __block biggestArea = 0;
        NSScreen* __block presentationScreen;
        NSUInteger __block presentationScreenIndex;
        [screens enumerateObjectsUsingBlock:^(NSScreen* screen,NSUInteger idx,BOOL* stop){
            NSDictionary *description = [screen deviceDescription];
            NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
            CGSize displayPhysicalSize = CGDisplayScreenSize(
                        [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);

            NSLog(@"Screen %d Physical Size: %@ ppi is %0.2f",(int) idx, NSStringFromSize(displayPhysicalSize), 
                     (displayPixelSize.width / displayPhysicalSize.width) * 25.4f); 
                     // there being 25.4 mm in an inch
            CGFloat screenArea = displayPhysicalSize.width * displayPhysicalSize.height;
            if(screenArea > biggestArea) {
                presentationScreen = screen;
                biggestArea = screenArea;
                presentationScreenIndex = idx;
            }
        }];
        NSLog(@"Presentation screen: index: %d %@",(int) presentationScreenIndex,presentationScreen);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top