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 AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot, 395 yHotSpot, nW, nH, nSS, cols, 396 (BYTE *)andMaskPtr))); 397 CATCH_BAD_ALLOC; 398 } 399 400 /* 401 * Class: sun_awt_windows_WCustomCursor 402 * Method: getCursorWidth 403 * Signature: ()I 404 */ 405 JNIEXPORT jint JNICALL 406 Java_sun_awt_windows_WCustomCursor_getCursorWidth(JNIEnv *, jclass) 407 { 408 TRY; 409 410 DTRACE_PRINTLN("WCustomCursor.getCursorWidth()"); 411 return (jint)::GetSystemMetrics(SM_CXCURSOR); 412 413 CATCH_BAD_ALLOC_RET(0); 414 } 415 416 /* 417 * Class: sun_awt_windows_WCustomCursor 418 * Method: getCursorHeight 419 * Signature: ()I 420 */ 421 JNIEXPORT jint JNICALL 422 Java_sun_awt_windows_WCustomCursor_getCursorHeight(JNIEnv *, jclass) 423 { 424 TRY; 425 426 DTRACE_PRINTLN("WCustomCursor.getCursorHeight()"); 427 return (jint)::GetSystemMetrics(SM_CYCURSOR); 428 429 CATCH_BAD_ALLOC_RET(0); 430 } 431 432 /************************************************************************ 433 * WGlobalCursorManager native methods 434 */ 435 436 /* 437 * Class: sun_awt_windows_WGlobalCursorManager 438 * Method: getCursorPos 439 * Signature: (Ljava/awt/Point;)V 440 */ 441 JNIEXPORT void JNICALL 442 Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env, 443 jobject, 444 jobject point) 445 { 446 TRY; 447 448 POINT p; 449 ::GetCursorPos(&p); 450 env->SetIntField(point, AwtCursor::pointXID, (jint)p.x); 451 env->SetIntField(point, AwtCursor::pointYID, (jint)p.y); 452 453 CATCH_BAD_ALLOC; 454 } 455 456 struct GlobalSetCursorStruct { 457 jobject cursor; 458 jboolean u; 459 }; 460 461 static void GlobalSetCursor(void* pStruct) { 462 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 463 jobject cursor = ((GlobalSetCursorStruct*)pStruct)->cursor; 464 jboolean u = ((GlobalSetCursorStruct*)pStruct)->u; 465 jlong pData = env->GetLongField(cursor, AwtCursor::pDataID); 466 AwtCursor *awtCursor = (AwtCursor *)jlong_to_ptr(pData); 467 468 if (awtCursor == NULL) { 469 awtCursor = AwtCursor::CreateSystemCursor(cursor); 470 } 471 472 HCURSOR hCursor = awtCursor->GetHCursor(); 473 474 BOOL blocked = false; 475 if (jobject jcomp = AwtComponent::FindHeavyweightUnderCursor(u)) { 476 if(jobject jpeer = AwtObject::GetPeerForTarget(env, jcomp)) 477 { 478 if(AwtComponent *awtComponent = (AwtComponent*)JNI_GET_PDATA(jpeer)) { 479 blocked = ::IsWindow(AwtWindow::GetModalBlocker( 480 AwtComponent::GetTopLevelParentForWindow( 481 awtComponent->GetHWnd()))); 482 if (!blocked) { 483 awtComponent->setCursorCache(hCursor); 484 } 485 } 486 env->DeleteLocalRef(jpeer); 487 } 488 env->DeleteGlobalRef(jcomp); 489 } 490 491 if (!blocked) { 492 ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR 493 } 494 495 env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor); 496 } 497 498 /* 499 * Class: sun_awt_windows_WGlobalCursorManager 500 * Method: setCursorImpl 501 * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V 502 */ 503 JNIEXPORT void JNICALL 504 Java_sun_awt_windows_WGlobalCursorManager_setCursorImpl(JNIEnv *env, jobject, 505 jobject, jobject cursor, jboolean u) 506 { 507 TRY; 508 509 if (cursor != NULL) { // fix for 4430302 - getCursor() returns NULL 510 GlobalSetCursorStruct data; 511 data.cursor = env->NewGlobalRef(cursor); 512 data.u = u; 513 AwtToolkit::GetInstance().InvokeFunction( 514 GlobalSetCursor, 515 (void *)&data); 516 } else { 517 JNU_ThrowNullPointerException(env, "NullPointerException"); 518 } 519 CATCH_BAD_ALLOC; 520 } 521 522 /* 523 * Class: sun_awt_windows_WGlobalCursorManager 524 * Method: setCursorDirect 525 * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V 526 */ 527 JNIEXPORT void JNICALL 528 Java_sun_awt_windows_WGlobalCursorManager_setCursorDirect(JNIEnv *env, jobject, 529 jobject, jobject cursor, jboolean u) 530 { 531 TRY; 532 533 if (cursor != NULL) { 534 GlobalSetCursorStruct data; 535 data.cursor = env->NewGlobalRef(cursor); 536 data.u = u; 537 GlobalSetCursor((void *)&data); 538 } else { 539 JNU_ThrowNullPointerException(env, "NullPointerException"); 540 } 541 CATCH_BAD_ALLOC; 542 } 543 544 /* 545 * Class: sun_awt_windows_WGlobalCursorManager 546 * Method: findHeavyweight 547 * Signature: (II)Z 548 */ 549 JNIEXPORT jobject JNICALL 550 Java_sun_awt_windows_WGlobalCursorManager_findHeavyweightUnderCursor( 551 JNIEnv *env, jobject, jboolean useCache) 552 { 553 TRY; 554 555 if (env->EnsureLocalCapacity(1) < 0) { 556 return NULL; 557 } 558 559 jobject globalRef = (jobject)AwtToolkit::GetInstance(). 560 InvokeFunction((void*(*)(void*)) 561 AwtComponent::FindHeavyweightUnderCursor, 562 (void *)useCache); 563 jobject localRef = env->NewLocalRef(globalRef); 564 env->DeleteGlobalRef(globalRef); 565 return localRef; 566 567 CATCH_BAD_ALLOC_RET(NULL); 568 } 569 570 /* 571 * Class: sun_awt_windows_WGlobalCursorManager 572 * Method: findComponentAt 573 * Signature: (L/java/awt/Container;II)L/java/awt/Component 574 */ 575 JNIEXPORT jobject JNICALL 576 Java_sun_awt_windows_WGlobalCursorManager_findComponentAt( 577 JNIEnv *env, jobject, jobject container, jint x, jint y) 578 { 579 TRY; 580 581 /* 582 * Call private version of Container.findComponentAt with the following 583 * flag set -- ignoreEnabled = false (i.e., don't return or recur into 584 * disabled Components); 585 * NOTE: it may return a JRootPane's glass pane as the target Component 586 */ 587 JNI_CHECK_NULL_RETURN_NULL(container, "null container"); 588 jobject comp = 589 env->CallObjectMethod(container, AwtContainer::findComponentAtMID, 590 x, y, JNI_FALSE); 591 return comp; 592 593 CATCH_BAD_ALLOC_RET(NULL); 594 } 595 596 /* 597 * Class: sun_awt_windows_WGlobalCursorManager 598 * Method: getLocationOnScreen 599 * Signature: (L/java/awt/Component;)L/java/awt/Point 600 */ 601 JNIEXPORT jobject JNICALL 602 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen( 603 JNIEnv *env, jobject, jobject component) 604 { 605 TRY; 606 607 JNI_CHECK_NULL_RETURN_NULL(component, "null component"); 608 jobject point = 609 env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID); 610 return point; 611 612 CATCH_BAD_ALLOC_RET(NULL); 613 } 614 615 } /* extern "C" */