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