Browse Source

cocoadisplay: use same scaling factor as the current view when switching to fullscreen on MacOS 10.15+

Fixes #794
LD 6 years ago
parent
commit
45461e667a
1 changed files with 42 additions and 1 deletions
  1. 42 1
      panda/src/cocoadisplay/cocoaGraphicsWindow.mm

+ 42 - 1
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -45,6 +45,10 @@
 
 
 TypeHandle CocoaGraphicsWindow::_type_handle;
 TypeHandle CocoaGraphicsWindow::_type_handle;
 
 
+#ifndef MAC_OS_X_VERSION_10_15
+#define NSAppKitVersionNumber10_14 1671
+#endif
+
 /**
 /**
  *
  *
  */
  */
@@ -1107,7 +1111,28 @@ set_properties_now(WindowProperties &properties) {
 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
 CGDisplayModeRef CocoaGraphicsWindow::
 CGDisplayModeRef CocoaGraphicsWindow::
 find_display_mode(int width, int height) {
 find_display_mode(int width, int height) {
-  CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL);
+  CFDictionaryRef options = NULL;
+  // On macOS 10.15+ (Catalina), we want to select the display mode with the
+  // samescaling factor as the current view to avoid cropping or scaling issues.
+  // This is a workaround until HiDPI display or scaling factor is properly
+  // handled. CGDisplayCopyAllDisplayModes() does not return upscaled display
+  // mode unless explicitly asked with kCGDisplayShowDuplicateLowResolutionModes
+  // (which is undocumented...).
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+  if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_14) {
+    const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
+    const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
+    options = CFDictionaryCreate(NULL,
+                                 (const void **)dictkeys,
+                                 (const void **)dictvalues,
+                                 1,
+                                 &kCFCopyStringDictionaryKeyCallBacks,
+                                 &kCFTypeDictionaryValueCallBacks);
+  }
+#endif
+  CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, options);
+  CFRelease(options);
+
   size_t num_modes = CFArrayGetCount(modes);
   size_t num_modes = CFArrayGetCount(modes);
   CGDisplayModeRef mode;
   CGDisplayModeRef mode;
 
 
@@ -1116,14 +1141,22 @@ find_display_mode(int width, int height) {
   int refresh_rate;
   int refresh_rate;
   mode = CGDisplayCopyDisplayMode(_display);
   mode = CGDisplayCopyDisplayMode(_display);
 
 
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
   // First check if the current mode is adequate.
   // First check if the current mode is adequate.
   if (CGDisplayModeGetWidth(mode) == width &&
   if (CGDisplayModeGetWidth(mode) == width &&
       CGDisplayModeGetHeight(mode) == height) {
       CGDisplayModeGetHeight(mode) == height) {
     return mode;
     return mode;
   }
   }
+#endif
 
 
   current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
   current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
   refresh_rate = CGDisplayModeGetRefreshRate(mode);
   refresh_rate = CGDisplayModeGetRefreshRate(mode);
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+  // Calculate the pixel width and height of the fullscreen mode we want using
+  // the currentdisplay mode dimensions and pixel dimensions.
+  size_t expected_pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
+  size_t expected_pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
+#endif
   CGDisplayModeRelease(mode);
   CGDisplayModeRelease(mode);
 
 
   for (size_t i = 0; i < num_modes; ++i) {
   for (size_t i = 0; i < num_modes; ++i) {
@@ -1131,9 +1164,17 @@ find_display_mode(int width, int height) {
 
 
     CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
     CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
 
 
+    // As explained above, we want to select the fullscreen display mode using
+    // the same scaling factor, but only for MacOS 10.15+ To do this we check
+    // the mode width and heightbut also actual pixel widh and height.
     if (CGDisplayModeGetWidth(mode) == width &&
     if (CGDisplayModeGetWidth(mode) == width &&
         CGDisplayModeGetHeight(mode) == height &&
         CGDisplayModeGetHeight(mode) == height &&
         CGDisplayModeGetRefreshRate(mode) == refresh_rate &&
         CGDisplayModeGetRefreshRate(mode) == refresh_rate &&
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+        (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_14 ||
+        (CGDisplayModeGetPixelWidth(mode) == expected_pixel_width &&
+         CGDisplayModeGetPixelHeight(mode) == expected_pixel_height)) &&
+#endif
         CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
         CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
 
 
       CFRetain(mode);
       CFRetain(mode);