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: findComponentAt 558 * Signature: (L/java/awt/Container;II)L/java/awt/Component 559 */ 560 JNIEXPORT jobject JNICALL 561 Java_sun_awt_windows_WGlobalCursorManager_findComponentAt( 562 JNIEnv *env, jobject, jobject container, jint x, jint y) 563 { 564 TRY; 565 566 /* 567 * Call private version of Container.findComponentAt with the following 568 * flag set -- ignoreEnabled = false (i.e., don't return or recur into 569 * disabled Components); 570 * NOTE: it may return a JRootPane's glass pane as the target Component 571 */ 572 JNI_CHECK_NULL_RETURN_NULL(container, "null container"); 573 jobject comp = 574 env->CallObjectMethod(container, AwtContainer::findComponentAtMID, 575 x, y, JNI_FALSE); 576 return comp; 577 578 CATCH_BAD_ALLOC_RET(NULL); 579 } 580 581 /* 582 * Class: sun_awt_windows_WGlobalCursorManager 583 * Method: getLocationOnScreen 584 * Signature: (L/java/awt/Component;)L/java/awt/Point 585 */ 586 JNIEXPORT jobject JNICALL 587 Java_sun_awt_windows_WGlobalCursorManager_getLocationOnScreen( 588 JNIEnv *env, jobject, jobject component) 589 { 590 TRY; 591 592 JNI_CHECK_NULL_RETURN_NULL(component, "null component"); 593 jobject point = 594 env->CallObjectMethod(component, AwtComponent::getLocationOnScreenMID); 595 return point; 596 597 CATCH_BAD_ALLOC_RET(NULL); 598 } 599 600 } /* extern "C" */