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     /* Copy the raster data because GDI may fail on some Java heap
 377      * allocated memory.
 378      */
 379     length = env->GetArrayLength(intRasterData);
 380     jint *intRasterDataPtr = new jint[length];
 381     HBITMAP hColor = NULL;
 382     try {
 383         env->GetIntArrayRegion(intRasterData, 0, length, intRasterDataPtr);
 384         hColor = create_BMP(NULL, (int *)intRasterDataPtr, nSS, nW, nH);
 385         memcpy(cols, intRasterDataPtr, nW*nH*sizeof(int));
 386     } catch (...) {
 387         delete[] intRasterDataPtr;
 388         throw;
 389     }
 390     delete[] intRasterDataPtr;
 391 
 392     HCURSOR hCursor = NULL;
 393 
 394     if (hMask && hColor) {
 395         ICONINFO icnInfo;
 396         memset(&icnInfo, 0, sizeof(ICONINFO));
 397         icnInfo.hbmMask = hMask;
 398         icnInfo.hbmColor = hColor;
 399         icnInfo.fIcon = FALSE;
 400         icnInfo.xHotspot = xHotSpot;
 401         icnInfo.yHotspot = yHotSpot;
 402 
 403         hCursor = ::CreateIconIndirect(&icnInfo);
 404 
 405         destroy_BMP(hColor);
 406         destroy_BMP(hMask);
 407     }
 408 
 409     DASSERT(hCursor);
 410 
 411     try {
 412         AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot,
 413                                                              yHotSpot, nW, nH, nSS, cols,
 414                                                              (BYTE *)andMaskPtr)));
 415     } catch (...) {
 416         if (cols) {
 417             delete[] cols;
 418         }
 419         throw;
 420     }
 421     CATCH_BAD_ALLOC;
 422 }
 423 
 424 /*
 425  * Class:     sun_awt_windows_WCustomCursor
 426  * Method:    getCursorWidth
 427  * Signature: ()I
 428  */
 429 JNIEXPORT jint JNICALL
 430 Java_sun_awt_windows_WCustomCursor_getCursorWidth(JNIEnv *, jclass)
 431 {
 432     TRY;
 433 
 434     DTRACE_PRINTLN("WCustomCursor.getCursorWidth()");
 435     return (jint)::GetSystemMetrics(SM_CXCURSOR);
 436 
 437     CATCH_BAD_ALLOC_RET(0);
 438 }
 439 
 440 /*
 441  * Class:     sun_awt_windows_WCustomCursor
 442  * Method:    getCursorHeight
 443  * Signature: ()I
 444  */
 445 JNIEXPORT jint JNICALL
 446 Java_sun_awt_windows_WCustomCursor_getCursorHeight(JNIEnv *, jclass)
 447 {
 448     TRY;
 449 
 450     DTRACE_PRINTLN("WCustomCursor.getCursorHeight()");
 451     return (jint)::GetSystemMetrics(SM_CYCURSOR);
 452 
 453     CATCH_BAD_ALLOC_RET(0);
 454 }
 455 
 456 /************************************************************************
 457  * WGlobalCursorManager native methods
 458  */
 459 
 460 /*
 461  * Class:     sun_awt_windows_WGlobalCursorManager
 462  * Method:    getCursorPos
 463  * Signature: (Ljava/awt/Point;)V
 464  */
 465 JNIEXPORT void JNICALL
 466 Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env,
 467                                                        jobject,
 468                                                        jobject point)
 469 {
 470     TRY;
 471 
 472     POINT p;
 473     ::GetCursorPos(&p);
 474     HMONITOR monitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
 475     int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
 476     Devices::InstanceAccess devices;
 477     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
 478     int x = (device == NULL) ? p.x : device->ScaleDownX(p.x);
 479     int y = (device == NULL) ? p.y : device->ScaleDownY(p.y);
 480     env->SetIntField(point, AwtCursor::pointXID, x);
 481     env->SetIntField(point, AwtCursor::pointYID, y);
 482 
 483     CATCH_BAD_ALLOC;
 484 }
 485 
 486 struct GlobalSetCursorStruct {
 487     jobject cursor;
 488     jboolean u;
 489 };
 490 
 491 static void GlobalSetCursor(void* pStruct) {
 492     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 493     jobject cursor  = ((GlobalSetCursorStruct*)pStruct)->cursor;
 494     jboolean u      = ((GlobalSetCursorStruct*)pStruct)->u;
 495     jlong pData = env->GetLongField(cursor, AwtCursor::pDataID);
 496     AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData);
 497 
 498     if (awtCursor == NULL) {
 499         awtCursor = AwtCursor::CreateSystemCursor(cursor);
 500     }
 501 
 502     HCURSOR hCursor = awtCursor->GetHCursor();
 503 
 504     BOOL blocked = false;
 505     if (jobject jcomp = AwtComponent::FindHeavyweightUnderCursor(u)) {
 506         if(jobject jpeer = AwtObject::GetPeerForTarget(env, jcomp))
 507         {
 508             if(AwtComponent *awtComponent = (AwtComponent*)JNI_GET_PDATA(jpeer)) {
 509                 blocked = ::IsWindow(AwtWindow::GetModalBlocker(
 510                                     AwtComponent::GetTopLevelParentForWindow(
 511                                     awtComponent->GetHWnd())));
 512                 if (!blocked) {
 513                     awtComponent->setCursorCache(hCursor);
 514                 }
 515             }
 516             env->DeleteLocalRef(jpeer);
 517         }
 518         env->DeleteGlobalRef(jcomp);
 519     }
 520 
 521     if (!blocked) {
 522         ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR
 523     }
 524 
 525     env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor);
 526 }
 527 
 528 /*
 529  * Class:     sun_awt_windows_WGlobalCursorManager
 530  * Method:    setCursor
 531  * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V
 532  */
 533 JNIEXPORT void JNICALL
 534 Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv *env, jobject,
 535                             jobject, jobject cursor, jboolean u)
 536 {
 537     TRY;
 538 
 539     if (cursor != NULL) {  // fix for 4430302 - getCursor() returns NULL
 540         GlobalSetCursorStruct data;
 541         data.cursor = env->NewGlobalRef(cursor);
 542         data.u = u;
 543         AwtToolkit::GetInstance().InvokeFunction(
 544                GlobalSetCursor,
 545                (void *)&data);
 546     } else {
 547         JNU_ThrowNullPointerException(env, "NullPointerException");
 548     }
 549     CATCH_BAD_ALLOC;
 550 }
 551 
 552 /*
 553  * Class:     sun_awt_windows_WGlobalCursorManager
 554  * Method:    findHeavyweight
 555  * Signature: (II)Z
 556  */
 557 JNIEXPORT jobject JNICALL
 558 Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor(
 559     JNIEnv *env, jobject, jboolean useCache)
 560 {
 561     TRY;
 562 
 563     if (env->EnsureLocalCapacity(1) < 0) {
 564         return NULL;
 565     }
 566 
 567     jobject globalRef = (jobject)AwtToolkit::GetInstance().
 568         InvokeFunction((void*(*)(void*))
 569                        AwtComponent::FindHeavyweightUnderCursor,
 570                        (void *)useCache);
 571     jobject localRef = env->NewLocalRef(globalRef);
 572     env->DeleteGlobalRef(globalRef);
 573     return localRef;
 574 
 575     CATCH_BAD_ALLOC_RET(NULL);
 576 }
 577 
 578 /*
 579  * Class:     sun_awt_windows_WGlobalCursorManager
 580  * Method:    getLocationOnScreen
 581  * Signature: (L/java/awt/Component;)L/java/awt/Point
 582  */
 583 JNIEXPORT jobject JNICALL
 584 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen(
 585     JNIEnv *env, jobject, jobject component)
 586 {
 587     TRY;
 588 
 589     JNI_CHECK_NULL_RETURN_NULL(component, "null component");
 590     jobject point =
 591         env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID);
 592     return point;
 593 
 594     CATCH_BAD_ALLOC_RET(NULL);
 595 }
 596 
 597 } /* extern "C" */