diff --git a/src/macosx/classes/sun/awt/CGraphicsDevice.java b/src/macosx/classes/sun/awt/CGraphicsDevice.java index 02f743d3e727747e995df35de3730a8713932a90..dba798062dfc70e2f28e2c4a07530181e9c162dc 100644 --- a/src/macosx/classes/sun/awt/CGraphicsDevice.java +++ b/src/macosx/classes/sun/awt/CGraphicsDevice.java @@ -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.GraphicsConfiguration; 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 @@ public class CGraphicsDevice extends GraphicsDevice { 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); } diff --git a/src/macosx/native/sun/awt/CGraphicsDevice.m b/src/macosx/native/sun/awt/CGraphicsDevice.m index 0d7846988fc17fc09d699ed0c18080391275611c..f24a86283b97c371af8cd3697d89d6bd5f9da110 100644 --- a/src/macosx/native/sun/awt/CGraphicsDevice.m +++ b/src/macosx/native/sun/awt/CGraphicsDevice.m @@ -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 @@ -25,6 +25,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 @@ -62,3 +140,85 @@ Java_sun_awt_CGraphicsDevice_nativeGetYResolution 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; +}