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