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