1 /*
2 * Copyright (c) 1996, 2011, 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 #include "awt_Clipboard.h"
27 #include "awt_DataTransferer.h"
28 #include "awt_Toolkit.h"
29 #include <shlobj.h>
30 #include <sun_awt_windows_WClipboard.h>
31
32
33 /************************************************************************
34 * AwtClipboard fields
35 */
36
37 jmethodID AwtClipboard::lostSelectionOwnershipMID;
38 jobject AwtClipboard::theCurrentClipboard;
39
40 /* This flag is set while we call EmptyClipboard to indicate to
41 WM_DESTROYCLIPBOARD handler that we are not losing ownership */
42 BOOL AwtClipboard::isGettingOwnership = FALSE;
43
44 volatile jmethodID AwtClipboard::handleContentsChangedMID;
45 volatile BOOL AwtClipboard::skipInitialWmDrawClipboardMsg = TRUE;
46 volatile BOOL AwtClipboard::isClipboardViewerRegistered = FALSE;
47 volatile HWND AwtClipboard::hwndNextViewer = NULL;
48
49 #define GALLOCFLG (GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT)
50
51 /************************************************************************
52 * AwtClipboard methods
53 */
54
LostOwnership(JNIEnv * env)55 void AwtClipboard::LostOwnership(JNIEnv *env) {
56 if (theCurrentClipboard != NULL) {
57 env->CallVoidMethod(theCurrentClipboard, lostSelectionOwnershipMID);
58 DASSERT(!safe_ExceptionOccurred(env));
59 }
60 }
61
WmChangeCbChain(WPARAM wParam,LPARAM lParam)62 void AwtClipboard::WmChangeCbChain(WPARAM wParam, LPARAM lParam) {
63 if ((HWND)wParam == hwndNextViewer) {
64 hwndNextViewer = (HWND)lParam;
65 } else if (hwndNextViewer != NULL) {
66 ::SendMessage(hwndNextViewer, WM_CHANGECBCHAIN, wParam, lParam);
67 }
68 }
69
WmDrawClipboard(JNIEnv * env,WPARAM wParam,LPARAM lParam)70 void AwtClipboard::WmDrawClipboard(JNIEnv *env, WPARAM wParam, LPARAM lParam) {
71 if (skipInitialWmDrawClipboardMsg) {
72 // skipping the first contents change notification as it comes
73 // immediately after registering the clipboard viewer window
74 // and it is not caused by an actual contents change.
75 skipInitialWmDrawClipboardMsg = FALSE;
76 return;
77 }
78 if (theCurrentClipboard != NULL) {
79 env->CallVoidMethod(theCurrentClipboard, handleContentsChangedMID);
80 DASSERT(!safe_ExceptionOccurred(env));
81 }
82 ::SendMessage(hwndNextViewer, WM_DRAWCLIPBOARD, wParam, lParam);
83 }
84
RegisterClipboardViewer(JNIEnv * env,jobject jclipboard)85 void AwtClipboard::RegisterClipboardViewer(JNIEnv *env, jobject jclipboard) {
86 if (isClipboardViewerRegistered) {
87 return;
88 }
89
90 if (theCurrentClipboard == NULL) {
91 theCurrentClipboard = env->NewGlobalRef(jclipboard);
92 }
93
94 jclass cls = env->GetObjectClass(jclipboard);
95 AwtClipboard::handleContentsChangedMID =
96 env->GetMethodID(cls, "handleContentsChanged", "()V");
97 DASSERT(AwtClipboard::handleContentsChangedMID != NULL);
98
99 hwndNextViewer = ::SetClipboardViewer(AwtToolkit::GetInstance().GetHWnd());
100 isClipboardViewerRegistered = TRUE;
101 }
102
UnregisterClipboardViewer(JNIEnv * env)103 void AwtClipboard::UnregisterClipboardViewer(JNIEnv *env) {
104 TRY;
105
106 if (isClipboardViewerRegistered) {
107 ::ChangeClipboardChain(AwtToolkit::GetInstance().GetHWnd(), AwtClipboard::hwndNextViewer);
108 AwtClipboard::hwndNextViewer = NULL;
109 isClipboardViewerRegistered = FALSE;
110 skipInitialWmDrawClipboardMsg = TRUE;
111 }
112
113 CATCH_BAD_ALLOC;
114 }
115
116 extern "C" {
117
awt_clipboard_uninitialize(JNIEnv * env)118 void awt_clipboard_uninitialize(JNIEnv *env) {
119 AwtClipboard::UnregisterClipboardViewer(env);
120 env->DeleteGlobalRef(AwtClipboard::theCurrentClipboard);
121 AwtClipboard::theCurrentClipboard = NULL;
122 }
123
124 /************************************************************************
125 * WClipboard native methods
126 */
127
128 /*
129 * Class: sun_awt_windows_WClipboard
130 * Method: init
131 * Signature: ()V
132 */
133 JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_init(JNIEnv * env,jclass cls)134 Java_sun_awt_windows_WClipboard_init(JNIEnv *env, jclass cls)
135 {
136 TRY;
137
138 AwtClipboard::lostSelectionOwnershipMID =
139 env->GetMethodID(cls, "lostSelectionOwnershipImpl", "()V");
140 DASSERT(AwtClipboard::lostSelectionOwnershipMID != NULL);
141
142 CATCH_BAD_ALLOC;
143 }
144
145 /*
146 * Class: sun_awt_windows_WClipboard
147 * Method: openClipboard
148 * Signature: (Lsun/awt/windows/WClipboard;)V
149 */
150 JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_openClipboard(JNIEnv * env,jobject self,jobject newOwner)151 Java_sun_awt_windows_WClipboard_openClipboard(JNIEnv *env, jobject self,
152 jobject newOwner)
153 {
154 TRY;
155
156 DASSERT(::GetOpenClipboardWindow() != AwtToolkit::GetInstance().GetHWnd());
157
158 if (!::OpenClipboard(AwtToolkit::GetInstance().GetHWnd())) {
159 JNU_ThrowByName(env, "java/lang/IllegalStateException",
160 "cannot open system clipboard");
161 return;
162 }
163 if (newOwner != NULL) {
164 AwtClipboard::GetOwnership();
165 if (AwtClipboard::theCurrentClipboard != NULL) {
166 env->DeleteGlobalRef(AwtClipboard::theCurrentClipboard);
167 }
168 AwtClipboard::theCurrentClipboard = env->NewGlobalRef(newOwner);
169 }
170
171 CATCH_BAD_ALLOC;
172 }
173
174 /*
175 * Class: sun_awt_windows_WClipboard
176 * Method: closeClipboard
177 * Signature: ()V
178 */
179 JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_closeClipboard(JNIEnv * env,jobject self)180 Java_sun_awt_windows_WClipboard_closeClipboard(JNIEnv *env, jobject self)
181 {
182 TRY;
183
184 if (::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd()) {
185 VERIFY(::CloseClipboard());
186 }
187
188 CATCH_BAD_ALLOC;
189 }
190
191 /*
192 * Class: sun_awt_windows_WClipboard
193 * Method: registerClipboardViewer
194 * Signature: ()V
195 */
196 JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_registerClipboardViewer(JNIEnv * env,jobject self)197 Java_sun_awt_windows_WClipboard_registerClipboardViewer(JNIEnv *env, jobject self)
198 {
199 TRY;
200
201 AwtClipboard::RegisterClipboardViewer(env, self);
202
203 CATCH_BAD_ALLOC;
204 }
205
206 /*
207 * Class: sun_awt_windows_WClipboard
208 * Method: publishClipboardData
209 * Signature: (J[B)V
210 */
211 JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_publishClipboardData(JNIEnv * env,jobject self,jlong format,jbyteArray bytes)212 Java_sun_awt_windows_WClipboard_publishClipboardData(JNIEnv *env,
213 jobject self,
214 jlong format,
215 jbyteArray bytes)
216 {
217 TRY;
218
219 DASSERT(::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd());
220
221 if (bytes == NULL) {
222 return;
223 }
224
225 jint nBytes = env->GetArrayLength(bytes);
226
227 if (format == CF_ENHMETAFILE) {
228 LPBYTE lpbEmfBuffer =
229 (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL);
230 if (lpbEmfBuffer == NULL) {
231 env->PopLocalFrame(NULL);
232 throw std::bad_alloc();
233 }
234
235 HENHMETAFILE hemf = ::SetEnhMetaFileBits(nBytes, lpbEmfBuffer);
236
237 env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbEmfBuffer,
238 JNI_ABORT);
239
240 if (hemf != NULL) {
241 VERIFY(::SetClipboardData((UINT)format, hemf));
242 }
243 return;
244 } else if (format == CF_METAFILEPICT) {
245 LPBYTE lpbMfpBuffer =
246 (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL);
247 if (lpbMfpBuffer == NULL) {
248 env->PopLocalFrame(NULL);
249 throw std::bad_alloc();
250 }
251
252 HMETAFILE hmf = ::SetMetaFileBitsEx(nBytes - sizeof(METAFILEPICT),
253 lpbMfpBuffer + sizeof(METAFILEPICT));
254 if (hmf == NULL) {
255 env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
256 env->PopLocalFrame(NULL);
257 return;
258 }
259
260 LPMETAFILEPICT lpMfpOld = (LPMETAFILEPICT)lpbMfpBuffer;
261
262 HMETAFILEPICT hmfp = ::GlobalAlloc(GALLOCFLG, sizeof(METAFILEPICT));
263 if (hmfp == NULL) {
264 VERIFY(::DeleteMetaFile(hmf));
265 env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
266 env->PopLocalFrame(NULL);
267 throw std::bad_alloc();
268 }
269
270 LPMETAFILEPICT lpMfp = (LPMETAFILEPICT)::GlobalLock(hmfp);
271 lpMfp->mm = lpMfpOld->mm;
272 lpMfp->xExt = lpMfpOld->xExt;
273 lpMfp->yExt = lpMfpOld->yExt;
274 lpMfp->hMF = hmf;
275 ::GlobalUnlock(hmfp);
276
277 env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
278
279 VERIFY(::SetClipboardData((UINT)format, hmfp));
280
281 return;
282 }
283
284 // We have to prepend the DROPFILES structure here because WDataTransferer
285 // doesn't.
286 HGLOBAL hglobal = ::GlobalAlloc(GALLOCFLG, nBytes + ((format == CF_HDROP)
287 ? sizeof(DROPFILES)
288 : 0));
289 if (hglobal == NULL) {
290 throw std::bad_alloc();
291 }
292 char *dataout = (char *)::GlobalLock(hglobal);
293
294 if (format == CF_HDROP) {
295 DROPFILES *dropfiles = (DROPFILES *)dataout;
296 dropfiles->pFiles = sizeof(DROPFILES);
297 dropfiles->fWide = TRUE; // we publish only Unicode
298 dataout += sizeof(DROPFILES);
299 }
300
301 env->GetByteArrayRegion(bytes, 0, nBytes, (jbyte *)dataout);
302 ::GlobalUnlock(hglobal);
303
304 VERIFY(::SetClipboardData((UINT)format, hglobal));
305
306 CATCH_BAD_ALLOC;
307 }
308
309 /*
310 * Class: sun_awt_windows_WClipboard
311 * Method: getClipboardFormats
312 * Signature: ()[J
313 */
314 JNIEXPORT jlongArray JNICALL
Java_sun_awt_windows_WClipboard_getClipboardFormats(JNIEnv * env,jobject self)315 Java_sun_awt_windows_WClipboard_getClipboardFormats
316 (JNIEnv *env, jobject self)
317 {
318 TRY;
319
320 DASSERT(::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd());
321
322 jsize nFormats = ::CountClipboardFormats();
323 jlongArray formats = env->NewLongArray(nFormats);
324 if (formats == NULL) {
325 throw std::bad_alloc();
326 }
327 if (nFormats == 0) {
328 return formats;
329 }
330 jboolean isCopy;
331 jlong *lFormats = env->GetLongArrayElements(formats, &isCopy),
332 *saveFormats = lFormats;
333 UINT num = 0;
334
335 for (jsize i = 0; i < nFormats; i++, lFormats++) {
336 *lFormats = num = ::EnumClipboardFormats(num);
337 }
338
339 env->ReleaseLongArrayElements(formats, saveFormats, 0);
340
341 return formats;
342
343 CATCH_BAD_ALLOC_RET(NULL);
344 }
345
346 /*
347 * Class: sun_awt_windows_WClipboard
348 * Method: getClipboardData
349 * Signature: (J)[B
350 */
351 JNIEXPORT jbyteArray JNICALL
Java_sun_awt_windows_WClipboard_getClipboardData(JNIEnv * env,jobject self,jlong format)352 Java_sun_awt_windows_WClipboard_getClipboardData
353 (JNIEnv *env, jobject self, jlong format)
354 {
355 TRY;
356
357 DASSERT(::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd());
358
359 HANDLE handle = ::GetClipboardData((UINT)format);
360 if (handle == NULL) {
361 JNU_ThrowIOException(env, "system clipboard data unavailable");
362 return NULL;
363 }
364
365 jbyteArray bytes = NULL;
366 jbyteArray paletteData = NULL;
367
368 switch (format) {
369 case CF_ENHMETAFILE:
370 case CF_METAFILEPICT: {
371 HENHMETAFILE hemf = NULL;
372
373 if (format == CF_METAFILEPICT) {
374 HMETAFILEPICT hMetaFilePict = (HMETAFILEPICT)handle;
375 LPMETAFILEPICT lpMetaFilePict =
376 (LPMETAFILEPICT)::GlobalLock(hMetaFilePict);
377 UINT uSize = ::GetMetaFileBitsEx(lpMetaFilePict->hMF, 0, NULL);
378 DASSERT(uSize != 0);
379
380 try {
381 LPBYTE lpMfBits = (LPBYTE)safe_Malloc(uSize);
382 VERIFY(::GetMetaFileBitsEx(lpMetaFilePict->hMF, uSize,
383 lpMfBits) == uSize);
384 hemf = ::SetWinMetaFileBits(uSize, lpMfBits, NULL,
385 lpMetaFilePict);
386 free(lpMfBits);
387 if (hemf == NULL) {
388 ::GlobalUnlock(hMetaFilePict);
389 JNU_ThrowIOException(env, "failed to get system clipboard data");
390 return NULL;
391 }
392 } catch (...) {
393 ::GlobalUnlock(hMetaFilePict);
394 throw;
395 }
396 ::GlobalUnlock(hMetaFilePict);
397 } else {
398 hemf = (HENHMETAFILE)handle;
399 }
400
401 UINT uEmfSize = ::GetEnhMetaFileBits(hemf, 0, NULL);
402 if (uEmfSize == 0) {
403 JNU_ThrowIOException(env, "cannot retrieve metafile bits");
404 return NULL;
405 }
406
407 bytes = env->NewByteArray(uEmfSize);
408 if (bytes == NULL) {
409 throw std::bad_alloc();
410 }
411
412 LPBYTE lpbEmfBuffer =
413 (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL);
414 if (lpbEmfBuffer == NULL) {
415 env->DeleteLocalRef(bytes);
416 throw std::bad_alloc();
417 }
418 VERIFY(::GetEnhMetaFileBits(hemf, uEmfSize, lpbEmfBuffer) == uEmfSize);
419 env->ReleasePrimitiveArrayCritical(bytes, lpbEmfBuffer, 0);
420
421 paletteData =
422 AwtDataTransferer::GetPaletteBytes(hemf, OBJ_ENHMETAFILE, FALSE);
423 break;
424 }
425 case CF_LOCALE: {
426 LCID *lcid = (LCID *)::GlobalLock(handle);
427 if (lcid == NULL) {
428 JNU_ThrowIOException(env, "invalid LCID");
429 return NULL;
430 }
431 try {
432 bytes = AwtDataTransferer::LCIDToTextEncoding(env, *lcid);
433 } catch (...) {
434 ::GlobalUnlock(handle);
435 throw;
436 }
437 ::GlobalUnlock(handle);
438 break;
439 }
440 default: {
441 ::SetLastError(0); // clear error
442 // Warning C4244.
443 // Cast SIZE_T (__int64 on 64-bit/unsigned int on 32-bit)
444 // to jsize (long).
445 SIZE_T globalSize = ::GlobalSize(handle);
446 jsize size = (globalSize <= INT_MAX) ? (jsize)globalSize : INT_MAX;
447 if (::GetLastError() != 0) {
448 JNU_ThrowIOException(env, "invalid global memory block handle");
449 return NULL;
450 }
451
452 bytes = env->NewByteArray(size);
453 if (bytes == NULL) {
454 throw std::bad_alloc();
455 }
456
457 if (size != 0) {
458 LPVOID data = ::GlobalLock(handle);
459 env->SetByteArrayRegion(bytes, 0, size, (jbyte *)data);
460 ::GlobalUnlock(handle);
461 }
462 break;
463 }
464 }
465
466 switch (format) {
467 case CF_ENHMETAFILE:
468 case CF_METAFILEPICT:
469 case CF_DIB: {
470 if (JNU_IsNull(env, paletteData)) {
471 HPALETTE hPalette = (HPALETTE)::GetClipboardData(CF_PALETTE);
472 paletteData =
473 AwtDataTransferer::GetPaletteBytes(hPalette, OBJ_PAL, TRUE);
474 }
475 DASSERT(!JNU_IsNull(env, paletteData) &&
476 !JNU_IsNull(env, bytes));
477
478 jbyteArray concat =
479 (jbyteArray)AwtDataTransferer::ConcatData(env, paletteData, bytes);
480
481 if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
482 env->ExceptionDescribe();
483 env->ExceptionClear();
484 env->DeleteLocalRef(bytes);
485 env->DeleteLocalRef(paletteData);
486 return NULL;
487 }
488
489 env->DeleteLocalRef(bytes);
490 env->DeleteLocalRef(paletteData);
491 bytes = concat;
492 break;
493 }
494 }
495
496 return bytes;
497
498 CATCH_BAD_ALLOC_RET(NULL);
499 }
500
501 } /* extern "C" */
502