Reputation: 15359
I'm searching for a way of getting two pieces of information: (1) the full physical resolution of a display, even if it is a Retina screen; (2) the resolution that the operating system will, according to current system settings, pretend the same screen has. So far I'm able to get (2) but not (1). It seems like I'm running up against the comment here that
There is even more mess if somebody sets "Scaled" Resolution in macOS System Preferences->Displays
without having been able to find any information about how to navigate that "mess". So far I have the following, which I compile with clang -framework Cocoa -x objective-c -o grokResolution
:
#import <AppKit/AppKit.h>
void ReportRect(CGRect rect, const char *description)
{
printf("{'x': % 5g, 'y':% 5g, 'width':% 5g, 'height':% 5g, 'name':'%s'}\n",
rect.origin.x, rect.origin.y,
rect.size.width, rect.size.height,
description);
}
int main(int argc, char** argv)
{
NSScreen *screen = [[NSScreen screens] objectAtIndex:0];
CGRect looksLike = [screen frame];
CGRect backing = [screen convertRectToBacking:looksLike];
ReportRect(looksLike, "looksLike");
ReportRect(backing, "backing");
printf("{'backingScaleFactor' : %0.2f}\n", [screen backingScaleFactor]);
}
My Retina screen has 2560x1600 physical pixels. If I use the default scaling setting, which the System Preferences app previews with "Looks like 1280 x 800", then the program outputs the following:
{'x': 0, 'y': 0, 'width': 1280, 'height': 800, 'name':'looksLike'}
{'x': 0, 'y': 0, 'width': 2560, 'height': 1600, 'name':'backing'}
{'backingScaleFactor' : 2.00}
So that seems correct. However, if I click on the next scaling setting to the right in System Preferences, then re-run the program, I get:
{'x': 0, 'y': 0, 'width': 1440, 'height': 900, 'name':'looksLike'}
{'x': 0, 'y': 0, 'width': 2880, 'height': 1800, 'name':'backing'}
{'backingScaleFactor' : 2.00}
Now, while the System Preferences' "looks like" setting seems to be correctly reflected in the output of [screen frame]
, my understanding of the whole system is clearly flawed because I expected the backingScaleFactor
and/or the convertRectToBacking
to convert correctly from fake to real physical resolution. It seems the backingScaleFactor
is not correctly adjusted when the system preference changes—in this case the conversion returns more pixels than my hardware really has.
How do I convert correctly? Or is there another more direct way of querying the actual number of physical pixels a display has?
(I know about system_profiler SPDisplaysDataType | grep Resolution
but I need a solution that will work within existing obj-C source code.)
Upvotes: 0
Views: 343
Reputation: 90661
The scale factor is always integral. So far, it's always 1 or 2. Some day, Apple may introduce 3x display support for macOS.
The backing store does not necessarily correspond to physical display pixels. For some "scaled" resolutions, the backing store is larger than the number of physical display pixels. Then it is scaled down for actual display. That's what's going on with your second example.
As to how to get the number of physical display pixels, there have been a couple of recent questions with some discussion of that and no firm answer. See this question and the links in the comments.
Upvotes: 1