1 /* 2 * Copyright (c) 1996, 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 "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 if(::DrawFocusRect(hDC, &focusRect) == 0) 294 VERIFY(::GetLastError() == 0); 295 } 296 /* erase focus rect */ 297 else if (!(drawInfo.itemState & ODS_FOCUS) && 298 (drawInfo.itemAction & ODA_FOCUS)) { 299 if(::DrawFocusRect(hDC, &focusRect) == 0) 300 VERIFY(::GetLastError() == 0); 301 } 302 303 /* Notify any subclasses */ 304 rect = drawInfo.rcItem; 305 DoCallback("handlePaint", "(IIII)V", rect.left, rect.top, 306 rect.right-rect.left, rect.bottom-rect.top); 307 308 env->DeleteLocalRef(target); 309 env->DeleteLocalRef(font); 310 env->DeleteLocalRef(str); 311 env->DeleteLocalRef(group); 312 313 return mrConsume; 314 } 315 316 MsgRouting AwtCheckbox::WmPaint(HDC) 317 { 318 /* Suppress peer notification, because it's handled in WmDrawItem. */ 319 return mrDoDefault; 320 } 321 322 BOOL AwtCheckbox::IsFocusingMouseMessage(MSG *pMsg) { 323 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP; 324 } 325 326 BOOL AwtCheckbox::IsFocusingKeyMessage(MSG *pMsg) { 327 return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) && 328 pMsg->wParam == VK_SPACE; 329 } 330 331 MsgRouting AwtCheckbox::HandleEvent(MSG *msg, BOOL synthetic) 332 { 333 if (IsFocusingMouseMessage(msg)) { 334 SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_LBUTTONDOWN ? TRUE : FALSE)); 335 delete msg; 336 return mrConsume; 337 } 338 if (IsFocusingKeyMessage(msg)) { 339 SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_KEYDOWN ? TRUE : FALSE)); 340 if (msg->message == WM_KEYDOWN) { 341 m_fLButtonDowned = TRUE; 342 } else if (m_fLButtonDowned == TRUE) { 343 WmNotify(BN_CLICKED); 344 m_fLButtonDowned = TRUE; 345 } 346 delete msg; 347 return mrConsume; 348 } 349 return AwtComponent::HandleEvent(msg, synthetic); 350 } 351 352 void AwtCheckbox::_SetLabel(void *param) 353 { 354 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 355 356 SetLabelStruct *sls = (SetLabelStruct *)param; 357 jobject checkbox = sls->checkbox; 358 jstring label = sls->label; 359 360 int badAlloc = 0; 361 AwtCheckbox *c = NULL; 362 363 PDATA pData; 364 JNI_CHECK_PEER_GOTO(checkbox, done); 365 366 c = (AwtCheckbox *)pData; 367 if (::IsWindow(c->GetHWnd())) 368 { 369 LPCTSTR labelStr = NULL; 370 371 // By convension null label means empty string 372 if (label == NULL) 373 { 374 labelStr = TEXT(""); 375 } 376 else 377 { 378 labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); 379 } 380 381 if (labelStr == NULL) 382 { 383 badAlloc = 1; 384 } 385 else 386 { 387 c->SetText(labelStr); 388 c->VerifyState(); 389 if (label != NULL) { 390 JNU_ReleaseStringPlatformChars(env, label, labelStr); 391 } 392 } 393 } 394 395 done: 396 env->DeleteGlobalRef(checkbox); 397 if (label != NULL) 398 { 399 env->DeleteGlobalRef(label); 400 } 401 402 delete sls; 403 404 if (badAlloc) { 405 throw std::bad_alloc(); 406 } 407 } 408 409 void AwtCheckbox::_SetCheckboxGroup(void *param) 410 { 411 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 412 413 jobject *jos = (jobject *)param; 414 jobject checkbox = jos[0]; 415 jobject group = jos[1]; 416 417 AwtCheckbox *c = NULL; 418 419 PDATA pData; 420 JNI_CHECK_PEER_GOTO(checkbox, done); 421 422 c = (AwtCheckbox *)pData; 423 if (::IsWindow(c->GetHWnd())) 424 { 425 /* 426 #ifdef DEBUG 427 if (group != NULL) { 428 DASSERT(IsInstanceOf((HObject*)group, "java/awt/CheckboxGroup")); 429 } 430 #endif 431 */ 432 long style = c->GetStyle(); 433 if (group == NULL) { 434 style = style & ~BS_AUTORADIOBUTTON; 435 style = style | BS_AUTOCHECKBOX; 436 } else { 437 style = style & ~BS_AUTOCHECKBOX; 438 style = style | BS_AUTORADIOBUTTON; 439 } 440 c->SetStyle(style); 441 c->SendMessage(BM_SETSTYLE, (WPARAM)BS_OWNERDRAW, (LPARAM)TRUE); 442 c->VerifyState(); 443 } 444 445 done: 446 env->DeleteGlobalRef(checkbox); 447 if (group != NULL) { 448 env->DeleteGlobalRef(group); 449 } 450 451 delete[] jos; 452 } 453 454 void AwtCheckbox::_SetState(void *param) 455 { 456 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 457 458 SetStateStruct *sss = (SetStateStruct *)param; 459 jobject checkbox = sss->checkbox; 460 jboolean state = sss->state; 461 462 AwtCheckbox *c = NULL; 463 464 PDATA pData; 465 JNI_CHECK_PEER_GOTO(checkbox, done); 466 467 c = (AwtCheckbox *)pData; 468 if (::IsWindow(c->GetHWnd())) 469 { 470 /* 471 * when multifont and group checkbox receive setState native 472 * method, it must be redraw to display correct check mark 473 */ 474 jobject target = env->GetObjectField(checkbox, AwtObject::targetID); 475 jobject group = env->GetObjectField(target, AwtCheckbox::groupID); 476 HWND hWnd = c->GetHWnd(); 477 if (group != NULL) { 478 RECT rect; 479 VERIFY(::GetWindowRect(hWnd, &rect)); 480 VERIFY(::ScreenToClient(hWnd, (LPPOINT)&rect)); 481 VERIFY(::ScreenToClient(hWnd, ((LPPOINT)&rect) + 1)); 482 VERIFY(::InvalidateRect(hWnd, &rect,TRUE)); 483 VERIFY(::UpdateWindow(hWnd)); 484 } else { 485 c->SendMessage(BM_SETCHECK, (WPARAM)(state ? BST_CHECKED : BST_UNCHECKED)); 486 VERIFY(::InvalidateRect(hWnd, NULL, FALSE)); 487 } 488 c->VerifyState(); 489 env->DeleteLocalRef(target); 490 env->DeleteLocalRef(group); 491 } 492 493 done: 494 env->DeleteGlobalRef(checkbox); 495 496 delete sss; 497 } 498 499 #ifdef DEBUG 500 void AwtCheckbox::VerifyState() 501 { 502 if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) { 503 return; 504 } 505 506 if (m_callbacksEnabled == FALSE) { 507 /* Component is not fully setup yet. */ 508 return; 509 } 510 511 AwtComponent::VerifyState(); 512 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 513 514 if (env->EnsureLocalCapacity(2) < 0) { 515 return; 516 } 517 518 jobject target = GetTarget(env); 519 520 /* Check button style */ 521 DWORD style = ::GetWindowLong(GetHWnd(), GWL_STYLE); 522 DASSERT(style & BS_OWNERDRAW); 523 524 /* Check label */ 525 int len = ::GetWindowTextLength(GetHWnd()); 526 LPTSTR peerStr; 527 try { 528 peerStr = new TCHAR[len+1]; 529 } catch (std::bad_alloc&) { 530 env->DeleteLocalRef(target); 531 throw; 532 } 533 534 GetText(peerStr, len+1); 535 jstring label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID); 536 DASSERT(_tcscmp(peerStr, JavaStringBuffer(env, label)) == 0); 537 delete [] peerStr; 538 539 env->DeleteLocalRef(target); 540 env->DeleteLocalRef(label); 541 } 542 #endif 543 544 545 /************************************************************************ 546 * Checkbox native methods 547 */ 548 549 extern "C" { 550 551 /* 552 * Class: sun_awt_windows_WButtonPeer 553 * Method: initIDs 554 * Signature: ()V 555 */ 556 JNIEXPORT void JNICALL 557 Java_java_awt_Checkbox_initIDs(JNIEnv *env, jclass cls) 558 { 559 TRY; 560 561 AwtCheckbox::labelID = 562 env->GetFieldID(cls, "label", "Ljava/lang/String;"); 563 DASSERT(AwtCheckbox::labelID != NULL); 564 CHECK_NULL(AwtCheckbox::labelID); 565 566 AwtCheckbox::groupID = 567 env->GetFieldID(cls, "group", "Ljava/awt/CheckboxGroup;"); 568 DASSERT(AwtCheckbox::groupID != NULL); 569 CHECK_NULL(AwtCheckbox::groupID); 570 571 AwtCheckbox::stateID = env->GetFieldID(cls, "state", "Z"); 572 DASSERT(AwtCheckbox::stateID != NULL); 573 574 CATCH_BAD_ALLOC; 575 } 576 577 } /* extern "C" */ 578 579 580 /************************************************************************ 581 * WCheckboxPeer native methods 582 */ 583 584 extern "C" { 585 586 /* 587 * Class: sun_awt_windows_WCheckboxPeer 588 * Method: getCheckMarkSize 589 * Signature: ()I 590 */ 591 JNIEXPORT jint JNICALL 592 Java_sun_awt_windows_WCheckboxPeer_getCheckMarkSize(JNIEnv *env, 593 jclass cls) 594 { 595 return (jint)AwtCheckbox::GetCheckSize(); 596 } 597 598 /* 599 * Class: sun_awt_windows_WCheckboxPeer 600 * Method: setState 601 * Signature: (Z)V 602 */ 603 JNIEXPORT void JNICALL 604 Java_sun_awt_windows_WCheckboxPeer_setState(JNIEnv *env, jobject self, 605 jboolean state) 606 { 607 TRY; 608 609 SetStateStruct *sss = new SetStateStruct; 610 sss->checkbox = env->NewGlobalRef(self); 611 sss->state = state; 612 613 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetState, sss); 614 // global refs and sss are deleted in _SetState() 615 616 CATCH_BAD_ALLOC; 617 } 618 619 /* 620 * Class: sun_awt_windows_WCheckboxPeer 621 * Method: setCheckboxGroup 622 * Signature: (Ljava/awt/CheckboxGroup;)V 623 */ 624 JNIEXPORT void JNICALL 625 Java_sun_awt_windows_WCheckboxPeer_setCheckboxGroup(JNIEnv *env, jobject self, 626 jobject group) 627 { 628 TRY; 629 630 jobject *jos = new jobject[2]; 631 jos[0] = env->NewGlobalRef(self); 632 jos[1] = env->NewGlobalRef(group); 633 634 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetCheckboxGroup, jos); 635 // global refs and jos are deleted in _SetLabel() 636 637 CATCH_BAD_ALLOC; 638 } 639 640 /* 641 * Class: sun_awt_windows_WCheckboxPeer 642 * Method: setLabel 643 * Signature: (Ljava/lang/String;)V 644 */ 645 JNIEXPORT void JNICALL 646 Java_sun_awt_windows_WCheckboxPeer_setLabel(JNIEnv *env, jobject self, 647 jstring label) 648 { 649 TRY; 650 651 SetLabelStruct *sls = new SetLabelStruct; 652 sls->checkbox = env->NewGlobalRef(self); 653 sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL; 654 655 AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetLabel, sls); 656 // global refs and sls are deleted in _SetLabel() 657 658 CATCH_BAD_ALLOC; 659 } 660 661 /* 662 * Class: sun_awt_windows_WCheckboxPeer 663 * Method: create 664 * Signature: (Lsun/awt/windows/WComponentPeer;)V 665 */ 666 JNIEXPORT void JNICALL 667 Java_sun_awt_windows_WCheckboxPeer_create(JNIEnv *env, jobject self, 668 jobject parent) 669 { 670 TRY; 671 672 PDATA pData; 673 JNI_CHECK_PEER_RETURN(parent); 674 AwtToolkit::CreateComponent(self, parent, 675 (AwtToolkit::ComponentFactory) 676 AwtCheckbox::Create); 677 JNI_CHECK_PEER_CREATION_RETURN(self); 678 679 #ifdef DEBUG 680 ((AwtComponent*)JNI_GET_PDATA(self))->VerifyState(); 681 #endif 682 683 CATCH_BAD_ALLOC; 684 } 685 686 } /* extern "C" */