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 }); 131 }]; 132 } 133 134 /* 135 * Class: sun_awt_CGraphicsEnvironment 136 * Method: registerDisplayReconfiguration 137 * Signature: ()J 138 */ 139 JNIEXPORT jlong JNICALL 140 Java_sun_awt_CGraphicsEnvironment_registerDisplayReconfiguration 141 (JNIEnv *env, jobject this) 142 { 143 jlong ret = 0L; 144 145 JNF_COCOA_ENTER(env); 146 147 JNFWeakJObjectWrapper *wrapper = [[JNFWeakJObjectWrapper wrapperWithJObject:this withEnv:env] retain]; 148 149 /* Register the callback */ 150 if (CGDisplayRegisterReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 151 [JNFException raise:env 152 as:kInternalError 153 reason:"CGDisplayRegisterReconfigurationCallback() failed"]; 154 return 0L; 155 } 156 157 ret = ptr_to_jlong(wrapper); 158 159 JNF_COCOA_EXIT(env); 160 161 return ret; 162 } 163 164 /* 165 * Class: sun_awt_CGraphicsEnvironment 166 * Method: deregisterDisplayReconfiguration 167 * Signature: (J)V 168 */ 169 JNIEXPORT void JNICALL 170 Java_sun_awt_CGraphicsEnvironment_deregisterDisplayReconfiguration 171 (JNIEnv *env, jobject this, jlong p) 172 { 173 JNF_COCOA_ENTER(env); 174 175 JNFWeakJObjectWrapper *wrapper = (JNFWeakJObjectWrapper *)jlong_to_ptr(p); 176 if (!wrapper) return; 177 178 /* Remove the registration */ 179 if (CGDisplayRemoveReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 180 [JNFException raise:env 181 as:kInternalError 182 reason:"CGDisplayRemoveReconfigurationCallback() failed, leaking the callback context!"]; 183 return; 184 } 185 186 [wrapper setJObject:NULL withEnv:env]; // more efficiant to pre-clear 187 [wrapper release]; 188 189 JNF_COCOA_EXIT(env); 190 }