1 /*
2  * Copyright (c) 1997, 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 #include "jlong.h"
27 #include "awt_Cursor.h"
28 #include "awt_Component.h"
29 #include "awt_Container.h"
30 #include "awt_IconCursor.h"
31 #include "awt_Toolkit.h"
32 #include "awt_Window.h"
33 #include <java_awt_Cursor.h>
34 #include <sun_awt_windows_WCustomCursor.h>
35 #include <sun_awt_windows_WGlobalCursorManager.h>
36 
37 
38 /************************************************************************
39  * AwtCursor fields
40  */
41 jmethodID AwtCursor::mSetPDataID;
42 jfieldID AwtCursor::pDataID;
43 jfieldID AwtCursor::typeID;
44 
45 jfieldID AwtCursor::pointXID;
46 jfieldID AwtCursor::pointYID;
47 
48 jclass AwtCursor::globalCursorManagerClass;
49 jmethodID AwtCursor::updateCursorID;
50 
51 AwtObjectList AwtCursor::customCursors;
52 
53 
AwtCursor(JNIEnv * env,HCURSOR hCur,jobject jCur)54 AwtCursor::AwtCursor(JNIEnv *env, HCURSOR hCur, jobject jCur)
55 {
56     hCursor = hCur;
57     jCursor = env->NewWeakGlobalRef(jCur);
58 
59     xHotSpot = yHotSpot = nWidth = nHeight = nSS = 0;
60     cols = NULL;
61     mask = NULL;
62 
63     custom = dirty = FALSE;
64 }
65 
AwtCursor(JNIEnv * env,HCURSOR hCur,jobject jCur,int xH,int yH,int nWid,int nHgt,int nS,int * col,BYTE * hM)66 AwtCursor::AwtCursor(JNIEnv *env, HCURSOR hCur, jobject jCur, int xH, int yH,
67                      int nWid, int nHgt, int nS, int *col, BYTE *hM)
68 {
69     hCursor = hCur;
70     jCursor = env->NewWeakGlobalRef(jCur);
71 
72     xHotSpot = xH;
73     yHotSpot = yH;
74     nWidth = nWid;
75     nHeight = nHgt;
76     nSS = nS;
77     cols = col;
78     mask = hM;
79 
80     custom = TRUE;
81     dirty = FALSE;
82 }
83 
~AwtCursor()84 AwtCursor::~AwtCursor()
85 {
86 }
87 
Dispose()88 void AwtCursor::Dispose()
89 {
90     delete[] mask;
91     delete[] cols;
92 
93     if (custom) {
94         ::DestroyIcon(hCursor);
95     }
96 
97     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
98     jobject localObj = env->NewLocalRef(jCursor);
99     if (localObj != NULL) {
100         setPData(localObj, ptr_to_jlong(NULL));
101         env->DeleteLocalRef(localObj);
102     }
103     env->DeleteWeakGlobalRef(jCursor);
104 
105     AwtObject::Dispose();
106 }
107 
CreateSystemCursor(jobject jCursor)108 AwtCursor * AwtCursor::CreateSystemCursor(jobject jCursor)
109 {
110     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
111 
112     jint type = env->GetIntField(jCursor, AwtCursor::typeID);
113     DASSERT(type != java_awt_Cursor_CUSTOM_CURSOR);
114 
115     LPCTSTR winCursor;
116     switch (type) {
117       case java_awt_Cursor_DEFAULT_CURSOR:
118       default:
119         winCursor = IDC_ARROW;
120         break;
121       case java_awt_Cursor_CROSSHAIR_CURSOR:
122         winCursor = IDC_CROSS;
123         break;
124       case java_awt_Cursor_TEXT_CURSOR:
125         winCursor = IDC_IBEAM;
126         break;
127       case java_awt_Cursor_WAIT_CURSOR:
128         winCursor = IDC_WAIT;
129         break;
130       case java_awt_Cursor_NE_RESIZE_CURSOR:
131       case java_awt_Cursor_SW_RESIZE_CURSOR:
132         winCursor = IDC_SIZENESW;
133         break;
134       case java_awt_Cursor_SE_RESIZE_CURSOR:
135       case java_awt_Cursor_NW_RESIZE_CURSOR:
136         winCursor = IDC_SIZENWSE;
137         break;
138       case java_awt_Cursor_N_RESIZE_CURSOR:
139       case java_awt_Cursor_S_RESIZE_CURSOR:
140         winCursor = IDC_SIZENS;
141         break;
142       case java_awt_Cursor_W_RESIZE_CURSOR:
143       case java_awt_Cursor_E_RESIZE_CURSOR:
144         winCursor = IDC_SIZEWE;
145         break;
146       case java_awt_Cursor_HAND_CURSOR:
147         winCursor = TEXT("HAND_CURSOR");
148         break;
149       case java_awt_Cursor_MOVE_CURSOR:
150         winCursor = IDC_SIZEALL;
151         break;
152     }
153     HCURSOR hCursor = ::LoadCursor(NULL, winCursor);
154     if (hCursor == NULL) {
155         /* Not a system cursor, check for resource. */
156         hCursor = ::LoadCursor(AwtToolkit::GetInstance().GetModuleHandle(),
157                                winCursor);
158     }
159     if (hCursor == NULL) {
160         hCursor = ::LoadCursor(NULL, IDC_ARROW);
161         DASSERT(hCursor != NULL);
162     }
163 
164     AwtCursor *awtCursor = new AwtCursor(env, hCursor, jCursor);
165     setPData(jCursor, ptr_to_jlong(awtCursor));
166 
167     return awtCursor;
168 }
169 
GetCursor(JNIEnv * env,AwtComponent * comp)170 HCURSOR  AwtCursor::GetCursor(JNIEnv *env, AwtComponent *comp) {
171     jlong  pData ;
172 
173     if (comp == NULL) {
174         return NULL;
175     }
176     if (env->EnsureLocalCapacity(2) < 0) {
177         return NULL;
178     }
179     jobject jcomp = comp->GetTarget(env);
180     if (jcomp == NULL)
181         return NULL;
182     jobject jcurs = env->GetObjectField (jcomp, AwtComponent::cursorID);
183 
184     if (jcurs != NULL) {
185         pData = env->GetLongField(jcurs, AwtCursor::pDataID);
186         AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData);
187 
188         env->DeleteLocalRef(jcomp);
189         env->DeleteLocalRef(jcurs);
190 
191         if (awtCursor == NULL) {
192             return NULL;
193         }
194         return awtCursor->GetHCursor();
195 
196     } else {
197         env->DeleteLocalRef(jcomp);
198     }
199 
200     //if component's cursor is null, get the parent's cursor
201     AwtComponent *parent = comp->GetParent() ;
202 
203     return AwtCursor::GetCursor(env, parent);
204 }
205 
UpdateCursor(AwtComponent * comp)206 void AwtCursor::UpdateCursor(AwtComponent *comp) {
207     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
208     if (env->EnsureLocalCapacity(1) < 0) {
209         return;
210     }
211     jobject jcomp = comp->GetTarget(env);
212     try {
213         //4372119:Disappearing of busy cursor on JDK 1.3
214         HWND captureWnd = GetCapture();
215         if ( !AwtComponent::isMenuLoopActive() &&
216             (captureWnd==NULL || captureWnd==comp->GetHWnd()))
217         {
218             if (IsWindow(AwtWindow::GetModalBlocker(
219                                     AwtComponent::GetTopLevelParentForWindow(
220                                     comp->GetHWnd()))))
221             {
222                 static HCURSOR hArrowCursor = LoadCursor(NULL, IDC_ARROW);
223                 SetCursor(hArrowCursor);
224             } else {
225                 HCURSOR cur = comp->getCursorCache();
226                 if (cur == NULL) {
227                     cur = GetCursor(env , comp);
228                 }
229                 if (cur != NULL) {
230                     ::SetCursor(cur);
231                 } else {
232                     if (safe_ExceptionOccurred(env)) {
233                         env->ExceptionClear();
234                     }
235                 }
236                 if (AwtCursor::updateCursorID == NULL) {
237                     jclass cls =
238                     env->FindClass("sun/awt/windows/WGlobalCursorManager");
239                     if(cls != NULL){
240                         AwtCursor::globalCursorManagerClass =
241                             (jclass)env->NewGlobalRef(cls);
242                         AwtCursor::updateCursorID =
243                             env->GetStaticMethodID(cls, "nativeUpdateCursor",
244                             "(Ljava/awt/Component;)V");
245                         env->DeleteLocalRef(cls);
246                         DASSERT(AwtCursor::globalCursorManagerClass != NULL);
247                         DASSERT(AwtCursor::updateCursorID != NULL);
248                     }
249                 }
250                 if (AwtCursor::updateCursorID != NULL
251                     && AwtCursor::globalCursorManagerClass != NULL) {
252                     env->CallStaticVoidMethod(AwtCursor::globalCursorManagerClass,
253                         AwtCursor::updateCursorID, jcomp);
254                 }
255             }
256         }
257     } catch (...) {
258         env->DeleteLocalRef(jcomp);
259         throw;
260     }
261     env->DeleteLocalRef(jcomp);
262 }
263 
Rebuild()264 void AwtCursor::Rebuild() {
265     if (!dirty) {
266         return;
267     }
268 
269     ::DestroyIcon(hCursor);
270     hCursor = NULL;
271 
272     HBITMAP hMask = ::CreateBitmap(nWidth, nHeight, 1, 1, mask);
273     HBITMAP hColor = create_BMP(NULL, cols, nSS, nWidth, nHeight);
274     if (hMask && hColor) {
275         ICONINFO icnInfo;
276         memset(&icnInfo, 0, sizeof(ICONINFO));
277         icnInfo.hbmMask = hMask;
278         icnInfo.hbmColor = hColor;
279         icnInfo.fIcon = FALSE;
280         icnInfo.xHotspot = xHotSpot;
281         icnInfo.yHotspot = yHotSpot;
282 
283         hCursor = ::CreateIconIndirect(&icnInfo);
284 
285         destroy_BMP(hColor);
286         destroy_BMP(hMask);
287     }
288     DASSERT(hCursor);
289     dirty = FALSE;
290 }
291 
292 extern "C" {
293 
294 /************************************************************************
295  * AwtCursor methods
296  */
297 
298 /*
299  * Class:     jave_awt_Cursor
300  * Method:    initIDs
301  * Signature: ()V
302  */
303 JNIEXPORT void JNICALL
Java_java_awt_Cursor_initIDs(JNIEnv * env,jclass cls)304 Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls)
305 {
306     TRY;
307 
308     AwtCursor::mSetPDataID = env->GetMethodID(cls, "setPData", "(J)V");
309     DASSERT(AwtCursor::mSetPDataID != NULL);
310     CHECK_NULL(AwtCursor::mSetPDataID);
311     AwtCursor::pDataID = env->GetFieldID(cls, "pData", "J");
312     DASSERT(AwtCursor::pDataID != NULL);
313     CHECK_NULL(AwtCursor::pDataID);
314     AwtCursor::typeID = env->GetFieldID(cls, "type", "I");
315     DASSERT(AwtCursor::typeID != NULL);
316     CHECK_NULL(AwtCursor::typeID);
317 
318     cls = env->FindClass("java/awt/Point");
319     CHECK_NULL(cls);
320 
321     AwtCursor::pointXID = env->GetFieldID(cls, "x", "I");
322     DASSERT(AwtCursor::pointXID != NULL);
323     CHECK_NULL(AwtCursor::pointXID);
324     AwtCursor::pointYID = env->GetFieldID(cls, "y", "I");
325     DASSERT(AwtCursor::pointYID != NULL);
326 
327     AwtCursor::updateCursorID = NULL;
328 
329     CATCH_BAD_ALLOC;
330 }
331 
332 /*
333  * Class:     java_awt_Cursor
334  * Method:    finalizeImpl
335  * Signature: ()V
336  */
337 JNIEXPORT void JNICALL
Java_java_awt_Cursor_finalizeImpl(JNIEnv * env,jclass clazz,jlong pData)338 Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jclass clazz, jlong pData)
339 {
340     TRY_NO_VERIFY;
341 
342     AwtObject::_Dispose((PDATA)pData);
343 
344     CATCH_BAD_ALLOC;
345 }
346 
347 /************************************************************************
348  * WCustomCursor native methods
349  */
350 
351 JNIEXPORT void JNICALL
Java_sun_awt_windows_WCustomCursor_createCursorIndirect(JNIEnv * env,jobject self,jintArray intRasterData,jbyteArray andMask,jint nSS,jint nW,jint nH,jint xHotSpot,jint yHotSpot)352 Java_sun_awt_windows_WCustomCursor_createCursorIndirect(
353     JNIEnv *env, jobject self, jintArray intRasterData, jbyteArray andMask,
354     jint nSS, jint nW, jint nH, jint xHotSpot, jint yHotSpot)
355 {
356     TRY;
357 
358     JNI_CHECK_NULL_RETURN(intRasterData, "intRasterData argument");
359 
360     if (nW != ::GetSystemMetrics(SM_CXCURSOR) ||
361         nH != ::GetSystemMetrics(SM_CYCURSOR)) {
362         JNU_ThrowArrayIndexOutOfBoundsException(env,
363                                                 "bad width and/or height");
364         return;
365     }
366 
367     jsize length = env->GetArrayLength(andMask);
368     jbyte *andMaskPtr = new jbyte[length]; // safe because sizeof(jbyte)==1
369     env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);
370 
371     HBITMAP hMask = ::CreateBitmap(nW, nH, 1, 1, (BYTE *)andMaskPtr);
372     ::GdiFlush();
373 
374     int *cols = SAFE_SIZE_NEW_ARRAY2(int, nW, nH);
375 
376     jint *intRasterDataPtr = NULL;
377     HBITMAP hColor = NULL;
378     try {
379         intRasterDataPtr =
380             (jint *)env->GetPrimitiveArrayCritical(intRasterData, 0);
381         hColor = create_BMP(NULL, (int *)intRasterDataPtr, nSS, nW, nH);
382         memcpy(cols, intRasterDataPtr, nW*nH*sizeof(int));
383     } catch (...) {
384         if (intRasterDataPtr != NULL) {
385             env->ReleasePrimitiveArrayCritical(intRasterData,
386                                                intRasterDataPtr, 0);
387         }
388         throw;
389     }
390 
391     env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
392     intRasterDataPtr = NULL;
393 
394     HCURSOR hCursor = NULL;
395 
396     if (hMask && hColor) {
397         ICONINFO icnInfo;
398         memset(&icnInfo, 0, sizeof(ICONINFO));
399         icnInfo.hbmMask = hMask;
400         icnInfo.hbmColor = hColor;
401         icnInfo.fIcon = FALSE;
402         icnInfo.xHotspot = xHotSpot;
403         icnInfo.yHotspot = yHotSpot;
404 
405         hCursor = ::CreateIconIndirect(&icnInfo);
406 
407         destroy_BMP(hColor);
408         destroy_BMP(hMask);
409     }
410 
411     DASSERT(hCursor);
412 
413     try {
414         AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot,
415                                                              yHotSpot, nW, nH, nSS, cols,
416                                                              (BYTE *)andMaskPtr)));
417     } catch (...) {
418         if (cols) {
419             delete[] cols;
420         }
421         throw;
422     }
423     CATCH_BAD_ALLOC;
424 }
425 
426 /*
427  * Class:     sun_awt_windows_WCustomCursor
428  * Method:    getCursorWidth
429  * Signature: ()I
430  */
431 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WCustomCursor_getCursorWidth(JNIEnv *,jclass)432 Java_sun_awt_windows_WCustomCursor_getCursorWidth(JNIEnv *, jclass)
433 {
434     TRY;
435 
436     DTRACE_PRINTLN("WCustomCursor.getCursorWidth()");
437     return (jint)::GetSystemMetrics(SM_CXCURSOR);
438 
439     CATCH_BAD_ALLOC_RET(0);
440 }
441 
442 /*
443  * Class:     sun_awt_windows_WCustomCursor
444  * Method:    getCursorHeight
445  * Signature: ()I
446  */
447 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WCustomCursor_getCursorHeight(JNIEnv *,jclass)448 Java_sun_awt_windows_WCustomCursor_getCursorHeight(JNIEnv *, jclass)
449 {
450     TRY;
451 
452     DTRACE_PRINTLN("WCustomCursor.getCursorHeight()");
453     return (jint)::GetSystemMetrics(SM_CYCURSOR);
454 
455     CATCH_BAD_ALLOC_RET(0);
456 }
457 
458 /************************************************************************
459  * WGlobalCursorManager native methods
460  */
461 
462 /*
463  * Class:     sun_awt_windows_WGlobalCursorManager
464  * Method:    getCursorPos
465  * Signature: (Ljava/awt/Point;)V
466  */
467 JNIEXPORT void JNICALL
Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv * env,jobject,jobject point)468 Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env,
469                                                        jobject,
470                                                        jobject point)
471 {
472     TRY;
473 
474     POINT p;
475     ::GetCursorPos(&p);
476     env->SetIntField(point, AwtCursor::pointXID, (jint)p.x);
477     env->SetIntField(point, AwtCursor::pointYID, (jint)p.y);
478 
479     CATCH_BAD_ALLOC;
480 }
481 
482 struct GlobalSetCursorStruct {
483     jobject cursor;
484     jboolean u;
485 };
486 
GlobalSetCursor(void * pStruct)487 static void GlobalSetCursor(void* pStruct) {
488     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
489     jobject cursor  = ((GlobalSetCursorStruct*)pStruct)->cursor;
490     jboolean u      = ((GlobalSetCursorStruct*)pStruct)->u;
491     jlong pData = env->GetLongField(cursor, AwtCursor::pDataID);
492     AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData);
493 
494     if (awtCursor == NULL) {
495         awtCursor = AwtCursor::CreateSystemCursor(cursor);
496     }
497 
498     HCURSOR hCursor = awtCursor->GetHCursor();
499 
500     BOOL blocked = false;
501     if (jobject jcomp = AwtComponent::FindHeavyweightUnderCursor(u)) {
502         if(jobject jpeer = AwtObject::GetPeerForTarget(env, jcomp))
503         {
504             if(AwtComponent *awtComponent = (AwtComponent*)JNI_GET_PDATA(jpeer)) {
505                 blocked = ::IsWindow(AwtWindow::GetModalBlocker(
506                                     AwtComponent::GetTopLevelParentForWindow(
507                                     awtComponent->GetHWnd())));
508                 if (!blocked) {
509                     awtComponent->setCursorCache(hCursor);
510                 }
511             }
512             env->DeleteLocalRef(jpeer);
513         }
514         env->DeleteGlobalRef(jcomp);
515     }
516 
517     if (!blocked) {
518         ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR
519     }
520 
521     env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor);
522 }
523 
524 /*
525  * Class:     sun_awt_windows_WGlobalCursorManager
526  * Method:    setCursor
527  * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V
528  */
529 JNIEXPORT void JNICALL
Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv * env,jobject,jobject,jobject cursor,jboolean u)530 Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv *env, jobject,
531                             jobject, jobject cursor, jboolean u)
532 {
533     TRY;
534 
535     if (cursor != NULL) {  // fix for 4430302 - getCursor() returns NULL
536         GlobalSetCursorStruct data;
537         data.cursor = env->NewGlobalRef(cursor);
538         data.u = u;
539         AwtToolkit::GetInstance().InvokeFunction(
540                GlobalSetCursor,
541                (void *)&data);
542     } else {
543         JNU_ThrowNullPointerException(env, "NullPointerException");
544     }
545     CATCH_BAD_ALLOC;
546 }
547 
548 /*
549  * Class:     sun_awt_windows_WGlobalCursorManager
550  * Method:    findHeavyweight
551  * Signature: (II)Z
552  */
553 JNIEXPORT jobject JNICALL
Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor(JNIEnv * env,jobject,jboolean useCache)554 Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor(
555     JNIEnv *env, jobject, jboolean useCache)
556 {
557     TRY;
558 
559     if (env->EnsureLocalCapacity(1) < 0) {
560         return NULL;
561     }
562 
563     jobject globalRef = (jobject)AwtToolkit::GetInstance().
564         InvokeFunction((void*(*)(void*))
565                        AwtComponent::FindHeavyweightUnderCursor,
566                        (void *)useCache);
567     jobject localRef = env->NewLocalRef(globalRef);
568     env->DeleteGlobalRef(globalRef);
569     return localRef;
570 
571     CATCH_BAD_ALLOC_RET(NULL);
572 }
573 
574 /*
575  * Class:     sun_awt_windows_WGlobalCursorManager
576  * Method:    getLocationOnScreen
577  * Signature: (L/java/awt/Component;)L/java/awt/Point
578  */
579 JNIEXPORT jobject JNICALL
Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen(JNIEnv * env,jobject,jobject component)580 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen(
581     JNIEnv *env, jobject, jobject component)
582 {
583     TRY;
584 
585     JNI_CHECK_NULL_RETURN_NULL(component, "null component");
586     jobject point =
587         env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID);
588     return point;
589 
590     CATCH_BAD_ALLOC_RET(NULL);
591 }
592 
593 } /* extern "C" */
594