1 /* 2 * Copyright (c) 2011, 2014, 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 <JavaNativeFoundation/JavaNativeFoundation.h> 27 28 #import "jni_util.h" 29 #import "LWCToolkit.h" 30 #import "AWT_debug.h" 31 32 33 /* 34 * Class: sun_awt_CGraphicsEnvironment 35 * Method: initCocoa 36 * Signature: ()V 37 */ 38 JNIEXPORT void JNICALL 39 Java_sun_awt_CGraphicsEnvironment_initCocoa 40 (JNIEnv *env, jclass self) 41 { 42 JNF_COCOA_ENTER(env); 43 44 // Inform Cocoa that we're multi-threaded. 45 // Creating a short-lived NSThread is the recommended way of doing so. 46 [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSObject class] withObject:nil]; 47 48 JNF_COCOA_EXIT(env); 49 } 50 51 #define MAX_DISPLAYS 64 52 53 /* 54 * Class: sun_awt_CGraphicsEnvironment 55 * Method: getDisplayIDs 56 * Signature: ()[I 57 */ 58 JNIEXPORT jintArray JNICALL 59 Java_sun_awt_CGraphicsEnvironment_getDisplayIDs 60 (JNIEnv *env, jclass class) 61 { 62 jintArray ret = NULL; 63 64 JNF_COCOA_ENTER(env); 65 66 /* Get the count */ 67 CGDisplayCount displayCount; 68 if (CGGetOnlineDisplayList(MAX_DISPLAYS, NULL, &displayCount) != kCGErrorSuccess) { 69 [JNFException raise:env 70 as:kInternalError 71 reason:"CGGetOnlineDisplayList() failed to get display count"]; 72 return NULL; 73 } 74 75 /* Allocate an array and get the size list of display Ids */ 76 CGDirectDisplayID displays[MAX_DISPLAYS]; 77 if (CGGetOnlineDisplayList(displayCount, displays, &displayCount) != kCGErrorSuccess) { 78 [JNFException raise:env 79 as:kInternalError 80 reason:"CGGetOnlineDisplayList() failed to get display list"]; 81 return NULL; 82 } 83 84 CGDisplayCount i; 85 CGDisplayCount displayActiveCount = 0; //Active and sleeping. 86 for (i = 0; i < displayCount; ++i) { 87 if (CGDisplayMirrorsDisplay(displays[i]) == kCGNullDirectDisplay) { 88 ++displayActiveCount; 89 } else { 90 displays[i] = kCGNullDirectDisplay; 91 } 92 } 93 94 /* Allocate a java array for display identifiers */ 95 ret = JNFNewIntArray(env, displayActiveCount); 96 97 /* Initialize and return the backing int array */ 98 assert(sizeof(jint) >= sizeof(CGDirectDisplayID)); 99 jint *elems = (*env)->GetIntArrayElements(env, ret, 0); 100 CHECK_NULL_RETURN(elems, NULL); 101 102 /* Filter out the mirrored displays */ 103 for (i = 0; i < displayCount; ++i) { 104 if (displays[i] != kCGNullDirectDisplay) { 105 elems[--displayActiveCount] = displays[i]; 106 } 107 } 108 109 (*env)->ReleaseIntArrayElements(env, ret, elems, 0); 110 111 JNF_COCOA_EXIT(env); 112 113 return ret; 114 } 115 116 /* 117 * Class: sun_awt_CGraphicsEnvironment 118 * Method: getMainDisplayID 119 * Signature: ()I 120 */ 121 JNIEXPORT jint JNICALL 122 Java_sun_awt_CGraphicsEnvironment_getMainDisplayID 123 (JNIEnv *env, jclass class) 124 { 125 return CGMainDisplayID(); 126 } 127 128 /* 129 * Post the display reconfiguration event. 130 */ 131 static void displaycb_handle 132 (CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo) 133 { 134 if (flags == kCGDisplayBeginConfigurationFlag) return; 135 136 JNFPerformEnvBlock(JNFThreadDetachImmediately, ^(JNIEnv *env) { 137 JNFWeakJObjectWrapper *wrapper = (JNFWeakJObjectWrapper *)userInfo; 138 139 jobject graphicsEnv = [wrapper jObjectWithEnv:env]; 140 if (graphicsEnv == NULL) return; // ref already GC'd 141 static JNF_CLASS_CACHE(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment"); 142 static JNF_MEMBER_CACHE(jm_displayReconfiguration, jc_CGraphicsEnvironment, "_displayReconfiguration", "(IZ)V"); 143 JNFCallVoidMethod(env, graphicsEnv, jm_displayReconfiguration, 144 (jint) display, 145 (jboolean) flags & kCGDisplayRemoveFlag); 146 }); 147 } 148 149 /* 150 * Class: sun_awt_CGraphicsEnvironment 151 * Method: registerDisplayReconfiguration 152 * Signature: ()J 153 */ 154 JNIEXPORT jlong JNICALL 155 Java_sun_awt_CGraphicsEnvironment_registerDisplayReconfiguration 156 (JNIEnv *env, jobject this) 157 { 158 jlong ret = 0L; 159 160 JNF_COCOA_ENTER(env); 161 162 JNFWeakJObjectWrapper *wrapper = [[JNFWeakJObjectWrapper wrapperWithJObject:this withEnv:env] retain]; 163 164 /* Register the callback */ 165 if (CGDisplayRegisterReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 166 [JNFException raise:env 167 as:kInternalError 168 reason:"CGDisplayRegisterReconfigurationCallback() failed"]; 169 return 0L; 170 } 171 172 ret = ptr_to_jlong(wrapper); 173 174 JNF_COCOA_EXIT(env); 175 176 return ret; 177 } 178 179 /* 180 * Class: sun_awt_CGraphicsEnvironment 181 * Method: deregisterDisplayReconfiguration 182 * Signature: (J)V 183 */ 184 JNIEXPORT void JNICALL 185 Java_sun_awt_CGraphicsEnvironment_deregisterDisplayReconfiguration 186 (JNIEnv *env, jobject this, jlong p) 187 { 188 JNF_COCOA_ENTER(env); 189 190 JNFWeakJObjectWrapper *wrapper = (JNFWeakJObjectWrapper *)jlong_to_ptr(p); 191 if (!wrapper) return; 192 193 /* Remove the registration */ 194 if (CGDisplayRemoveReconfigurationCallback(&displaycb_handle, wrapper) != kCGErrorSuccess) { 195 [JNFException raise:env 196 as:kInternalError 197 reason:"CGDisplayRemoveReconfigurationCallback() failed, leaking the callback context!"]; 198 return; 199 } 200 201 [wrapper setJObject:NULL withEnv:env]; // more efficiant to pre-clear 202 [wrapper release]; 203 204 JNF_COCOA_EXIT(env); 205 }