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_MenuItem.h" 28 #include "awt_Menu.h" 29 #include "awt_MenuBar.h" 30 #include "awt_DesktopProperties.h" 31 #include <sun_awt_windows_WCheckboxMenuItemPeer.h> 32 33 // Begin -- Win32 SDK include files 34 #include <tchar.h> 35 #include <imm.h> 36 #include <ime.h> 37 // End -- Win32 SDK include files 38 39 //add for multifont menuitem 40 #include <java_awt_CheckboxMenuItem.h> 41 #include <java_awt_Toolkit.h> 42 #include <java_awt_event_InputEvent.h> 43 44 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 45 */ 46 47 /***********************************************************************/ 48 // struct for _SetLabel() method 49 struct SetLabelStruct { 50 jobject menuitem; 51 jstring label; 52 }; 53 /************************************************************************ 54 * AwtMenuItem fields 55 */ 56 57 HBITMAP AwtMenuItem::bmpCheck; 58 jobject AwtMenuItem::systemFont; 59 60 jfieldID AwtMenuItem::labelID; 61 jfieldID AwtMenuItem::enabledID; 62 jfieldID AwtMenuItem::fontID; 63 jfieldID AwtMenuItem::appContextID; 64 jfieldID AwtMenuItem::shortcutLabelID; 65 jfieldID AwtMenuItem::isCheckboxID; 66 jfieldID AwtMenuItem::stateID; 67 68 jmethodID AwtMenuItem::getDefaultFontMID; 69 70 // Added by waleed to initialize the RTL Flags 71 LANGID AwtMenuItem::m_idLang = LOWORD(GetKeyboardLayout(0)); 72 UINT AwtMenuItem::m_CodePage = 73 AwtMenuItem::LangToCodePage(AwtMenuItem::m_idLang); 74 BOOL AwtMenuItem::sm_rtl = PRIMARYLANGID(GetInputLanguage()) == LANG_ARABIC || 75 PRIMARYLANGID(GetInputLanguage()) == LANG_HEBREW; 76 BOOL AwtMenuItem::sm_rtlReadingOrder = 77 PRIMARYLANGID(GetInputLanguage()) == LANG_ARABIC; 78 79 /* 80 * This constant holds width of the default menu 81 * check-mark bitmap for default settings on XP/Vista, 82 * in pixels 83 */ 84 static const int SM_CXMENUCHECK_DEFAULT_ON_XP = 13; 85 static const int SM_CXMENUCHECK_DEFAULT_ON_VISTA = 15; 86 87 /************************************************************************ 88 * AwtMenuItem methods 89 */ 90 91 AwtMenuItem::AwtMenuItem() { 92 m_peerObject = NULL; 93 m_menuContainer = NULL; 94 m_Id = (UINT)-1; 95 m_freeId = FALSE; 96 m_isCheckbox = FALSE; 97 } 98 99 AwtMenuItem::~AwtMenuItem() 100 { 101 } 102 103 void AwtMenuItem::RemoveCmdID() 104 { 105 if (m_freeId) { 106 AwtToolkit::GetInstance().RemoveCmdID( GetID() ); 107 } 108 } 109 void AwtMenuItem::Dispose() 110 { 111 RemoveCmdID(); 112 113 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 114 if (m_peerObject != NULL) { 115 JNI_SET_DESTROYED(m_peerObject); 116 JNI_SET_PDATA(m_peerObject, NULL); 117 env->DeleteGlobalRef(m_peerObject); 118 m_peerObject = NULL; 119 } 120 121 AwtObject::Dispose(); 122 } 123 124 LPCTSTR AwtMenuItem::GetClassName() { 125 return TEXT("SunAwtMenuItem"); 126 } 127 // Convert Language ID to CodePage 128 UINT AwtMenuItem::LangToCodePage(LANGID idLang) 129 { 130 TCHAR strCodePage[MAX_ACP_STR_LEN]; 131 // use the LANGID to create a LCID 132 LCID idLocale = MAKELCID(idLang, SORT_DEFAULT); 133 // get the ANSI code page associated with this locale 134 if (GetLocaleInfo(idLocale, LOCALE_IDEFAULTANSICODEPAGE, strCodePage, sizeof(strCodePage)/sizeof(TCHAR)) > 0 ) 135 return _ttoi(strCodePage); 136 else 137 return GetACP(); 138 } 139 140 BOOL AwtMenuItem::CheckMenuCreation(JNIEnv *env, jobject self, HMENU hMenu) 141 { 142 // fix for 5088782 143 // check if CreateMenu() returns not null value and if it does - 144 // create an InternalError or OutOfMemoryError based on GetLastError(). 145 // This error is set to createError field of WObjectPeer and then 146 // checked and thrown in WMenuPeer or WMenuItemPeer constructor. We 147 // can't throw an error here because this code is invoked on Toolkit thread 148 // return TRUE if menu is created successfully, FALSE otherwise 149 if (hMenu == NULL) 150 { 151 DWORD dw = GetLastError(); 152 jobject createError = NULL; 153 if (dw == ERROR_OUTOFMEMORY) 154 { 155 jstring errorMsg = JNU_NewStringPlatform(env, L"too many menu handles"); 156 if (errorMsg == NULL) { 157 throw std::bad_alloc(); 158 } 159 createError = JNU_NewObjectByName(env, "java/lang/OutOfMemoryError", 160 "(Ljava/lang/String;)V", 161 errorMsg); 162 env->DeleteLocalRef(errorMsg); 163 } 164 else 165 { 166 TCHAR *buf; 167 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 168 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 169 (LPTSTR)&buf, 0, NULL); 170 jstring s = JNU_NewStringPlatform(env, buf); 171 if (s == NULL) { 172 throw std::bad_alloc(); 173 } 174 createError = JNU_NewObjectByName(env, "java/lang/InternalError", 175 "(Ljava/lang/String;)V", s); 176 LocalFree(buf); 177 env->DeleteLocalRef(s); 178 } 179 if (createError == NULL) { 180 throw std::bad_alloc(); 181 } 182 env->SetObjectField(self, AwtObject::createErrorID, createError); 183 env->DeleteLocalRef(createError); 184 return FALSE; 185 } 186 return TRUE; 187 } 188 189 /* 190 * Link the C++, Java peer together 191 */ 192 void AwtMenuItem::LinkObjects(JNIEnv *env, jobject peer) 193 { 194 m_peerObject = env->NewGlobalRef(peer); 195 JNI_SET_PDATA(peer, this); 196 } 197 198 AwtMenuItem* AwtMenuItem::Create(jobject peer, jobject menuPeer) 199 { 200 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 201 202 jobject target = NULL; 203 AwtMenuItem* item = NULL; 204 205 try { 206 if (env->EnsureLocalCapacity(1) < 0) { 207 return NULL; 208 } 209 PDATA pData; 210 JNI_CHECK_PEER_RETURN_NULL(menuPeer); 211 212 /* target is a java.awt.MenuItem */ 213 target = env->GetObjectField(peer, AwtObject::targetID); 214 215 AwtMenu* menu = (AwtMenu *)pData; 216 item = new AwtMenuItem(); 217 jboolean isCheckbox = 218 (jboolean)env->GetBooleanField(peer, AwtMenuItem::isCheckboxID); 219 if (isCheckbox) { 220 item->SetCheckbox(); 221 } 222 223 item->LinkObjects(env, peer); 224 item->SetMenuContainer(menu); 225 item->SetNewID(); 226 menu->AddItem(item); 227 } catch (...) { 228 env->DeleteLocalRef(target); 229 throw; 230 } 231 232 env->DeleteLocalRef(target); 233 return item; 234 } 235 236 MsgRouting AwtMenuItem::WmNotify(UINT notifyCode) 237 { 238 return mrDoDefault; 239 } 240 241 // This function returns a local reference 242 jobject 243 AwtMenuItem::GetFont(JNIEnv *env) 244 { 245 jobject self = GetPeer(env); 246 jobject target = env->GetObjectField(self, AwtObject::targetID); 247 jobject font = JNU_CallMethodByName(env, 0, target, "getFont_NoClientCode", "()Ljava/awt/Font;").l; 248 env->DeleteLocalRef(target); 249 if (env->ExceptionCheck()) { 250 throw std::bad_alloc(); 251 } 252 253 if (font == NULL) { 254 font = env->NewLocalRef(GetDefaultFont(env)); 255 if (env->ExceptionCheck()) { 256 throw std::bad_alloc(); 257 } 258 } 259 260 return font; 261 } 262 263 jobject 264 AwtMenuItem::GetDefaultFont(JNIEnv *env) { 265 if (AwtMenuItem::systemFont == NULL) { 266 jclass cls = env->FindClass("sun/awt/windows/WMenuItemPeer"); 267 if (cls == NULL) { 268 throw std::bad_alloc(); 269 } 270 271 AwtMenuItem::systemFont = 272 env->CallStaticObjectMethod(cls, AwtMenuItem::getDefaultFontMID); 273 if (env->ExceptionCheck()) { 274 env->DeleteLocalRef(cls); 275 throw std::bad_alloc(); 276 } 277 278 AwtMenuItem::systemFont = env->NewGlobalRef(AwtMenuItem::systemFont); 279 if (systemFont == NULL) { 280 env->DeleteLocalRef(cls); 281 throw std::bad_alloc(); 282 } 283 } 284 return AwtMenuItem::systemFont; 285 } 286 287 void 288 AwtMenuItem::DrawSelf(DRAWITEMSTRUCT& drawInfo) 289 { 290 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 291 if (env->EnsureLocalCapacity(4) < 0) { 292 return; 293 } 294 295 // self is sun.awt.windows.WMenuItemPeer 296 jobject self = GetPeer(env); 297 298 // target is java.awt.MenuItem 299 jobject target = env->GetObjectField(self, AwtObject::targetID); 300 301 HDC hDC = drawInfo.hDC; 302 RECT rect = drawInfo.rcItem; 303 RECT textRect = rect; 304 SIZE size; 305 306 DWORD crBack,crText; 307 HBRUSH hbrBack; 308 309 jobject font; 310 try { 311 font = GetFont(env); 312 } catch (std::bad_alloc&) { 313 env->DeleteLocalRef(target); 314 throw; 315 } 316 317 jstring text = GetJavaString(env); 318 if (env->ExceptionCheck()) { 319 env->DeleteLocalRef(target); 320 throw std::bad_alloc(); 321 } 322 size = AwtFont::getMFStringSize(hDC, font, text); 323 324 /* 4700350: If the font size is taller than the menubar, change to the 325 * default font. Otherwise, menu text is painted over the title bar and 326 * client area. -bchristi 327 */ 328 if (IsTopMenu() && size.cy > ::GetSystemMetrics(SM_CYMENU)) { 329 env->DeleteLocalRef(font); 330 try { 331 font = env->NewLocalRef(GetDefaultFont(env)); 332 } catch (std::bad_alloc&) { 333 env->DeleteLocalRef(target); 334 env->DeleteLocalRef(text); 335 throw; 336 } 337 size = AwtFont::getMFStringSize(hDC, font, text); 338 } 339 340 /* Fix for bug 4257944 by ssi@sparc.spb.su 341 * check state of the parent 342 */ 343 AwtMenu* menu = GetMenuContainer(); 344 DASSERT(menu != NULL && GetID() >= 0); 345 346 //Check whether the MenuItem is disabled. 347 BOOL bEnabled = (jboolean)env->GetBooleanField(target, 348 AwtMenuItem::enabledID); 349 if (menu != NULL) { 350 bEnabled = bEnabled && !menu->IsDisabledAndPopup(); 351 } 352 353 if ((drawInfo.itemState) & (ODS_SELECTED)) { 354 // Set background and text colors for selected item 355 crBack = ::GetSysColor (COLOR_HIGHLIGHT); 356 // Disabled text must be drawn in gray. 357 crText = ::GetSysColor(bEnabled? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT); 358 } else { 359 // COLOR_MENUBAR is only defined on WindowsXP. Our binaries are 360 // built on NT, hence the below ifdef. 361 362 #ifndef COLOR_MENUBAR 363 #define COLOR_MENUBAR 30 364 #endif 365 // Set background and text colors for unselected item 366 if (IS_WINXP && IsTopMenu() && AwtDesktopProperties::IsXPStyle()) { 367 crBack = ::GetSysColor (COLOR_MENUBAR); 368 } else { 369 crBack = ::GetSysColor (COLOR_MENU); 370 } 371 // Disabled text must be drawn in gray. 372 crText = ::GetSysColor (bEnabled ? COLOR_MENUTEXT : COLOR_GRAYTEXT); 373 } 374 375 // Fill item rectangle with background color 376 hbrBack = ::CreateSolidBrush (crBack); 377 DASSERT(hbrBack); 378 VERIFY(::FillRect (hDC, &rect, hbrBack)); 379 VERIFY(::DeleteObject (hbrBack)); 380 381 // Set current background and text colors 382 ::SetBkColor (hDC, crBack); 383 ::SetTextColor (hDC, crText); 384 385 int nOldBkMode = ::SetBkMode(hDC, OPAQUE); 386 DASSERT(nOldBkMode != 0); 387 388 //draw check mark 389 int checkWidth = ::GetSystemMetrics(SM_CXMENUCHECK); 390 // Workaround for CR#6401956 391 if (IS_WINVISTA) { 392 AdjustCheckWidth(checkWidth); 393 } 394 395 if (IsCheckbox()) { 396 // means that target is a java.awt.CheckboxMenuItem 397 jboolean state = 398 (jboolean)env->GetBooleanField(target, AwtMenuItem::stateID); 399 if (state) { 400 DASSERT(drawInfo.itemState & ODS_CHECKED); 401 RECT checkRect; 402 ::CopyRect(&checkRect, &textRect); 403 if (GetRTL()) 404 checkRect.left = checkRect.right - checkWidth; 405 else 406 checkRect.right = checkRect.left + checkWidth; 407 408 DrawCheck(hDC, checkRect); 409 } 410 } 411 412 ::SetBkMode(hDC, TRANSPARENT); 413 int x = 0; 414 //draw string 415 if (!IsTopMenu()){ 416 textRect.left += checkWidth; 417 x = (GetRTL()) ? textRect.right - checkWidth - size.cx : textRect.left; 418 } else { 419 x = textRect.left = (textRect.left + textRect.right - size.cx) / 2; 420 } 421 422 int y = (textRect.top+textRect.bottom-size.cy)/2; 423 424 // Text must be drawn in emboss if the Menu is disabled and not selected. 425 BOOL bEmboss = !bEnabled && !(drawInfo.itemState & ODS_SELECTED); 426 if (bEmboss) { 427 ::SetTextColor(hDC, GetSysColor(COLOR_BTNHILIGHT)); 428 AwtFont::drawMFString(hDC, font, text, x + 1, y + 1, GetCodePage()); 429 ::SetTextColor(hDC, GetSysColor(COLOR_BTNSHADOW)); 430 } 431 AwtFont::drawMFString(hDC, font, text, x, y, GetCodePage()); 432 433 jstring shortcutLabel = 434 (jstring)env->GetObjectField(self, AwtMenuItem::shortcutLabelID); 435 if (!IsTopMenu() && shortcutLabel != NULL) { 436 UINT oldAlign = 0; 437 if (GetRTL()){ 438 oldAlign = ::SetTextAlign(hDC, TA_LEFT); 439 AwtFont::drawMFString(hDC, font, shortcutLabel, textRect.left, y, 440 GetCodePage()); 441 } else { 442 oldAlign = ::SetTextAlign(hDC, TA_RIGHT); 443 AwtFont::drawMFString(hDC, font, shortcutLabel, 444 textRect.right - checkWidth, y, 445 GetCodePage()); 446 } 447 448 ::SetTextAlign(hDC, oldAlign); 449 } 450 451 VERIFY(::SetBkMode(hDC,nOldBkMode)); 452 453 env->DeleteLocalRef(target); 454 env->DeleteLocalRef(text); 455 env->DeleteLocalRef(font); 456 env->DeleteLocalRef(shortcutLabel); 457 } 458 459 /* 460 * This function helps us to prevent check-mark's 461 * distortion appeared due to changing of default 462 * settings on Vista 463 */ 464 void AwtMenuItem::AdjustCheckWidth(int& checkWidth) 465 { 466 if (checkWidth == SM_CXMENUCHECK_DEFAULT_ON_VISTA) { 467 checkWidth = SM_CXMENUCHECK_DEFAULT_ON_XP; 468 } 469 } 470 471 void AwtMenuItem::DrawItem(DRAWITEMSTRUCT& drawInfo) 472 { 473 DASSERT(drawInfo.CtlType == ODT_MENU); 474 475 if (drawInfo.itemID != m_Id) 476 return; 477 478 DrawSelf(drawInfo); 479 } 480 481 void AwtMenuItem::MeasureSelf(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 482 { 483 JNIEnv *env =(JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 484 if (env->EnsureLocalCapacity(4) < 0) { 485 return; 486 } 487 488 /* self is a sun.awt.windows.WMenuItemPeer */ 489 jobject self = GetPeer(env); 490 491 /* font is a java.awt.Font */ 492 jobject font = GetFont(env); 493 jstring text = GetJavaString(env); 494 if (env->ExceptionCheck()) { 495 env->DeleteLocalRef(font); 496 throw std::bad_alloc(); 497 } 498 SIZE size = AwtFont::getMFStringSize(hDC, font, text); 499 500 /* 4700350: If the font size is taller than the menubar, change to the 501 * default font. Otherwise, menu text is painted over the title bar and 502 * client area. -bchristi 503 */ 504 if (IsTopMenu() && size.cy > ::GetSystemMetrics(SM_CYMENU)) { 505 jobject defFont; 506 try { 507 defFont = GetDefaultFont(env); 508 } catch (std::bad_alloc&) { 509 env->DeleteLocalRef(text); 510 env->DeleteLocalRef(font); 511 throw; 512 } 513 env->DeleteLocalRef(font); 514 font = env->NewLocalRef(defFont); 515 size = AwtFont::getMFStringSize(hDC, font, text); 516 } 517 518 jstring fontName = 519 (jstring)JNU_CallMethodByName(env, 0,font, "getName", 520 "()Ljava/lang/String;").l; 521 if (env->ExceptionCheck()) { 522 env->DeleteLocalRef(text); 523 env->DeleteLocalRef(font); 524 throw std::bad_alloc(); 525 } 526 527 /* fontMetrics is a Hsun_awt_windows_WFontMetrics */ 528 jobject fontMetrics = GetFontMetrics(env, font); 529 if (env->ExceptionCheck()) { 530 env->DeleteLocalRef(text); 531 env->DeleteLocalRef(font); 532 env->DeleteLocalRef(fontName); 533 throw std::bad_alloc(); 534 } 535 536 // int height = env->GetIntField(fontMetrics, AwtFont::heightID); 537 int height = (jint)JNU_CallMethodByName(env, 0, fontMetrics, "getHeight", 538 "()I").i; 539 if (env->ExceptionCheck()) { 540 env->DeleteLocalRef(text); 541 env->DeleteLocalRef(font); 542 env->DeleteLocalRef(fontName); 543 env->DeleteLocalRef(fontMetrics); 544 throw std::bad_alloc(); 545 } 546 547 measureInfo.itemHeight = height; 548 measureInfo.itemHeight += measureInfo.itemHeight/3; 549 // 3 is a heuristic number 550 measureInfo.itemWidth = size.cx; 551 if (!IsTopMenu()) { 552 int checkWidth = ::GetSystemMetrics(SM_CXMENUCHECK); 553 // Workaround for CR#6401956 554 if (IS_WINVISTA) { 555 AdjustCheckWidth(checkWidth); 556 } 557 measureInfo.itemWidth += checkWidth; 558 559 // Add in shortcut width, if one exists. 560 jstring shortcutLabel = 561 (jstring)env->GetObjectField(self, AwtMenuItem::shortcutLabelID); 562 if (shortcutLabel != NULL) { 563 size = AwtFont::getMFStringSize(hDC, font, shortcutLabel); 564 measureInfo.itemWidth += size.cx + checkWidth; 565 env->DeleteLocalRef(shortcutLabel); 566 } 567 } 568 env->DeleteLocalRef(text); 569 env->DeleteLocalRef(font); 570 env->DeleteLocalRef(fontName); 571 env->DeleteLocalRef(fontMetrics); 572 } 573 574 void AwtMenuItem::MeasureItem(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 575 { 576 DASSERT(measureInfo.CtlType == ODT_MENU); 577 578 if (measureInfo.itemID != m_Id) 579 return; 580 581 MeasureSelf(hDC, measureInfo); 582 } 583 584 jobject AwtMenuItem::GetFontMetrics(JNIEnv *env, jobject font) 585 { 586 static jobject toolkit = NULL; 587 if (toolkit == NULL) { 588 if (env->PushLocalFrame(2) < 0) 589 return NULL; 590 jclass cls = env->FindClass("java/awt/Toolkit"); 591 CHECK_NULL_RETURN(cls, NULL); 592 jobject toolkitLocal = 593 env->CallStaticObjectMethod(cls, AwtToolkit::getDefaultToolkitMID); 594 env->DeleteLocalRef(cls); 595 CHECK_NULL_RETURN(toolkitLocal, NULL); 596 toolkit = env->NewGlobalRef(toolkitLocal); 597 env->DeleteLocalRef(toolkitLocal); 598 CHECK_NULL_RETURN(toolkit, NULL); 599 env->PopLocalFrame(0); 600 } 601 /* 602 JNU_PrintClass(env, "toolkit", toolkit); 603 JNU_PrintClass(env, "font", font); 604 605 jclass cls = env->FindClass("java/awt/Toolkit"); 606 jmethodID mid = env->GetMethodID(cls, "getFontMetrics", 607 "(Ljava/awt/Font;)Ljava/awt/FontMetrics;"); 608 jstring fontName = 609 (jstring)JNU_CallMethodByName(env, 0,font, "getName", 610 "()Ljava/lang/String;").l; 611 JNU_PrintString(env, "font name", fontName); 612 613 fprintf(stderr, "mid: %x\n", mid); 614 fprintf(stderr, "cached mid: %x\n", AwtToolkit::getFontMetricsMID); 615 DASSERT(!safe_ExceptionOccurred(env)); 616 */ 617 jobject fontMetrics = 618 env->CallObjectMethod(toolkit, AwtToolkit::getFontMetricsMID, font); 619 DASSERT(!safe_ExceptionOccurred(env)); 620 621 return fontMetrics; 622 } 623 624 BOOL AwtMenuItem::IsTopMenu() 625 { 626 return FALSE; 627 } 628 629 void AwtMenuItem::DrawCheck(HDC hDC, RECT rect) 630 { 631 if (bmpCheck == NULL) { 632 bmpCheck = ::LoadBitmap(AwtToolkit::GetInstance().GetModuleHandle(), 633 TEXT("CHECK_BITMAP")); 634 DASSERT(bmpCheck != NULL); 635 } 636 637 #define BM_SIZE 26 /* height and width of check.bmp */ 638 639 // Square the rectangle, so the check is proportional. 640 int width = rect.right - rect.left; 641 int diff = max(rect.bottom - rect.top - width, 0) ; 642 int bottom = diff / 2; 643 rect.bottom -= bottom; 644 rect.top += diff - bottom; 645 646 HDC hdcBitmap = ::CreateCompatibleDC(hDC); 647 DASSERT(hdcBitmap != NULL); 648 HBITMAP hbmSave = (HBITMAP)::SelectObject(hdcBitmap, bmpCheck); 649 VERIFY(::StretchBlt(hDC, rect.left, rect.top, 650 rect.right - rect.left, rect.bottom - rect.top, 651 hdcBitmap, 0, 0, BM_SIZE, BM_SIZE, SRCCOPY)); 652 ::SelectObject(hdcBitmap, hbmSave); 653 VERIFY(::DeleteDC(hdcBitmap)); 654 } 655 656 void AwtMenuItem::DoCommand() 657 { 658 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 659 660 // peer is sun.awt.windows.WMenuItemPeer 661 jobject peer = GetPeer(env); 662 663 if (IsCheckbox()) { 664 UINT nState = ::GetMenuState(GetMenuContainer()->GetHMenu(), 665 GetID(), MF_BYCOMMAND); 666 DASSERT(nState != 0xFFFFFFFF); 667 DoCallback("handleAction", "(Z)V", ((nState & MF_CHECKED) == 0)); 668 } else { 669 DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0), 670 (jint)AwtComponent::GetActionModifiers()); 671 } 672 } 673 674 void AwtMenuItem::SetLabel(LPCTSTR sb) 675 { 676 AwtMenu* menu = GetMenuContainer(); 677 /* Fix for bug 4257944 by ssi@sparc.spb.su 678 * check parent 679 */ 680 if (menu == NULL) return; 681 DASSERT(menu != NULL && GetID() >= 0); 682 683 /* 684 * SetMenuItemInfo is replaced by this code for fix bug 4261935 685 */ 686 HMENU hMenu = menu->GetHMenu(); 687 MENUITEMINFO mii, mii1; 688 689 // get full information about menu item 690 memset(&mii, 0, sizeof(MENUITEMINFO)); 691 mii.cbSize = sizeof(MENUITEMINFO); 692 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID 693 | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; 694 695 ::GetMenuItemInfo(hMenu, GetID(), FALSE, &mii); 696 697 mii.fType = MFT_OWNERDRAW; 698 mii.dwTypeData = (LPTSTR)(*sb); 699 700 // find index by menu item id 701 int nMenuItemCount = ::GetMenuItemCount(hMenu); 702 int idx; 703 for (idx = 0; (idx < nMenuItemCount); idx++) { 704 memset(&mii1, 0, sizeof(MENUITEMINFO)); 705 mii1.cbSize = sizeof mii1; 706 mii1.fMask = MIIM_ID; 707 ::GetMenuItemInfo(hMenu, idx, TRUE, &mii1); 708 if (mii.wID == mii1.wID) break; 709 } 710 711 ::RemoveMenu(hMenu, idx, MF_BYPOSITION); 712 ::InsertMenuItem(hMenu, idx, TRUE, &mii); 713 714 RedrawMenuBar(); 715 } 716 717 void AwtMenuItem::Enable(BOOL isEnabled) 718 { 719 AwtMenu* menu = GetMenuContainer(); 720 /* Fix for bug 4257944 by ssi@sparc.spb.su 721 * check state of the parent 722 */ 723 if (menu == NULL) return; 724 isEnabled = isEnabled && !menu->IsDisabledAndPopup(); 725 DASSERT(menu != NULL && GetID() >= 0); 726 VERIFY(::EnableMenuItem(menu->GetHMenu(), GetID(), 727 MF_BYCOMMAND | (isEnabled ? MF_ENABLED : MF_GRAYED)) 728 != 0xFFFFFFFF); 729 730 RedrawMenuBar(); 731 } 732 733 void AwtMenuItem::SetState(BOOL isChecked) 734 { 735 AwtMenu* menu = GetMenuContainer(); 736 /* Fix for bug 4257944 by ssi@sparc.spb.su 737 * check parent 738 */ 739 if (menu == NULL) return; 740 DASSERT(menu != NULL && GetID() >= 0); 741 VERIFY(::CheckMenuItem(menu->GetHMenu(), GetID(), 742 MF_BYCOMMAND | (isChecked ? MF_CHECKED : MF_UNCHECKED)) 743 != 0xFFFFFFFF); 744 745 RedrawMenuBar(); 746 } 747 748 /** 749 * If the menu changes after the system has created the window, 750 * this function must be called to draw the changed menu bar. 751 */ 752 void AwtMenuItem::RedrawMenuBar() { 753 AwtMenu* menu = GetMenuContainer(); 754 if (menu != NULL && menu->GetMenuBar() == menu){ 755 menu->RedrawMenuBar(); 756 } 757 } 758 759 void AwtMenuItem::UpdateContainerLayout() { 760 AwtMenu* menu = GetMenuContainer(); 761 if (menu != NULL) { 762 DASSERT(menu != NULL && GetID() >= 0); 763 menu->UpdateLayout(); 764 } 765 } 766 767 LRESULT AwtMenuItem::WinThreadExecProc(ExecuteArgs * args) 768 { 769 switch( args->cmdId ) { 770 case MENUITEM_ENABLE: 771 { 772 BOOL isEnabled = (BOOL)args->param1; 773 this->Enable(isEnabled); 774 } 775 break; 776 777 case MENUITEM_SETSTATE: 778 { 779 BOOL isChecked = (BOOL)args->param1; 780 this->SetState(isChecked); 781 } 782 break; 783 784 default: 785 AwtObject::WinThreadExecProc(args); 786 break; 787 } 788 return 0L; 789 } 790 791 void AwtMenuItem::_SetLabel(void *param) { 792 if (AwtToolkit::IsMainThread()) { 793 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 794 795 SetLabelStruct *sls = (SetLabelStruct *)param; 796 jobject self = sls->menuitem; 797 jstring label = sls->label; 798 799 int badAlloc = 0; 800 AwtMenuItem *m = NULL; 801 802 PDATA pData; 803 JNI_CHECK_PEER_GOTO(self, ret); 804 m = (AwtMenuItem *)pData; 805 // if (::IsWindow(m->GetOwnerHWnd())) 806 { 807 // fix for bug 4251036 MenuItem setLabel(null/"") behaves differently 808 // under Win32 and Solaris 809 jstring empty = NULL; 810 if (JNU_IsNull(env, label)) 811 { 812 empty = JNU_NewStringPlatform(env, TEXT("")); 813 } 814 if (env->ExceptionCheck()) { 815 badAlloc = 1; 816 goto ret; 817 } 818 LPCTSTR labelPtr; 819 if (empty != NULL) 820 { 821 labelPtr = JNU_GetStringPlatformChars(env, empty, 0); 822 } 823 else 824 { 825 labelPtr = JNU_GetStringPlatformChars(env, label, 0); 826 } 827 if (labelPtr == NULL) 828 { 829 badAlloc = 1; 830 } 831 else 832 { 833 DASSERT(!IsBadStringPtr(labelPtr, 20)); 834 m->SetLabel(labelPtr); 835 if (empty != NULL) 836 { 837 JNU_ReleaseStringPlatformChars(env, empty, labelPtr); 838 } 839 else 840 { 841 JNU_ReleaseStringPlatformChars(env, label, labelPtr); 842 } 843 } 844 if (empty != NULL) 845 { 846 env->DeleteLocalRef(empty); 847 } 848 } 849 850 ret: 851 env->DeleteGlobalRef(self); 852 if (label != NULL) 853 { 854 env->DeleteGlobalRef(label); 855 } 856 857 delete sls; 858 859 if (badAlloc) 860 { 861 throw std::bad_alloc(); 862 } 863 } else { 864 AwtToolkit::GetInstance().InvokeFunction(AwtMenuItem::_SetLabel, param); 865 } 866 } 867 868 void AwtMenuItem::_UpdateLayout(void *param) 869 { 870 if (AwtToolkit::IsMainThread()) { 871 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 872 873 jobject self = (jobject)param; 874 875 AwtMenuItem *m = NULL; 876 877 PDATA pData; 878 JNI_CHECK_PEER_GOTO(self, ret); 879 880 m = (AwtMenuItem *)pData; 881 882 m->UpdateContainerLayout(); 883 ret: 884 env->DeleteGlobalRef(self); 885 } else { 886 AwtToolkit::GetInstance().InvokeFunction(AwtMenuItem::_UpdateLayout, param); 887 } 888 } 889 890 BOOL AwtMenuItem::IsSeparator() { 891 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 892 if (env->EnsureLocalCapacity(2) < 0) { 893 return FALSE; 894 } 895 jobject jitem = GetTarget(env); 896 jstring label = 897 (jstring)(env)->GetObjectField(jitem, AwtMenuItem::labelID); 898 if (label == NULL) { 899 env->DeleteLocalRef(label); 900 env->DeleteLocalRef(jitem); 901 return FALSE; //separator must has '-' as label. 902 } 903 LPCWSTR labelW = JNU_GetStringPlatformChars(env, label, NULL); 904 BOOL isSeparator = (labelW && (wcscmp(labelW, L"-") == 0)); 905 JNU_ReleaseStringPlatformChars(env, label, labelW); 906 907 env->DeleteLocalRef(label); 908 env->DeleteLocalRef(jitem); 909 910 return isSeparator; 911 } 912 913 /************************************************************************ 914 * MenuComponent native methods 915 */ 916 917 extern "C" { 918 919 JNIEXPORT void JNICALL 920 Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jclass cls) 921 { 922 TRY; 923 924 AwtMenuItem::fontID = env->GetFieldID(cls, "font", "Ljava/awt/Font;"); 925 CHECK_NULL(AwtMenuItem::fontID); 926 AwtMenuItem::appContextID = env->GetFieldID(cls, "appContext", "Lsun/awt/AppContext;"); 927 928 CATCH_BAD_ALLOC; 929 } 930 931 } /* extern "C" */ 932 933 934 /************************************************************************ 935 * MenuItem native methods 936 */ 937 938 extern "C" { 939 940 JNIEXPORT void JNICALL 941 Java_java_awt_MenuItem_initIDs(JNIEnv *env, jclass cls) 942 { 943 TRY; 944 945 AwtMenuItem::labelID = env->GetFieldID(cls, "label", "Ljava/lang/String;"); 946 CHECK_NULL(AwtMenuItem::labelID); 947 AwtMenuItem::enabledID = env->GetFieldID(cls, "enabled", "Z"); 948 949 CATCH_BAD_ALLOC; 950 } 951 952 } /* extern "C" */ 953 954 955 /************************************************************************ 956 * CheckboxMenuItem fields 957 */ 958 959 extern "C" { 960 961 JNIEXPORT void JNICALL 962 Java_java_awt_CheckboxMenuItem_initIDs(JNIEnv *env, jclass cls) 963 { 964 TRY; 965 966 AwtMenuItem::stateID = env->GetFieldID(cls, "state", "Z"); 967 968 CATCH_BAD_ALLOC; 969 } 970 971 } /* extern "C" */ 972 973 974 /************************************************************************ 975 * WMenuItemPeer native methods 976 */ 977 978 extern "C" { 979 980 /* 981 * Class: sun_awt_windows_WMenuItemPeer 982 * Method: initIDs 983 * Signature: ()V 984 */ 985 JNIEXPORT void JNICALL 986 Java_sun_awt_windows_WMenuItemPeer_initIDs(JNIEnv *env, jclass cls) 987 { 988 TRY; 989 990 AwtMenuItem::isCheckboxID = env->GetFieldID(cls, "isCheckbox", "Z"); 991 CHECK_NULL(AwtMenuItem::isCheckboxID); 992 AwtMenuItem::shortcutLabelID = env->GetFieldID(cls, "shortcutLabel", 993 "Ljava/lang/String;"); 994 CHECK_NULL(AwtMenuItem::shortcutLabelID); 995 AwtMenuItem::getDefaultFontMID = 996 env->GetStaticMethodID(cls, "getDefaultFont", "()Ljava/awt/Font;"); 997 998 CATCH_BAD_ALLOC; 999 } 1000 1001 /* 1002 * Class: sun_awt_windows_WMenuItemPeer 1003 * Method: _setLabel 1004 * Signature: (Ljava/lang/String;)V 1005 */ 1006 JNIEXPORT void JNICALL 1007 Java_sun_awt_windows_WMenuItemPeer__1setLabel(JNIEnv *env, jobject self, 1008 jstring label) 1009 { 1010 TRY; 1011 1012 SetLabelStruct *sls = new SetLabelStruct; 1013 sls->menuitem = env->NewGlobalRef(self); 1014 sls->label = (label == NULL) ? NULL : (jstring)env->NewGlobalRef(label); 1015 1016 AwtToolkit::GetInstance().SyncCall(AwtMenuItem::_SetLabel, sls); 1017 // global refs and sls are deleted in _SetLabel 1018 1019 CATCH_BAD_ALLOC; 1020 } 1021 1022 /* 1023 * Class: sun_awt_windows_WMenuItemPeer 1024 * Method: _setFont 1025 * Signature: (Ljava/awt/Font;)V 1026 */ 1027 JNIEXPORT void JNICALL 1028 Java_sun_awt_windows_WMenuItemPeer__1setFont(JNIEnv *env, jobject self, jobject) 1029 { 1030 TRY; 1031 1032 jobject selfGlobalRef = env->NewGlobalRef(self); 1033 1034 // Current implementation of AwtMenuItem get font attribute from the peer 1035 // directly, so we ignore it here, but update current menu layout. 1036 AwtToolkit::GetInstance().SyncCall(AwtMenuItem::_UpdateLayout, selfGlobalRef); 1037 // selfGlobalRef is deleted in _UpdateLayout 1038 1039 CATCH_BAD_ALLOC; 1040 } 1041 1042 /* 1043 * Class: sun_awt_windows_WMenuItemPeer 1044 * Method: create 1045 * Signature: (Lsun/awt/windows/WMenuPeer;)V 1046 */ 1047 JNIEXPORT void JNICALL 1048 Java_sun_awt_windows_WMenuItemPeer_create(JNIEnv *env, jobject self, 1049 jobject menu) 1050 { 1051 TRY; 1052 1053 JNI_CHECK_NULL_RETURN(menu, "null Menu"); 1054 AwtToolkit::CreateComponent(self, menu, 1055 (AwtToolkit::ComponentFactory) 1056 AwtMenuItem::Create); 1057 PDATA pData; 1058 JNI_CHECK_PEER_CREATION_RETURN(self); 1059 1060 CATCH_BAD_ALLOC; 1061 } 1062 1063 /* 1064 * Class: sun_awt_windows_WMenuItemPeer 1065 * Method: enable 1066 * Signature: (Z)V 1067 */ 1068 JNIEXPORT void JNICALL 1069 Java_sun_awt_windows_WMenuItemPeer_enable(JNIEnv *env, jobject self, 1070 jboolean on) 1071 { 1072 TRY; 1073 1074 PDATA pData; 1075 JNI_CHECK_PEER_RETURN(self); 1076 AwtObject::WinThreadExec(self, AwtMenuItem::MENUITEM_ENABLE, (LPARAM)on ); 1077 1078 CATCH_BAD_ALLOC; 1079 } 1080 1081 /* 1082 * Class: sun_awt_windows_WMenuItemPeer 1083 * Method: _dispose 1084 * Signature: ()V 1085 */ 1086 JNIEXPORT void JNICALL 1087 Java_sun_awt_windows_WMenuItemPeer__1dispose(JNIEnv *env, jobject self) 1088 { 1089 TRY_NO_HANG; 1090 1091 AwtObject::_Dispose(self); 1092 1093 CATCH_BAD_ALLOC; 1094 } 1095 1096 } /* extern "C" */ 1097 1098 /************************************************************************ 1099 * WCheckboxMenuItemPeer native methods 1100 */ 1101 1102 extern "C" { 1103 1104 /* 1105 * Class: sun_awt_windows_WCheckboxMenuItemPeer 1106 * Method: setState 1107 * Signature: (Z)V 1108 */ 1109 JNIEXPORT void JNICALL 1110 Java_sun_awt_windows_WCheckboxMenuItemPeer_setState(JNIEnv *env, jobject self, 1111 jboolean on) 1112 { 1113 TRY; 1114 1115 PDATA pData; 1116 JNI_CHECK_PEER_RETURN(self); 1117 AwtObject::WinThreadExec(self, AwtMenuItem::MENUITEM_SETSTATE, (LPARAM)on); 1118 1119 CATCH_BAD_ALLOC; 1120 } 1121 1122 } /* extern "C" */