1 /* 2 * Copyright (c) 1996, 2014, 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 "awt.h" 27 #include "awt_Toolkit.h" 28 #include "awt_Checkbox.h" 29 #include "awt_Canvas.h" 30 #include "awt_Window.h" 31 32 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 33 */ 34 35 /***********************************************************************/ 36 // Struct for _SetLabel() method 37 struct SetLabelStruct { 38 jobject checkbox; 39 jstring label; 40 }; 41 // Struct for _SetState() method 42 struct SetStateStruct { 43 jobject checkbox; 44 jboolean state; 45 }; 46 47 /************************************************************************ 48 * AwtCheckbox fields 49 */ 50 51 /* java.awt.Checkbox field IDs */ 52 jfieldID AwtCheckbox::labelID; 53 jfieldID AwtCheckbox::groupID; 54 jfieldID AwtCheckbox::stateID; 55 56 const int AwtCheckbox::CHECK_SIZE = 13; 57 58 /************************************************************************ 59 * AwtCheckbox methods 60 */ 61 62 AwtCheckbox::AwtCheckbox() { 63 64 m_fLButtonDowned = FALSE; 65 } 66 67 LPCTSTR AwtCheckbox::GetClassName() { 68 return TEXT("BUTTON"); /* System provided checkbox class (a type of button) */ 69 } 70 71 AwtCheckbox* AwtCheckbox::Create(jobject peer, jobject parent) 72 { 73 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 74 75 jstring label = NULL; 76 jobject target = NULL; 77 AwtCheckbox *checkbox = NULL; 78 79 try { 80 if (env->EnsureLocalCapacity(2) < 0) { 81 return NULL; 82 } 83 84 AwtComponent* awtParent; 85 JNI_CHECK_NULL_GOTO(parent, "null parent", done); 86 87 awtParent = (AwtComponent*)JNI_GET_PDATA(parent); 88 JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done); 89 90 target = env->GetObjectField(peer, AwtObject::targetID); 91 JNI_CHECK_NULL_GOTO(target, "null target", done); 92 93 checkbox = new AwtCheckbox(); 94 95 { 96 DWORD style = WS_CHILD | WS_CLIPSIBLINGS | BS_OWNERDRAW; 97 LPCWSTR defaultLabelStr = L""; 98 LPCWSTR labelStr = defaultLabelStr; 99 DWORD exStyle = 0; 100 101 if (GetRTL()) { 102 exStyle |= WS_EX_RIGHT; 103 if (GetRTLReadingOrder()) 104 exStyle |= WS_EX_RTLREADING; 105 } 106 107 label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID); 108 if (label != NULL) { 109 labelStr = JNU_GetStringPlatformChars(env, label, 0); 110 } 111 if (labelStr != 0) { 112 jint x = env->GetIntField(target, AwtComponent::xID); 113 jint y = env->GetIntField(target, AwtComponent::yID); 114 jint width = env->GetIntField(target, AwtComponent::widthID); 115 jint height = env->GetIntField(target, AwtComponent::heightID); 116 checkbox->CreateHWnd(env, labelStr, style, exStyle, 117 x, y, width, height, 118 awtParent->GetHWnd(), 119 reinterpret_cast<HMENU>(static_cast<INT_PTR>( 120 awtParent->CreateControlID())), 121 ::GetSysColor(COLOR_WINDOWTEXT), 122 ::GetSysColor(COLOR_BTNFACE), 123 peer); 124 125 if (labelStr != defaultLabelStr) { 126 JNU_ReleaseStringPlatformChars(env, label, labelStr); 127 } 128 } else { 129 throw std::bad_alloc(); 130 } 131 } 132 } catch (...) { 133 env->DeleteLocalRef(label); 134 env->DeleteLocalRef(target); 135 throw; 136 } 137 138 done: 139 env->DeleteLocalRef(label); 140 env->DeleteLocalRef(target); 141 142 return checkbox; 143 } 144 145 MsgRouting 146 AwtCheckbox::WmMouseUp(UINT flags, int x, int y, int button) 147 { 148 MsgRouting mrResult = AwtComponent::WmMouseUp(flags, x, y, button); 149 150 if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd())))) 151 { 152 return mrConsume; 153 } 154 155 POINT p = {x, y}; 156 RECT rect; 157 ::GetClientRect(GetHWnd(), &rect); 158 159 if (::PtInRect(&rect, p) && button == LEFT_BUTTON && m_fLButtonDowned) { 160 WmNotify(BN_CLICKED); 161 } 162 m_fLButtonDowned = FALSE; 163 return mrResult; 164 } 165 166 MsgRouting 167 AwtCheckbox::WmMouseDown(UINT flags, int x, int y, int button) 168 { 169 m_fLButtonDowned = TRUE; 170 return AwtComponent::WmMouseDown(flags, x, y, button); 171 } 172 173 MsgRouting 174 AwtCheckbox::WmNotify(UINT notifyCode) 175 { 176 if (notifyCode == BN_CLICKED) { 177 BOOL fChecked = !GetState(); 178 DoCallback("handleAction", "(Z)V", fChecked); 179 } 180 return mrDoDefault; 181 } 182 183 BOOL AwtCheckbox::GetState() 184 { 185 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 186 187 if (env->EnsureLocalCapacity(2) < 0) { 188 return NULL; 189 } 190 jobject target = GetTarget(env); 191 jboolean result = JNI_FALSE; 192 if (target != NULL) { 193 result = env->GetBooleanField(target, AwtCheckbox::stateID); 194 } 195 196 env->DeleteLocalRef(target); 197 198 return (BOOL)result; 199 } 200 201 int AwtCheckbox::GetCheckSize() 202 { 203 /* using height of small icon for check mark size */ 204 return CHECK_SIZE; 205 } 206 207 MsgRouting 208 AwtCheckbox::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo) 209 { 210 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 211 212 if (env->EnsureLocalCapacity(4) < 0) { 213 return mrConsume; 214 } 215 216 jobject self = GetPeer(env); 217 jobject target = env->GetObjectField(self, AwtObject::targetID); 218 219 HDC hDC = drawInfo.hDC; 220 RECT rect = drawInfo.rcItem; 221 int checkSize; 222 UINT nState; 223 SIZE size; 224 225 jobject font = GET_FONT(target, self); 226 jstring str = (jstring)env->GetObjectField(target, AwtCheckbox::labelID); 227 size = AwtFont::getMFStringSize(hDC, font, str); 228 229 jobject group = env->GetObjectField(target, AwtCheckbox::groupID); 230 if (group != NULL) 231 nState = DFCS_BUTTONRADIO; 232 else 233 nState = DFCS_BUTTONCHECK; 234 235 if (GetState()) 236 nState |= DFCS_CHECKED; 237 else 238 nState &= ~DFCS_CHECKED; 239 240 if (drawInfo.itemState & ODS_SELECTED) 241 nState |= DFCS_PUSHED; 242 243 if (drawInfo.itemAction & ODA_DRAWENTIRE) { 244 VERIFY(::FillRect (hDC, &rect, GetBackgroundBrush())); 245 } 246 247 /* draw check mark */ 248 checkSize = GetCheckSize(); 249 RECT boxRect; 250 251 boxRect.left = (GetRTL()) ? rect.right - checkSize : rect.left; 252 boxRect.top = (rect.bottom - rect.top - checkSize)/2; 253 boxRect.right = boxRect.left + checkSize; 254 boxRect.bottom = boxRect.top + checkSize; 255 ::DrawFrameControl(hDC, &boxRect, DFC_BUTTON, nState); 256 257 /* 258 * draw string 259 * 260 * 4 is a heuristic number 261 */ 262 rect.left = rect.left + checkSize + checkSize/4; 263 if (drawInfo.itemAction & ODA_DRAWENTIRE) { 264 BOOL bEnabled = isEnabled(); 265 266 int x = (GetRTL()) ? rect.right - (checkSize + checkSize / 4 + size.cx) 267 : rect.left; 268 int y = (rect.top + rect.bottom - size.cy) / 2; 269 if (bEnabled) { 270 AwtComponent::DrawWindowText(hDC, font, str, x, y); 271 } else { 272 AwtComponent::DrawGrayText(hDC, font, str, x, y); 273 } 274 } 275 276 /* Draw focus rect */ 277 RECT focusRect; 278 const int margin = 2; /* 2 is a heuristic number */ 279 280 focusRect.left = (GetRTL()) ? rect.right - checkSize - checkSize / 4 - 281 2 * margin - size.cx 282 : rect.left - margin; 283 focusRect.top = (rect.top+rect.bottom-size.cy)/2; 284 focusRect.right = (GetRTL()) ? rect.right - checkSize - checkSize / 4 + 285 margin 286 : focusRect.left + size.cx + 2 * margin; 287 focusRect.bottom = focusRect.top + size.cy; 288 289 /* draw focus rect */ 290 if ((drawInfo.itemState & ODS_FOCUS) && 291 ((drawInfo.itemAction & ODA_FOCUS)|| 292 (drawInfo.itemAction &ODA_DRAWENTIRE))) { 293 VERIFY(::DrawFocusRect(hDC, &focusRect)); 294 } 295 /* erase focus rect */ 296 else if (!(drawInfo.itemState & ODS_FOCUS) && 297 (drawInfo.itemAction & ODA_FOCUS)) { 298 VERIFY(::DrawFocusRect(hDC, &focusRect)); 299 } 300 301 /* Notify any subclasses */ 302 rect = drawInfo.rcItem; 303 DoCallback("handlePaint", "(IIII)V", rect.left, rect.top, 304 rect.right-rect.left, rect.bottom-rect.top); 305 306 env->DeleteLocalRef(target); 307 env->DeleteLocalRef(font); 308 env->DeleteLocalRef(str); 309 env->DeleteLocalRef(group); 310 311 return mrConsume; 312 } 313 314 MsgRouting AwtCheckbox::WmPaint(HDC) 315 { 316 /* Suppress peer notification, because it's handled in WmDrawItem. */ 317 return mrDoDefault; 318 } 319 320 BOOL AwtCheckbox::IsFocusingMouseMessage(MSG *pMsg) { 321 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP; 322 } 323 324 BOOL AwtCheckbox::IsFocusingKeyMessage(MSG *pMsg) { 325 return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) && 326 pMsg->wParam == VK_SPACE; 327 } 328 329 MsgRouting AwtCheckbox::HandleEvent(MSG *msg, BOOL synthetic) 330 { 331 if (IsFocusingMouseMessage(msg)) { 332 SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_LBUTTONDOWN ? TRUE : FALSE)); 333 delete msg; 334 return mrConsume; 335 } 336 if (IsFocusingKeyMessage(msg)) { 337 SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_KEYDOWN ? TRUE : FALSE)); 338 if (msg->message == WM_KEYDOWN) { 339 m_fLButtonDowned = TRUE; 340 } else if (m_fLButtonDowned == TRUE) { 341 WmNotify(BN_CLICKED); 342 m_fLButtonDowned = TRUE; 343 } 344 delete msg; 345 return mrConsume; 346 } 347 return AwtComponent::HandleEvent(msg, synthetic); 348 } 349 350 void AwtCheckbox::_SetLabel(void *param) 351 { 352 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 353 354 SetLabelStruct *sls = (SetLabelStruct *)param; 355 jobject checkbox = sls->checkbox; 356 jstring label = sls->label; 357 358 int badAlloc = 0; 359 AwtCheckbox *c = NULL; 360 361 PDATA pData; 362 JNI_CHECK_PEER_GOTO(checkbox, done); 363 364 c = (AwtCheckbox *)pData; 365 if (::IsWindow(c->GetHWnd())) 366 { 367 LPCTSTR labelStr = NULL; 368 369 // By convension null label means empty string 370 if (label == NULL) 371 { 372 labelStr = TEXT(""); 373 } 374 else 375 { 376 labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); 377 } 378 379 if (labelStr == NULL) 380 { 381 badAlloc = 1; 382 } 383 else 384 { 385 c->SetText(labelStr); 386 c->VerifyState(); 387 if (label != NULL) { 388 JNU_ReleaseStringPlatformChars(env, label, labelStr); 389 } 390 } 391 } 392 393 done: 394 env->DeleteGlobalRef(checkbox); 395 if (label != NULL) 396 { 397 env->DeleteGlobalRef(label); 398 } 399 400 delete sls; 401 402 if (badAlloc) { 403 throw std::bad_alloc(); 404 } 405 } 406 407 void AwtCheckbox::_SetCheckboxGroup(void *param) 408 { 409 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 410 411 jobject *jos = (jobject *)param; 412 jobject checkbox = jos[0]; 413 jobject group = jos[1]; 414 415 AwtCheckbox *c = NULL; 416 417 PDATA pData; 418 JNI_CHECK_PEER_GOTO(checkbox, done); 419 420 c = (AwtCheckbox *)pData; 421 if (::IsWindow(c->GetHWnd())) 422 { 423 /* 424 #ifdef DEBUG 425 if (group != NULL) { 426 DASSERT(IsInstanceOf((HObject*)group, "java/awt/CheckboxGroup")); 427 } 428 #endif 429 */ 430 long style = c->GetStyle(); 431 if (group == NULL) { 432 style = style & ~BS_AUTORADIOBUTTON; 433 style = style | BS_AUTOCHECKBOX; 434 } else { 435 style = style & ~BS_AUTOCHECKBOX; 436 style = style | BS_AUTORADIOBUTTON; 437 } 438 c->SetStyle(style); 439 c->SendMessage(BM_SETSTYLE, (WPARAM)BS_OWNERDRAW, (LPARAM)TRUE); 440 c->VerifyState(); 441 } 442 443 done: 444 env->DeleteGlobalRef(checkbox); 445 if (group != NULL) { 446 env->DeleteGlobalRef(group); 447 } 448 449 delete[] jos; 450 } 451 452 void AwtCheckbox::_SetState(void *param) 453 { 454 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 455 456 SetStateStruct *sss = (SetStateStruct *)param; 457 jobject checkbox = sss->checkbox; 458 jboolean state = sss->state; 459 460 AwtCheckbox *c = NULL; 461 462 PDATA pData; 463 JNI_CHECK_PEER_GOTO(checkbox, done); 464 465 c = (AwtCheckbox *)pData; 466 if (::IsWindow(c->GetHWnd())) 467 { 468 /* 469 * when multifont and group checkbox receive setState native 470 * method, it must be redraw to display correct check mark 471 */ 472 jobject target = env->GetObjectField(checkbox, AwtObject::targetID); 473 jobject group = env->GetObjectField(target, AwtCheckbox::groupID); 474 HWND hWnd = c->GetHWnd(); 475 if (group != NULL) { 476 RECT rect; 477 VERIFY(::GetWindowRect(hWnd, &rect)); 478 VERIFY(::ScreenToClient(hWnd, (LPPOINT)&rect)); 479 VERIFY(::ScreenToClient(hWnd, ((LPPOINT)&rect) + 1)); 480 VERIFY(::InvalidateRect(hWnd, &rect,TRUE)); 481 VERIFY(::UpdateWindow(hWnd)); 482 } else { 483 c->SendMessage(BM_SETCHECK, (WPARAM)(state ? BST_CHECKED : BST_UNCHECKED)); 484 VERIFY(::InvalidateRect(hWnd, NULL, FALSE)); 485 } 486 c->VerifyState(); 487 env->DeleteLocalRef(target); 488 env->DeleteLocalRef(group); 489 } 490 491 done: 492 env->DeleteGlobalRef(checkbox); 493 494 delete sss; 495 } 496 497 #ifdef DEBUG 498 void AwtCheckbox::VerifyState() 499 { 500 if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) { 501 return; 502 } 503 504 if (m_callbacksEnabled == FALSE) { 505 /* Component is not fully setup yet. */ 506 return; 507 } 508 509 AwtComponent::VerifyState(); 510 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 511 512 if (env->EnsureLocalCapacity(2) < 0) { 513 return; 514 } 515 516 jobject target = GetTarget(env); 517 518 /* Check button style */ 519 DWORD style = ::GetWindowLong(GetHWnd(), GWL_STYLE); 520 DASSERT(style & BS_OWNERDRAW); 521 522 /* Check label */ 523 int len = ::GetWindowTextLength(GetHWnd()); 524 LPTSTR peerStr; 525 try { 526 peerStr = new TCHAR[len+1]; 527 } catch (std::bad_alloc&) { 528 env->DeleteLocalRef(target); 529 throw; 530 } 531 532 GetText(peerStr, len+1); 533 jstring label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID); 534 DASSERT(_tcscmp(peerStr, JavaStringBuffer(env, label)) == 0); 535 delete [] peerStr; 536 537 env->DeleteLocalRef(target); 538 env->DeleteLocalRef(label); 539 } 540 #endif 541 542 543 /************************************************************************ 544 * Checkbox native methods 545 */ 546 547 extern "C" { 548 549 /* 550 * Class: sun_awt_windows_WButtonPeer 551 * Method: initIDs 552 * Signature: ()V 553 */ 554 JNIEXPORT void JNICALL 555 Java_java_awt_Checkbox_initIDs(JNIEnv *env, jclass cls) 556 { 557 TRY; 558 559 AwtCheckbox::labelID = 560 env->GetFieldID(cls, "label", "Ljava/lang/String;"); 561 DASSERT(AwtCheckbox::labelID != NULL); 562 CHECK_NULL(AwtCheckbox::labelID); 563 564 AwtCheckbox::groupID = 565 env->GetFieldID(cls, "group", "Ljava/awt/CheckboxGroup;"); 566 DASSERT(AwtCheckbox::groupID != NULL); 567 CHECK_NULL(AwtCheckbox::groupID); 568 569 AwtCheckbox::stateID = env->GetFieldID(cls, "state", "Z"); 570 DASSERT(AwtCheckbox::stateID != NULL); 571 572 CATCH_BAD_ALLOC; 573 } 574 575 } /* extern "C" */ 576 577 578 /************************************************************************ 579 * WCheckboxPeer native methods 580 */ 581 582 extern "C" { 583 584 /* 585 * Class: sun_awt_windows_WCheckboxPeer 586 * Method: getCheckMarkSize 587 * Signature: ()I 588 */ 589 JNIEXPORT jint JNICALL 590 Java_sun_awt_windows_WCheckboxPeer_getCheckMarkSize(JNIEnv *env, 591 jclass cls) 592 { 593 return (jint)AwtCheckbox::GetCheckSize(); 594 } 595 596 /* 597 * Class: sun_awt_windows_WCheckboxPeer 598 * Method: setState 599 * Signature: (Z)V 600 */ 601 JNIEXPORT void JNICALL 602 Java_sun_awt_windows_WCheckboxPeer_setState(JNIEnv *env, jobject self, 603 jboolean state) 604 { 605 TRY; 606 607 SetStateStruct *sss = new SetStateStruct; 608 sss->checkbox = env->NewGlobalRef(self); 609 sss->state = state; 610 611 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetState, sss); 612 // global refs and sss are deleted in _SetState() 613 614 CATCH_BAD_ALLOC; 615 } 616 617 /* 618 * Class: sun_awt_windows_WCheckboxPeer 619 * Method: setCheckboxGroup 620 * Signature: (Ljava/awt/CheckboxGroup;)V 621 */ 622 JNIEXPORT void JNICALL 623 Java_sun_awt_windows_WCheckboxPeer_setCheckboxGroup(JNIEnv *env, jobject self, 624 jobject group) 625 { 626 TRY; 627 628 jobject *jos = new jobject[2]; 629 jos[0] = env->NewGlobalRef(self); 630 jos[1] = env->NewGlobalRef(group); 631 632 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetCheckboxGroup, jos); 633 // global refs and jos are deleted in _SetLabel() 634 635 CATCH_BAD_ALLOC; 636 } 637 638 /* 639 * Class: sun_awt_windows_WCheckboxPeer 640 * Method: setLabel 641 * Signature: (Ljava/lang/String;)V 642 */ 643 JNIEXPORT void JNICALL 644 Java_sun_awt_windows_WCheckboxPeer_setLabel(JNIEnv *env, jobject self, 645 jstring label) 646 { 647 TRY; 648 649 SetLabelStruct *sls = new SetLabelStruct; 650 sls->checkbox = env->NewGlobalRef(self); 651 sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL; 652 653 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetLabel, sls); 654 // global refs and sls are deleted in _SetLabel() 655 656 CATCH_BAD_ALLOC; 657 } 658 659 /* 660 * Class: sun_awt_windows_WCheckboxPeer 661 * Method: create 662 * Signature: (Lsun/awt/windows/WComponentPeer;)V 663 */ 664 JNIEXPORT void JNICALL 665 Java_sun_awt_windows_WCheckboxPeer_create(JNIEnv *env, jobject self, 666 jobject parent) 667 { 668 TRY; 669 670 PDATA pData; 671 JNI_CHECK_PEER_RETURN(parent); 672 AwtToolkit::CreateComponent(self, parent, 673 (AwtToolkit::ComponentFactory) 674 AwtCheckbox::Create); 675 JNI_CHECK_PEER_CREATION_RETURN(self); 676 677 #ifdef DEBUG 678 ((AwtComponent*)JNI_GET_PDATA(self))->VerifyState(); 679 #endif 680 681 CATCH_BAD_ALLOC; 682 } 683 684 } /* extern "C" */