From 88b515ba15150b55a313bd27dbd4e507fe9e4633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 27 Jan 2020 21:59:45 +0100 Subject: [PATCH] Platform: assume HiDPI is on by default on macOS 10.13+ and iOS 13+. Also fix the detection in case the app explicitly sets the property to false -- previously it thought the app is HiDPI-aware as well, which was wrong. --- doc/changelog.dox | 6 ++ doc/platforms-macos.dox | 10 +++- .../Platform/Implementation/DpiScaling.mm | 58 +++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 628afa1b5..bf46da95e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -161,6 +161,12 @@ See also: [mosra/magnum#392](https://github.com/mosra/magnum/pull/392), [mosra/magnum#400](https://github.com/mosra/magnum/issues/400), [mosra/magnum#401](https://github.com/mosra/magnum/pull/401)) +- HiDPI capability checking on macOS and iOS got fixed to behave correctly + when the capability is explicitly set to @cb{.xml} @ce in the + `Info.plist` file and additionally, unless overriden, it's assumed to be + enabled by default on macOS 10.15+ and iOS 13+. Applications running on + these platforms no longer need to supply a custom `Info.plist` in order to + enable HiDPI. See @ref platforms-macos-hidpi for more information. @subsubsection changelog-latest-changes-trade Trade library diff --git a/doc/platforms-macos.dox b/doc/platforms-macos.dox index 4635c951d..2f36e2c4b 100644 --- a/doc/platforms-macos.dox +++ b/doc/platforms-macos.dox @@ -108,9 +108,9 @@ example. @section platforms-macos-hidpi HiDPI (Retina) support macOS and iOS is the only platform where HiDPI support of an app can't be -advertised programmatically. In case of CMake, you have to supply a custom -`*.plist` file with `NSHighResolutionCapable` enabled -(@ref platforms-macos-bundle "see above for details about creating bundles"): +advertised programmatically. According to various sources, this capability is +enabled by default on macOS 10.15+ and iOS 13+, for older versions you need to +supply a custom `*.plist` file with `NSHighResolutionCapable` enabled: @code{.xml} @@ -124,6 +124,10 @@ advertised programmatically. In case of CMake, you have to supply a custom @endcode +If you are using CMake, you can use the @ref platforms-macos-bundle "method described above" +to create a bundle with given file. Also note that this property is already +included in CMake's builtin `Info.plist` on [version 3.9 and newer](https://gitlab.kitware.com/cmake/cmake/merge_requests/682). + @section platforms-macos-clang-version-mapping Clang version mapping Apple Clang has a different versioning scheme from upstream Clang, making it diff --git a/src/Magnum/Platform/Implementation/DpiScaling.mm b/src/Magnum/Platform/Implementation/DpiScaling.mm index 6c4ce9f49..84503e8ca 100644 --- a/src/Magnum/Platform/Implementation/DpiScaling.mm +++ b/src/Magnum/Platform/Implementation/DpiScaling.mm @@ -24,6 +24,7 @@ */ #import "Foundation/NSBundle.h" +#import "Foundation/NSProcessInfo.h" #include "DpiScaling.h" @@ -33,12 +34,61 @@ namespace Magnum { namespace Platform { namespace Implementation { -/* HiDPI is available only for bundles, so if the executable is not a bundle, - return false */ +/* UGH! */ bool isAppleBundleHiDpiEnabled() { + /* Retrieve the NSHighResolutionCapable property from the bundle + Info.plist. A non-nil bundle may be returned even for executables that + aren't a bundle, so one can't use that to decide about anything. */ + id nsHighResolutionCapable = nil; NSBundle* bundle = [NSBundle mainBundle]; - if(!bundle) return false; - return bool([bundle objectForInfoDictionaryKey:@"NSHighResolutionCapable"]); + if(bundle) nsHighResolutionCapable = [bundle objectForInfoDictionaryKey:@"NSHighResolutionCapable"]; + + /* If the nsHighResolutionCapable entry is not found, it might mean it was + either not specified in the Info.plist file or the executable is not a + bundle. In that case, it'll be a default and that's where it gets ugly. + Before 10.15, HiDPI is available only for bundles, so (if the executable + is not a bundle or) the key is not specified, returning false. On 10.15, + according to the global consensus (but nothing really confirmed by + apple) in the following issues / changes + + https://github.com/simbody/simbody/issues/674 + https://github.com/redeclipse/base/issues/920 + https://github.com/UltraStar-Deluxe/USDX/issues/492 + https://bugzilla.libsdl.org/show_bug.cgi?id=4822 + https://hg.libsdl.org/SDL/rev/46b094f7d20e + https://github.com/deepmind/lab/issues/173 + https://github.com/widelands/widelands/issues/3542 + + ... it seems that HiDPI is the default. THANKS APPLE FOR CONFIRMING IT + SO CLEARLY IN YOUR CHANGELOG AND DEVELOPER DOCUMENTATION! So returning + true if the key is not specified and version is 10.15+. + + Of course, I have absolutely no idea how is it on iOS. So there it'll + assume it's since iOS 13 (which has the ~same release date as macOS + 10.15) so I suppose both changes were done in tandem. In any case it's + less of a problem because almost nobody looks at the logs anyway. Eh. */ + if(!nsHighResolutionCapable) { + /* Based on https://stackoverflow.com/a/24004701. If someone is on 10.9 + and below, this will fail to compile. Sorry about that --- if that + affects you, please open an issue. On the SO link there are + alternatives that should work on older versions as well, but right + now I'll assume everyone has 10.10 at least. For iOS this goes back + to version 8, which should be more than okay. */ + NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; + #ifndef CORRADE_TARGET_IOS + return version.majorVersion*100 + version.minorVersion >= 1015; + #else + return version.majorVersion >= 13; + #endif + } + + /* Doing bool(nsHighResolutionCapable) would always return true, so that + is not what we want. This works. ObjC, thank you, I thought it's + impossible to have a language designed in a way that allows you to make + a deadly mistake on each line and yet it all seemingly ""works"" with no + compiler errors, runtime crashes or anything whatsoever. */ + NSNumber* soIsItOrIsItNot = nsHighResolutionCapable; + return soIsItOrIsItNot.boolValue; } }}}