7124247: [macosx] Implement GraphicsDevice.setDisplayMode()
authorkizune
Thu, 07 Jun 2012 20:04:56 +0400
changeset 12836 66cabfe1972f
parent 12834 6dc96f9ffb73
child 12837 a7d04f276889
7124247: [macosx] Implement GraphicsDevice.setDisplayMode() Reviewed-by: anthony, swingler
jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java
jdk/src/macosx/native/sun/awt/CGraphicsDevice.m
--- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java	Thu Jun 07 10:22:10 2012 +0800
+++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java	Thu Jun 07 20:04:56 2012 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 import java.awt.GraphicsDevice;
 import java.awt.Window;
 import java.awt.AWTPermission;
+import java.awt.DisplayMode;
 
 import sun.java2d.opengl.CGLGraphicsConfig;
 
@@ -178,4 +179,33 @@
             peer.exitFullScreenMode();
         }
     }
+
+    @Override
+    public boolean isDisplayChangeSupported() {
+        return true;
+    }
+
+    @Override
+    public void setDisplayMode(DisplayMode dm) {
+        nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), dm.getBitDepth(), dm.getRefreshRate());
+        if (isFullScreenSupported() && getFullScreenWindow() != null) {
+            getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight());
+        }
+    }
+
+    @Override
+    public DisplayMode getDisplayMode() {
+        return nativeGetDisplayMode(displayID);
+    }
+
+    @Override
+    public DisplayMode[] getDisplayModes() {
+        return nativeGetDisplayModes(displayID);
+    }
+
+    private native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
+
+    private native DisplayMode nativeGetDisplayMode(int displayID);
+
+    private native DisplayMode[] nativeGetDisplayModes(int displayID);
 }
--- a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m	Thu Jun 07 10:22:10 2012 +0800
+++ b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m	Thu Jun 07 20:04:56 2012 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,84 @@
 #include "LWCToolkit.h"
 
 /*
+ * Convert the mode string to the more convinient bits per pixel value
+ */
+static int getBPPFromModeString(CFStringRef mode) 
+{
+    if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
+        // This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits
+        // Java is not ready to work with this mode but we have to specify it as supported
+        return 30;
+    }
+    else if (CFStringCompare(mode, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+        return 32;
+    }
+    else if (CFStringCompare(mode, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+        return 16;
+    }
+    else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+        return 8;
+    }
+    
+    return 0;
+}
+
+/*
+ * Find the best possible match in the list of display modes that we can switch to based on
+ * the provided parameters.
+ */
+static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int h, int bpp, int refrate) {
+    CGDisplayModeRef bestGuess = NULL;
+    CFIndex numModes = CFArrayGetCount(allModes), n;
+    int thisBpp = 0;
+    for(n = 0; n < numModes; n++ ) {
+        CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
+        if(cRef == NULL) {
+            continue;
+        }
+        CFStringRef modeString = CGDisplayModeCopyPixelEncoding(cRef);
+        thisBpp = getBPPFromModeString(modeString);
+        CFRelease(modeString);
+        if (thisBpp != bpp || (int)CGDisplayModeGetHeight(cRef) != h || (int)CGDisplayModeGetWidth(cRef) != w) {
+            // One of the key parameters does not match
+            continue;
+        }
+        // Refresh rate might be 0 in display mode and we ask for specific display rate
+        // but if we do not find exact match then 0 refresh rate might be just Ok
+        if (CGDisplayModeGetRefreshRate(cRef) == refrate) {
+            // Exact match
+            return cRef;
+        }
+        if (CGDisplayModeGetRefreshRate(cRef) == 0) {
+            // Not exactly what was asked for, but may fit our needs if we don't find an exact match
+            bestGuess = cRef;
+        }
+    }
+    return bestGuess;
+}
+
+/*
+ * Create a new java.awt.DisplayMode instance based on provided CGDisplayModeRef
+ */
+static jobject createJavaDisplayMode(CGDisplayModeRef mode, JNIEnv *env, jint displayID) {
+    jobject ret = NULL;
+    jint h, w, bpp, refrate;
+    JNF_COCOA_ENTER(env);
+    CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
+    bpp = getBPPFromModeString(currentBPP);
+    refrate = CGDisplayModeGetRefreshRate(mode);
+    h = CGDisplayPixelsHigh(displayID);
+    w = CGDisplayPixelsWide(displayID);
+    CFRelease(currentBPP);
+    static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");
+    static JNF_CTOR_CACHE(jc_DisplayMode_ctor, jc_DisplayMode, "(IIII)V");
+    ret = JNFNewObject(env, jc_DisplayMode_ctor, w, h, bpp, refrate);
+    JNF_COCOA_EXIT(env);
+    return ret;
+}
+
+
+/*
  * Class:     sun_awt_CGraphicsDevice
  * Method:    nativeGetXResolution
  * Signature: (I)D
@@ -62,3 +140,85 @@
     jfloat dpi = rect.size.height / inches;
     return dpi;
 }
+
+/*
+ * Class:     sun_awt_CGraphicsDevice
+ * Method:    nativeSetDisplayMode
+ * Signature: (IIIII)V
+ */
+JNIEXPORT void JNICALL
+Java_sun_awt_CGraphicsDevice_nativeSetDisplayMode
+(JNIEnv *env, jclass class, jint displayID, jint w, jint h, jint bpp, jint refrate)
+{
+    JNF_COCOA_ENTER(env);
+    CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL);
+    CGDisplayModeRef closestMatch = getBestModeForParameters(allModes, (int)w, (int)h, (int)bpp, (int)refrate);
+    if (closestMatch != NULL) {
+        CGDisplayConfigRef config;
+        CGError retCode = CGBeginDisplayConfiguration(&config);
+        if (retCode == kCGErrorSuccess) {
+            CGConfigureDisplayWithDisplayMode(config, displayID, closestMatch, NULL);
+            CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly);
+            CFRelease(config);
+        }
+    }
+    CFRelease(allModes);
+    JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_awt_CGraphicsDevice
+ * Method:    nativeGetDisplayMode
+ * Signature: (I)Ljava/awt/DisplayMode
+ */
+JNIEXPORT jobject JNICALL
+Java_sun_awt_CGraphicsDevice_nativeGetDisplayMode
+(JNIEnv *env, jclass class, jint displayID)
+{
+    jobject ret = NULL;
+    CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
+    ret = createJavaDisplayMode(currentMode, env, displayID);
+    CGDisplayModeRelease(currentMode);
+    return ret;
+}
+
+/*
+ * Class:     sun_awt_CGraphicsDevice
+ * Method:    nativeGetDisplayMode
+ * Signature: (I)[Ljava/awt/DisplayModes
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
+(JNIEnv *env, jclass class, jint displayID)
+{
+    jobjectArray jreturnArray = NULL;
+    JNF_COCOA_ENTER(env);
+    CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL);
+    CFIndex numModes = CFArrayGetCount(allModes);
+    static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");
+
+    jreturnArray = JNFNewObjectArray(env, &jc_DisplayMode, (jsize) numModes);
+    if (!jreturnArray) {
+        NSLog(@"CGraphicsDevice can't create java array of DisplayMode objects");
+        return nil;
+    }
+
+    CFIndex n;
+    for (n=0; n < numModes; n++) {
+        CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
+        if (cRef != NULL) {
+            jobject oneMode = createJavaDisplayMode(cRef, env, displayID);
+            (*env)->SetObjectArrayElement(env, jreturnArray, n, oneMode);
+            if ((*env)->ExceptionOccurred(env)) {
+                (*env)->ExceptionDescribe(env);
+                (*env)->ExceptionClear(env);
+                continue;
+            }
+            (*env)->DeleteLocalRef(env, oneMode);
+        }
+    }
+    CFRelease(allModes);
+    JNF_COCOA_EXIT(env);
+
+    return jreturnArray;
+}