Browse Source

patch from gerakinis and yaio to detect available desktop sizes

Zeno Gerakin 15 years ago
parent
commit
9a3d16b1c5
1 changed files with 159 additions and 0 deletions
  1. 159 0
      panda/src/osxdisplay/osxGraphicsPipe.cxx

+ 159 - 0
panda/src/osxdisplay/osxGraphicsPipe.cxx

@@ -17,6 +17,145 @@
 #include "pnmImage.h"
 #include "pnmImage.h"
 #include "subprocessWindow.h"
 #include "subprocessWindow.h"
 #include "nativeWindowHandle.h"
 #include "nativeWindowHandle.h"
+#import <Carbon/Carbon.h>
+
+// some macros to make code more readable.
+#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
+#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
+#define GetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
+#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
+#define GetModeSafeForHardware(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware)
+#define GetModeStretched(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsStretched)
+#define MAX_DISPLAYS 32
+
+Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) {
+  // get a boolean from the dictionary
+  Boolean value = false;
+  CFBooleanRef boolRef;
+  boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
+  if (boolRef != NULL)
+    value = CFBooleanGetValue(boolRef);   
+  return value;
+}
+
+long GetDictionaryLong(CFDictionaryRef theDict, const void* key) {
+  // get a long from the dictionary
+  long value = 0;
+  CFNumberRef numRef;
+  numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
+  if (numRef != NULL)
+    CFNumberGetValue(numRef, kCFNumberLongType, &value);   
+  return value;
+}
+
+static CFComparisonResult CompareModes (const void *val1,const void *val2,void *context) {
+  // CFArray comparison callback for sorting display modes.
+#pragma unused(context)
+  CFDictionaryRef thisMode = (CFDictionaryRef)val1;
+  CFDictionaryRef otherMode = (CFDictionaryRef)val2;
+   
+  long width = GetModeWidth(thisMode);
+  long otherWidth = GetModeWidth(otherMode);
+  long height = GetModeHeight(thisMode);
+  long otherHeight = GetModeHeight(otherMode);
+   
+  // sort modes in screen size order
+  if (width * height < otherWidth * otherHeight) {
+    return kCFCompareLessThan;
+  } else if (width * height > otherWidth * otherHeight) {
+    return kCFCompareGreaterThan;
+  }
+   
+  // sort modes by bits per pixel
+  long bitsPerPixel = GetModeBitsPerPixel(thisMode);
+  long otherBitsPerPixel = GetModeBitsPerPixel(otherMode);   
+  if (bitsPerPixel < otherBitsPerPixel) {
+    return kCFCompareLessThan;
+  } else if (bitsPerPixel > otherBitsPerPixel) {
+    return kCFCompareGreaterThan;
+  }
+   
+  // sort modes by refresh rate.
+  long refreshRate = GetModeRefreshRate(thisMode);
+  long otherRefreshRate = GetModeRefreshRate(otherMode);   
+  if (refreshRate < otherRefreshRate) {
+    return kCFCompareLessThan;
+  } else if (refreshRate > otherRefreshRate) {
+    return kCFCompareGreaterThan;
+  }
+     
+  return kCFCompareEqualTo;
+}
+
+CFArrayRef GSCGDisplayAvailableModesUsefulForOpenGL(CGDirectDisplayID display) {
+  // get a list of all possible display modes for this system.
+  CFArrayRef availableModes = CGDisplayAvailableModes(display);
+  unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
+ 
+  // creat mutable array to hold the display modes we are interested int.
+  CFMutableArrayRef usefulModes = CFArrayCreateMutable(kCFAllocatorDefault, numberOfAvailableModes, NULL);
+ 
+  // get the current bits per pixel.
+  long currentModeBitsPerPixel = GetModeBitsPerPixel(CGDisplayCurrentMode(display));
+ 
+  unsigned int i;
+  for (i= 0; i<numberOfAvailableModes; ++i) {
+    // look at each mode in the available list
+    CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
+     
+    // we are only interested in modes with the same bits per pixel as current.
+    //   to allow for switching from fullscreen to windowed modes.
+    // that are safe for this hardward
+    // that are not stretched.
+    long bitsPerPixel = GetModeBitsPerPixel(mode);
+    Boolean safeForHardware = GetModeSafeForHardware(mode);
+    Boolean stretched = GetModeStretched(mode);
+   
+    if ((bitsPerPixel != currentModeBitsPerPixel) || (!safeForHardware) || (stretched)) {
+      continue; // skip this mode
+    }
+     
+    long width = GetModeWidth(mode);
+    long height = GetModeHeight(mode);
+    long refreshRate = GetModeRefreshRate(mode);     
+    Boolean replaced = false;
+    Boolean skipped = false;
+     
+    // now check to see if we already added a mode like this one.
+    //   we want the highest refresh rate for this width/height
+    unsigned int j;
+    unsigned int currentNumberOfUsefulModes =  CFArrayGetCount(usefulModes);
+    for (j = 0; j < currentNumberOfUsefulModes; ++j) {
+      CFDictionaryRef otherMode = (CFDictionaryRef)CFArrayGetValueAtIndex(usefulModes, j);       
+      long otherWidth = GetModeWidth(otherMode);
+      long otherHeight = GetModeHeight(otherMode);       
+      if ((otherWidth == width) && (otherHeight == height)) {
+        long otherRefreshRate = GetModeRefreshRate(otherMode);         
+        if (otherRefreshRate < refreshRate) {
+          // replace lower refresh rate.
+          const void* value = mode;
+          CFArrayReplaceValues(usefulModes, CFRangeMake(j ,1), &value, 1);
+          replaced = true;
+          break;
+        }
+        else if (otherRefreshRate > refreshRate) {
+          skipped = true;
+          break;
+        }
+      }
+    }     
+    // this is a useful mode so add it to the array.
+    if (!replaced && !skipped) {
+      CFArrayAppendValue(usefulModes, mode);
+    }     
+  }   
+  // now sort the useful mode array, using the comparison callback.
+  CFArraySortValues( usefulModes,
+    CFRangeMake(0, CFArrayGetCount(usefulModes)),
+    (CFComparatorFunction) CompareModes, NULL); 
+  // return the CFArray of the useful display modes.
+  return usefulModes;
+}
 
 
 TypeHandle osxGraphicsPipe::_type_handle;
 TypeHandle osxGraphicsPipe::_type_handle;
   
   
@@ -30,6 +169,26 @@ osxGraphicsPipe() {
   CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay);
   CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay);
   _display_width = CGRectGetWidth(display_bounds);
   _display_width = CGRectGetWidth(display_bounds);
   _display_height = CGRectGetHeight(display_bounds);
   _display_height = CGRectGetHeight(display_bounds);
+ 
+  CGDirectDisplayID display, displayArray[MAX_DISPLAYS] ;
+  CGDisplayCount numDisplays;
+  CFDictionaryRef displayMode; 
+  CFArrayRef displayModeArray;
+  int number, i; 
+  CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays);
+  display = displayArray [numDisplays - 1];
+  displayModeArray = GSCGDisplayAvailableModesUsefulForOpenGL( display );   
+  number = CFArrayGetCount( displayModeArray );
+  DisplayMode *displays = new DisplayMode[ number ]; 
+  for(i = 0; i < number; i++) {     
+     displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i);
+     _display_information -> _total_display_modes++;     
+     displays[i].width = (signed int)GetModeWidth (displayMode);
+     displays[i].height = (signed int)GetModeHeight (displayMode);
+     displays[i].bits_per_pixel = (signed int)GetModeBitsPerPixel (displayMode);
+     displays[i].refresh_rate = (signed int)GetModeRefreshRate (displayMode);
+  }   
+  _display_information -> _display_mode_array = displays;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////