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 "CDataTransferer.h" 27 #import "ThreadUtilities.h" 28 #import "jni_util.h" 29 #import <Cocoa/Cocoa.h> 30 #import <JavaNativeFoundation/JavaNativeFoundation.h> 31 32 @interface CClipboard : NSObject { } 33 @property NSInteger changeCount; 34 @property jobject clipboardOwner; 35 36 + (CClipboard*)sharedClipboard; 37 - (void)declareTypes:(NSArray *)types withOwner:(jobject)owner jniEnv:(JNIEnv*)env; 38 - (void)checkPasteboard:(id)sender; 39 @end 40 41 @implementation CClipboard 42 @synthesize changeCount = _changeCount; 43 @synthesize clipboardOwner = _clipboardOwner; 44 45 // Clipboard creation is synchronized at the Java level 46 + (CClipboard*)sharedClipboard { 47 static CClipboard* sClipboard = nil; 48 if (sClipboard == nil) { 49 sClipboard = [[CClipboard alloc] init]; 50 [[NSNotificationCenter defaultCenter] addObserver:sClipboard selector: @selector(checkPasteboard:) 51 name: NSApplicationDidBecomeActiveNotification 52 object: nil]; 53 } 54 55 return sClipboard; 56 } 57 58 - (id)init { 59 if (self = [super init]) { 60 self.changeCount = [[NSPasteboard generalPasteboard] changeCount]; 61 } 62 return self; 63 } 64 65 - (void)declareTypes:(NSArray*)types withOwner:(jobject)owner jniEnv:(JNIEnv*)env { 66 @synchronized(self) { 67 if (owner != NULL) { 68 if (self.clipboardOwner != NULL) { 69 JNFDeleteGlobalRef(env, self.clipboardOwner); 70 } 71 self.clipboardOwner = JNFNewGlobalRef(env, owner); 72 } 73 } 74 [ThreadUtilities performOnMainThreadWaiting:YES block:^() { 75 self.changeCount = [[NSPasteboard generalPasteboard] declareTypes:types owner:self]; 76 }]; 77 } 78 79 - (void)checkPasteboard:(id)sender { 80 81 NSInteger newChangeCount = [[NSPasteboard generalPasteboard] changeCount]; 82 83 if (self.changeCount != newChangeCount) { 84 self.changeCount = newChangeCount; 85 86 // Notify that the content might be changed 87 static JNF_CLASS_CACHE(jc_CClipboard, "sun/lwawt/macosx/CClipboard"); 88 static JNF_STATIC_MEMBER_CACHE(jm_contentChanged, jc_CClipboard, "notifyChanged", "()V"); 89 JNIEnv *env = [ThreadUtilities getJNIEnv]; 90 JNFCallStaticVoidMethod(env, jm_contentChanged); 91 92 // If we have a Java pasteboard owner, tell it that it doesn't own the pasteboard anymore. 93 static JNF_MEMBER_CACHE(jm_lostOwnership, jc_CClipboard, "notifyLostOwnership", "()V"); 94 @synchronized(self) { 95 if (self.clipboardOwner) { 96 JNIEnv *env = [ThreadUtilities getJNIEnv]; 97 JNFCallVoidMethod(env, self.clipboardOwner, jm_lostOwnership); // AWT_THREADING Safe (event) 98 JNFDeleteGlobalRef(env, self.clipboardOwner); 99 self.clipboardOwner = NULL; 100 } 101 } 102 } 103 } 104 105 @end 106 107 /* 108 * Class: sun_lwawt_macosx_CClipboard 109 * Method: declareTypes 110 * Signature: ([JLsun/awt/datatransfer/SunClipboard;)V 111 */ 112 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CClipboard_declareTypes 113 (JNIEnv *env, jobject inObject, jlongArray inTypes, jobject inJavaClip) 114 { 115 JNF_COCOA_ENTER(env); 116 117 jint i; 118 jint nElements = (*env)->GetArrayLength(env, inTypes); 119 NSMutableArray *formatArray = [NSMutableArray arrayWithCapacity:nElements]; 120 jlong *elements = (*env)->GetPrimitiveArrayCritical(env, inTypes, NULL); 121 122 for (i = 0; i < nElements; i++) { 123 NSString *pbFormat = formatForIndex(elements[i]); 124 if (pbFormat) 125 [formatArray addObject:pbFormat]; 126 } 127 128 (*env)->ReleasePrimitiveArrayCritical(env, inTypes, elements, JNI_ABORT); 129 [[CClipboard sharedClipboard] declareTypes:formatArray withOwner:inJavaClip jniEnv:env]; 130 JNF_COCOA_EXIT(env); 131 } 132 133 /* 134 * Class: sun_lwawt_macosx_CClipboard 135 * Method: setData 136 * Signature: ([BJ)V 137 */ 138 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CClipboard_setData 139 (JNIEnv *env, jobject inObject, jbyteArray inBytes, jlong inFormat) 140 { 141 if (inBytes == NULL) { 142 return; 143 } 144 145 JNF_COCOA_ENTER(env); 146 jint nBytes = (*env)->GetArrayLength(env, inBytes); 147 jbyte *rawBytes = (*env)->GetPrimitiveArrayCritical(env, inBytes, NULL); 148 CHECK_NULL(rawBytes); 149 NSData *bytesAsData = [NSData dataWithBytes:rawBytes length:nBytes]; 150 (*env)->ReleasePrimitiveArrayCritical(env, inBytes, rawBytes, JNI_ABORT); 151 NSString *format = formatForIndex(inFormat); 152 [ThreadUtilities performOnMainThreadWaiting:YES block:^() { 153 [[NSPasteboard generalPasteboard] setData:bytesAsData forType:format]; 154 }]; 155 JNF_COCOA_EXIT(env); 156 } 157 158 /* 159 * Class: sun_lwawt_macosx_CClipboard 160 * Method: getClipboardFormats 161 * Signature: (J)[J 162 */ 163 JNIEXPORT jlongArray JNICALL Java_sun_lwawt_macosx_CClipboard_getClipboardFormats 164 (JNIEnv *env, jobject inObject) 165 { 166 jlongArray returnValue = NULL; 167 JNF_COCOA_ENTER(env); 168 169 __block NSArray* dataTypes; 170 [ThreadUtilities performOnMainThreadWaiting:YES block:^() { 171 dataTypes = [[[NSPasteboard generalPasteboard] types] retain]; 172 }]; 173 [dataTypes autorelease]; 174 175 NSUInteger nFormats = [dataTypes count]; 176 NSUInteger knownFormats = 0; 177 NSUInteger i; 178 179 // There can be any number of formats on the general pasteboard. Find out which ones 180 // we know about (i.e., live in the flavormap.properties). 181 for (i = 0; i < nFormats; i++) { 182 NSString *format = (NSString *)[dataTypes objectAtIndex:i]; 183 if (indexForFormat(format) != -1) 184 knownFormats++; 185 } 186 187 returnValue = (*env)->NewLongArray(env, knownFormats); 188 if (returnValue == NULL) { 189 return NULL; 190 } 191 192 if (knownFormats == 0) { 193 return returnValue; 194 } 195 196 // Now go back and map the formats we found back to Java indexes. 197 jboolean isCopy; 198 jlong *lFormats = (*env)->GetLongArrayElements(env, returnValue, &isCopy); 199 jlong *saveFormats = lFormats; 200 201 for (i = 0; i < nFormats; i++) { 202 NSString *format = (NSString *)[dataTypes objectAtIndex:i]; 203 jlong index = indexForFormat(format); 204 205 if (index != -1) { 206 *lFormats = index; 207 lFormats++; 208 } 209 } 210 211 (*env)->ReleaseLongArrayElements(env, returnValue, saveFormats, JNI_COMMIT); 212 JNF_COCOA_EXIT(env); 213 return returnValue; 214 } 215 216 /* 217 * Class: sun_lwawt_macosx_CClipboard 218 * Method: getClipboardData 219 * Signature: (JJ)[B 220 */ 221 JNIEXPORT jbyteArray JNICALL Java_sun_lwawt_macosx_CClipboard_getClipboardData 222 (JNIEnv *env, jobject inObject, jlong format) 223 { 224 jbyteArray returnValue = NULL; 225 226 // Note that this routine makes no attempt to interpret the data, since we're returning 227 // a byte array back to Java. CDataTransferer will do that if necessary. 228 JNF_COCOA_ENTER(env); 229 230 NSString *formatAsString = formatForIndex(format); 231 __block NSData* clipData; 232 [ThreadUtilities performOnMainThreadWaiting:YES block:^() { 233 clipData = [[[NSPasteboard generalPasteboard] dataForType:formatAsString] retain]; 234 }]; 235 236 if (clipData == NULL) { 237 [JNFException raise:env as:"java/io/IOException" reason:"Font transform has NaN position"]; 238 return NULL; 239 } else { 240 [clipData autorelease]; 241 } 242 243 NSUInteger dataSize = [clipData length]; 244 returnValue = (*env)->NewByteArray(env, dataSize); 245 if (returnValue == NULL) { 246 return NULL; 247 } 248 249 if (dataSize != 0) { 250 const void *dataBuffer = [clipData bytes]; 251 (*env)->SetByteArrayRegion(env, returnValue, 0, dataSize, (jbyte *)dataBuffer); 252 } 253 254 JNF_COCOA_EXIT(env); 255 return returnValue; 256 } 257 258 /* 259 * Class: sun_lwawt_macosx_CClipboard 260 * Method: checkPasteboard 261 * Signature: ()V 262 */ 263 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CClipboard_checkPasteboard 264 (JNIEnv *env, jobject inObject ) 265 { 266 JNF_COCOA_ENTER(env); 267 268 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 269 [[CClipboard sharedClipboard] checkPasteboard:nil]; 270 }]; 271 272 JNF_COCOA_EXIT(env); 273 } 274 275