1 /*
   2  * Copyright (c) 1997, 2008, 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 
  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 
  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 
  84 AwtCursor::~AwtCursor()
  85 {
  86 }
  87 
  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 
 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 
 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 
 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 
 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             }
 232 
 233             if (AwtCursor::updateCursorID == NULL) {
 234                 jclass cls =
 235                     env->FindClass("sun/awt/windows/WGlobalCursorManager");
 236                 AwtCursor::globalCursorManagerClass =
 237                     (jclass)env->NewGlobalRef(cls);
 238                 AwtCursor::updateCursorID =
 239                     env->GetStaticMethodID(cls, "nativeUpdateCursor",
 240                     "(Ljava/awt/Component;)V");
 241                 DASSERT(AwtCursor::globalCursorManagerClass != NULL);
 242                 DASSERT(AwtCursor::updateCursorID != NULL);
 243             }
 244 
 245             env->CallStaticVoidMethod(AwtCursor::globalCursorManagerClass,
 246                 AwtCursor::updateCursorID, jcomp);
 247         }
 248     }
 249     env->DeleteLocalRef(jcomp);
 250 }
 251 
 252 void AwtCursor::Rebuild() {
 253     if (!dirty) {
 254         return;
 255     }
 256 
 257     ::DestroyIcon(hCursor);
 258     hCursor = NULL;
 259 
 260     HBITMAP hMask = ::CreateBitmap(nWidth, nHeight, 1, 1, mask);
 261     HBITMAP hColor = create_BMP(NULL, cols, nSS, nWidth, nHeight);
 262     if (hMask && hColor) {
 263         ICONINFO icnInfo;
 264         memset(&icnInfo, 0, sizeof(ICONINFO));
 265         icnInfo.hbmMask = hMask;
 266         icnInfo.hbmColor = hColor;
 267         icnInfo.fIcon = FALSE;
 268         icnInfo.xHotspot = xHotSpot;
 269         icnInfo.yHotspot = yHotSpot;
 270 
 271         hCursor = ::CreateIconIndirect(&icnInfo);
 272 
 273         destroy_BMP(hColor);
 274         destroy_BMP(hMask);
 275     }
 276     DASSERT(hCursor);
 277     dirty = FALSE;
 278 }
 279 
 280 extern "C" {
 281 
 282 /************************************************************************
 283  * AwtCursor methods
 284  */
 285 
 286 /*
 287  * Class:     jave_awt_Cursor
 288  * Method:    initIDs
 289  * Signature: ()V
 290  */
 291 JNIEXPORT void JNICALL
 292 Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls)
 293 {
 294     TRY;
 295 
 296     AwtCursor::mSetPDataID = env->GetMethodID(cls, "setPData", "(J)V");
 297     AwtCursor::pDataID = env->GetFieldID(cls, "pData", "J");
 298     AwtCursor::typeID = env->GetFieldID(cls, "type", "I");
 299     DASSERT(AwtCursor::pDataID != NULL);
 300     DASSERT(AwtCursor::typeID != NULL);
 301 
 302     cls = env->FindClass("java/awt/Point");
 303     AwtCursor::pointXID = env->GetFieldID(cls, "x", "I");
 304     AwtCursor::pointYID = env->GetFieldID(cls, "y", "I");
 305     DASSERT(AwtCursor::pointXID != NULL);
 306     DASSERT(AwtCursor::pointYID != NULL);
 307 
 308     AwtCursor::updateCursorID = NULL;
 309 
 310     CATCH_BAD_ALLOC;
 311 }
 312 
 313 /*
 314  * Class:     java_awt_Cursor
 315  * Method:    finalizeImpl
 316  * Signature: ()V
 317  */
 318 JNIEXPORT void JNICALL
 319 Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jclass clazz, jlong pData)
 320 {
 321     TRY_NO_VERIFY;
 322 
 323     AwtObject::_Dispose((PDATA)pData);
 324 
 325     CATCH_BAD_ALLOC;
 326 }
 327 
 328 /************************************************************************
 329  * WCustomCursor native methods
 330  */
 331 
 332 JNIEXPORT void JNICALL
 333 Java_sun_awt_windows_WCustomCursor_createCursorIndirect(
 334     JNIEnv *env, jobject self, jintArray intRasterData, jbyteArray andMask,
 335     jint nSS, jint nW, jint nH, jint xHotSpot, jint yHotSpot)
 336 {
 337     TRY;
 338 
 339     JNI_CHECK_NULL_RETURN(intRasterData, "intRasterData argument");
 340 
 341     if (nW != ::GetSystemMetrics(SM_CXCURSOR) ||
 342         nH != ::GetSystemMetrics(SM_CYCURSOR)) {
 343         JNU_ThrowArrayIndexOutOfBoundsException(env,
 344                                                 "bad width and/or height");
 345         return;
 346     }
 347 
 348     jsize length = env->GetArrayLength(andMask);
 349     jbyte *andMaskPtr = new jbyte[length]; // safe because sizeof(jbyte)==1
 350     env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);
 351 
 352     HBITMAP hMask = ::CreateBitmap(nW, nH, 1, 1, (BYTE *)andMaskPtr);
 353     ::GdiFlush();
 354 
 355     int *cols = SAFE_SIZE_NEW_ARRAY2(int, nW, nH);
 356 
 357     jint *intRasterDataPtr = NULL;
 358     HBITMAP hColor = NULL;
 359     try {
 360         intRasterDataPtr =
 361             (jint *)env->GetPrimitiveArrayCritical(intRasterData, 0);
 362         hColor = create_BMP(NULL, (int *)intRasterDataPtr, nSS, nW, nH);
 363         memcpy(cols, intRasterDataPtr, nW*nH*sizeof(int));
 364     } catch (...) {
 365         if (intRasterDataPtr != NULL) {
 366             env->ReleasePrimitiveArrayCritical(intRasterData,
 367                                                intRasterDataPtr, 0);
 368         }
 369         throw;
 370     }
 371 
 372     env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
 373     intRasterDataPtr = NULL;
 374 
 375     HCURSOR hCursor = NULL;
 376 
 377     if (hMask && hColor) {
 378         ICONINFO icnInfo;
 379         memset(&icnInfo, 0, sizeof(ICONINFO));
 380         icnInfo.hbmMask = hMask;
 381         icnInfo.hbmColor = hColor;
 382         icnInfo.fIcon = FALSE;
 383         icnInfo.xHotspot = xHotSpot;
 384         icnInfo.yHotspot = yHotSpot;
 385 
 386         hCursor = ::CreateIconIndirect(&icnInfo);
 387 
 388         destroy_BMP(hColor);
 389         destroy_BMP(hMask);
 390     }
 391 
 392     DASSERT(hCursor);
 393 
 394     try {
 395         AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot,
 396                                                              yHotSpot, nW, nH, nSS, cols,
 397                                                              (BYTE *)andMaskPtr)));
 398     } catch (...) {
 399         if (cols) {
 400             delete[] cols;
 401         }
 402         throw;
 403     }
 404     CATCH_BAD_ALLOC;
 405 }
 406 
 407 /*
 408  * Class:     sun_awt_windows_WCustomCursor
 409  * Method:    getCursorWidth
 410  * Signature: ()I
 411  */
 412 JNIEXPORT jint JNICALL
 413 Java_sun_awt_windows_WCustomCursor_getCursorWidth(JNIEnv *, jclass)
 414 {
 415     TRY;
 416 
 417     DTRACE_PRINTLN("WCustomCursor.getCursorWidth()");
 418     return (jint)::GetSystemMetrics(SM_CXCURSOR);
 419 
 420     CATCH_BAD_ALLOC_RET(0);
 421 }
 422 
 423 /*
 424  * Class:     sun_awt_windows_WCustomCursor
 425  * Method:    getCursorHeight
 426  * Signature: ()I
 427  */
 428 JNIEXPORT jint JNICALL
 429 Java_sun_awt_windows_WCustomCursor_getCursorHeight(JNIEnv *, jclass)
 430 {
 431     TRY;
 432 
 433     DTRACE_PRINTLN("WCustomCursor.getCursorHeight()");
 434     return (jint)::GetSystemMetrics(SM_CYCURSOR);
 435 
 436     CATCH_BAD_ALLOC_RET(0);
 437 }
 438 
 439 /************************************************************************
 440  * WGlobalCursorManager native methods
 441  */
 442 
 443 /*
 444  * Class:     sun_awt_windows_WGlobalCursorManager
 445  * Method:    getCursorPos
 446  * Signature: (Ljava/awt/Point;)V
 447  */
 448 JNIEXPORT void JNICALL
 449 Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env,
 450                                                        jobject,
 451                                                        jobject point)
 452 {
 453     TRY;
 454 
 455     POINT p;
 456     ::GetCursorPos(&p);
 457     env->SetIntField(point, AwtCursor::pointXID, (jint)p.x);
 458     env->SetIntField(point, AwtCursor::pointYID, (jint)p.y);
 459 
 460     CATCH_BAD_ALLOC;
 461 }
 462 
 463 struct GlobalSetCursorStruct {
 464     jobject cursor;
 465     jboolean u;
 466 };
 467 
 468 static void GlobalSetCursor(void* pStruct) {
 469     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 470     jobject cursor  = ((GlobalSetCursorStruct*)pStruct)->cursor;
 471     jboolean u      = ((GlobalSetCursorStruct*)pStruct)->u;
 472     jlong pData = env->GetLongField(cursor, AwtCursor::pDataID);
 473     AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData);
 474 
 475     if (awtCursor == NULL) {
 476         awtCursor = AwtCursor::CreateSystemCursor(cursor);
 477     }
 478 
 479     HCURSOR hCursor = awtCursor->GetHCursor();
 480 
 481     BOOL blocked = false;
 482     if (jobject jcomp = AwtComponent::FindHeavyweightUnderCursor(u)) {
 483         if(jobject jpeer = AwtObject::GetPeerForTarget(env, jcomp))
 484         {
 485             if(AwtComponent *awtComponent = (AwtComponent*)JNI_GET_PDATA(jpeer)) {
 486                 blocked = ::IsWindow(AwtWindow::GetModalBlocker(
 487                                     AwtComponent::GetTopLevelParentForWindow(
 488                                     awtComponent->GetHWnd())));
 489                 if (!blocked) {
 490                     awtComponent->setCursorCache(hCursor);
 491                 }
 492             }
 493             env->DeleteLocalRef(jpeer);
 494         }
 495         env->DeleteGlobalRef(jcomp);
 496     }
 497 
 498     if (!blocked) {
 499         ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR
 500     }
 501 
 502     env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor);
 503 }
 504 
 505 /*
 506  * Class:     sun_awt_windows_WGlobalCursorManager
 507  * Method:    setCursor
 508  * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V
 509  */
 510 JNIEXPORT void JNICALL
 511 Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv *env, jobject,
 512                             jobject, jobject cursor, jboolean u)
 513 {
 514     TRY;
 515 
 516     if (cursor != NULL) {  // fix for 4430302 - getCursor() returns NULL
 517         GlobalSetCursorStruct data;
 518         data.cursor = env->NewGlobalRef(cursor);
 519         data.u = u;
 520         AwtToolkit::GetInstance().InvokeFunction(
 521                GlobalSetCursor,
 522                (void *)&data);
 523     } else {
 524         JNU_ThrowNullPointerException(env, "NullPointerException");
 525     }
 526     CATCH_BAD_ALLOC;
 527 }
 528 
 529 /*
 530  * Class:     sun_awt_windows_WGlobalCursorManager
 531  * Method:    findHeavyweight
 532  * Signature: (II)Z
 533  */
 534 JNIEXPORT jobject JNICALL
 535 Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor(
 536     JNIEnv *env, jobject, jboolean useCache)
 537 {
 538     TRY;
 539 
 540     if (env->EnsureLocalCapacity(1) < 0) {
 541         return NULL;
 542     }
 543 
 544     jobject globalRef = (jobject)AwtToolkit::GetInstance().
 545         InvokeFunction((void*(*)(void*))
 546                        AwtComponent::FindHeavyweightUnderCursor,
 547                        (void *)useCache);
 548     jobject localRef = env->NewLocalRef(globalRef);
 549     env->DeleteGlobalRef(globalRef);
 550     return localRef;
 551 
 552     CATCH_BAD_ALLOC_RET(NULL);
 553 }
 554 
 555 /*
 556  * Class:     sun_awt_windows_WGlobalCursorManager
 557  * Method:    getLocationOnScreen
 558  * Signature: (L/java/awt/Component;)L/java/awt/Point
 559  */
 560 JNIEXPORT jobject JNICALL
 561 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen(
 562     JNIEnv *env, jobject, jobject component)
 563 {
 564     TRY;
 565 
 566     JNI_CHECK_NULL_RETURN_NULL(component, "null component");
 567     jobject point =
 568         env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID);
 569     return point;
 570 
 571     CATCH_BAD_ALLOC_RET(NULL);
 572 }
 573 
 574 } /* extern "C" */