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