1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "AWT_debug.h" 27 28 #import "jni_util.h" 29 #import "ThreadUtilities.h" 30 31 #import <JavaNativeFoundation/JavaNativeFoundation.h> 32 33 #define MAX_DISPLAYS 64 34 35 /* 36 * Class: sun_awt_CGraphicsEnvironment 37 * Method: getDisplayIDs 38 * Signature: ()[I 39 */ 40 JNIEXPORT jintArray JNICALL 41 Java_sun_awt_CGraphicsEnvironment_getDisplayIDs 42 (JNIEnv *env, jclass class) 43 { 44 jintArray ret = NULL; 45 46 JNF_COCOA_ENTER(env); 47 48 /* Get the count */ 49 CGDisplayCount displayCount; 50 if (CGGetOnlineDisplayList(MAX_DISPLAYS, NULL, &displayCount) != kCGErrorSuccess) { 51 [JNFException raise:env 52 as:kInternalError 53 reason:"CGGetOnlineDisplayList() failed to get display count"]; 54 return NULL; 55 } 56 57 /* Allocate an array and get the size list of display Ids */ 58 CGDirectDisplayID displays[MAX_DISPLAYS]; 59 if (CGGetOnlineDisplayList(displayCount, displays, &displayCount) != kCGErrorSuccess) { 60 [JNFException raise:env 61 as:kInternalError 62 reason:"CGGetOnlineDisplayList() failed to get display list"]; 63 return NULL; 64 } 65 66 CGDisplayCount i; 67 CGDisplayCount displayActiveCount = 0; //Active and sleeping. 68 for (i = 0; i < displayCount; ++i) { 69 if (CGDisplayMirrorsDisplay(displays[i]) == kCGNullDirectDisplay) { 70 ++displayActiveCount; 71 } else { 72 displays[i] = kCGNullDirectDisplay; 73 } 74 } 75 76 /* Allocate a java array for display identifiers */ 77 ret = JNFNewIntArray(env, displayActiveCount); 78 79 /* Initialize and return the backing int array */ 80 assert(sizeof(jint) >= sizeof(CGDirectDisplayID)); 81 jint *elems = (*env)->GetIntArrayElements(env, ret, 0); 82 CHECK_NULL_RETURN(elems, NULL); 83 84 /* Filter out the mirrored displays */ 85 for (i = 0; i < displayCount; ++i) { 86 if (displays[i] != kCGNullDirectDisplay) { 87 elems[--displayActiveCount] = displays[i]; 88 } 89 } 90 91 (*env)->ReleaseIntArrayElements(env, ret, elems, 0); 92 93 JNF_COCOA_EXIT(env); 94 95 return ret; 96 } 97 98 /* 99 * Class: sun_awt_CGraphicsEnvironment 100 * Method: getMainDisplayID 101 * Signature: ()I 102 */ 103 JNIEXPORT jint JNICALL 104 Java_sun_awt_CGraphicsEnvironment_getMainDisplayID 105 (JNIEnv *env, jclass class) 106 { 107 return CGMainDisplayID(); 108 } 109 110 /* 111 * Post the display reconfiguration event. 112 */ 113 static void displaycb_handle 114 (CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo) 115 { 116 if (flags == kCGDisplayBeginConfigurationFlag) return; 117 118 [ThreadUtilities performOnMainThreadWaiting:NO block:^() { 119 120 JNFPerformEnvBlock(JNFThreadDetachImmediately, ^(JNIEnv *env) { 121 JNFWeakJObjectWrapper *wrapper = (JNFWeakJObjectWrapper *)userInfo; 122 123 jobject graphicsEnv = [wrapper jObjectWithEnv:env]; 124 if (graphicsEnv == NULL) return; // ref already GC'd 125 static JNF_CLASS_CACHE(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment"); 126 static JNF_MEMBER_CACHE(jm_displayReconfiguration, 127 jc_CGraphicsEnvironment, "_displayReconfiguration","(IZ)V"); 128 JNFCallVoidMethod(env, graphicsEnv, jm_displayReconfiguration, 129 (jint) display, (jboolean) flags & kCGDisplayRemoveFlag); 130 (*env)->DeleteLocalRef(env, graphicsEnv); 131 }); 132 }]; 133 } 134 135 /* 136 * Class: sun_awt_CGraphicsEnvironment 137 * Method: registerDisplayReconfiguration 138 * Signature: ()J 139 */ 140 JNIEXPORT jlong JNICALL 141 Java_sun_awt_CGraphicsEnvironment_registerDisplayReconfiguration 142 (JNIEnv *env, jobject this) 143 { 144 jlong ret = 0L; 145 146 JNF_COCOA_ENTER(env); 147 148 JNFWeakJObjectWrapper *wrapper = [[JNFWeakJObjectWrapper wrapperWithJObject:this withEnv:env] retain]; 149 150 /* Register the callback */ 151 if (CGDisplayRegisterReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 152 [JNFException raise:env 153 as:kInternalError 154 reason:"CGDisplayRegisterReconfigurationCallback() failed"]; 155 return 0L; 156 } 157 158 ret = ptr_to_jlong(wrapper); 159 160 JNF_COCOA_EXIT(env); 161 162 return ret; 163 } 164 165 /* 166 * Class: sun_awt_CGraphicsEnvironment 167 * Method: deregisterDisplayReconfiguration 168 * Signature: (J)V 169 */ 170 JNIEXPORT void JNICALL 171 Java_sun_awt_CGraphicsEnvironment_deregisterDisplayReconfiguration 172 (JNIEnv *env, jobject this, jlong p) 173 { 174 JNF_COCOA_ENTER(env); 175 176 JNFWeakJObjectWrapper *wrapper = (JNFWeakJObjectWrapper *)jlong_to_ptr(p); 177 if (!wrapper) return; 178 179 /* Remove the registration */ 180 if (CGDisplayRemoveReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 181 [JNFException raise:env 182 as:kInternalError 183 reason:"CGDisplayRemoveReconfigurationCallback() failed, leaking the callback context!"]; 184 return; 185 } 186 187 [wrapper setJObject:NULL withEnv:env]; // more efficiant to pre-clear 188 [wrapper release]; 189 190 JNF_COCOA_EXIT(env); 191 }