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