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