1 /*
   2  * Copyright (c) 1997, 2015, 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 = IDC_HAND;
 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     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 
 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
 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
 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
 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
 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
 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
 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     HMONITOR monitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
 477     int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
 478     Devices::InstanceAccess devices;
 479     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
 480     int x = (device == NULL) ? p.x : device->ScaleDownX(p.x);
 481     int y = (device == NULL) ? p.y : device->ScaleDownY(p.y);
 482     env->SetIntField(point, AwtCursor::pointXID, x);
 483     env->SetIntField(point, AwtCursor::pointYID, y);
 484 
 485     CATCH_BAD_ALLOC;
 486 }
 487 
 488 struct GlobalSetCursorStruct {
 489     jobject cursor;
 490     jboolean u;
 491 };
 492 
 493 static void GlobalSetCursor(void* pStruct) {
 494     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 495     jobject cursor  = ((GlobalSetCursorStruct*)pStruct)->cursor;
 496     jboolean u      = ((GlobalSetCursorStruct*)pStruct)->u;
 497     jlong pData = env->GetLongField(cursor, AwtCursor::pDataID);
 498     AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData);
 499 
 500     if (awtCursor == NULL) {
 501         awtCursor = AwtCursor::CreateSystemCursor(cursor);
 502     }
 503 
 504     HCURSOR hCursor = awtCursor->GetHCursor();
 505 
 506     BOOL blocked = false;
 507     if (jobject jcomp = AwtComponent::FindHeavyweightUnderCursor(u)) {
 508         if(jobject jpeer = AwtObject::GetPeerForTarget(env, jcomp))
 509         {
 510             if(AwtComponent *awtComponent = (AwtComponent*)JNI_GET_PDATA(jpeer)) {
 511                 blocked = ::IsWindow(AwtWindow::GetModalBlocker(
 512                                     AwtComponent::GetTopLevelParentForWindow(
 513                                     awtComponent->GetHWnd())));
 514                 if (!blocked) {
 515                     awtComponent->setCursorCache(hCursor);
 516                 }
 517             }
 518             env->DeleteLocalRef(jpeer);
 519         }
 520         env->DeleteGlobalRef(jcomp);
 521     }
 522 
 523     if (!blocked) {
 524         ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR
 525     }
 526 
 527     env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor);
 528 }
 529 
 530 /*
 531  * Class:     sun_awt_windows_WGlobalCursorManager
 532  * Method:    setCursor
 533  * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V
 534  */
 535 JNIEXPORT void JNICALL
 536 Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv *env, jobject,
 537                             jobject, jobject cursor, jboolean u)
 538 {
 539     TRY;
 540 
 541     if (cursor != NULL) {  // fix for 4430302 - getCursor() returns NULL
 542         GlobalSetCursorStruct data;
 543         data.cursor = env->NewGlobalRef(cursor);
 544         data.u = u;
 545         AwtToolkit::GetInstance().InvokeFunction(
 546                GlobalSetCursor,
 547                (void *)&data);
 548     } else {
 549         JNU_ThrowNullPointerException(env, "NullPointerException");
 550     }
 551     CATCH_BAD_ALLOC;
 552 }
 553 
 554 /*
 555  * Class:     sun_awt_windows_WGlobalCursorManager
 556  * Method:    findHeavyweight
 557  * Signature: (II)Z
 558  */
 559 JNIEXPORT jobject JNICALL
 560 Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor(
 561     JNIEnv *env, jobject, jboolean useCache)
 562 {
 563     TRY;
 564 
 565     if (env->EnsureLocalCapacity(1) < 0) {
 566         return NULL;
 567     }
 568 
 569     jobject globalRef = (jobject)AwtToolkit::GetInstance().
 570         InvokeFunction((void*(*)(void*))
 571                        AwtComponent::FindHeavyweightUnderCursor,
 572                        (void *)useCache);
 573     jobject localRef = env->NewLocalRef(globalRef);
 574     env->DeleteGlobalRef(globalRef);
 575     return localRef;
 576 
 577     CATCH_BAD_ALLOC_RET(NULL);
 578 }
 579 
 580 /*
 581  * Class:     sun_awt_windows_WGlobalCursorManager
 582  * Method:    getLocationOnScreen
 583  * Signature: (L/java/awt/Component;)L/java/awt/Point
 584  */
 585 JNIEXPORT jobject JNICALL
 586 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen(
 587     JNIEnv *env, jobject, jobject component)
 588 {
 589     TRY;
 590 
 591     JNI_CHECK_NULL_RETURN_NULL(component, "null component");
 592     jobject point =
 593         env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID);
 594     return point;
 595 
 596     CATCH_BAD_ALLOC_RET(NULL);
 597 }
 598 
 599 } /* extern "C" */