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_Menu.h" 27#include "awt_MenuBar.h" 28#include "awt_Frame.h" 29#include <java_awt_Menu.h> 30#include <sun_awt_windows_WMenuPeer.h> 31#include <java_awt_MenuBar.h> 32#include <sun_awt_windows_WMenuBarPeer.h> 33 34/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 35 */ 36 37/***********************************************************************/ 38// struct for _DelItem() method 39struct DelItemStruct { 40 jobject menuitem; 41 jint index; 42}; 43 44/************************************************************************ 45 * AwtMenuItem fields 46 */ 47 48jmethodID AwtMenu::countItemsMID; 49jmethodID AwtMenu::getItemMID; 50 51 52/************************************************************************ 53 * AwtMenuItem methods 54 */ 55 56AwtMenu::AwtMenu() { 57 m_hMenu = NULL; 58} 59 60AwtMenu::~AwtMenu() 61{ 62} 63 64void AwtMenu::Dispose() 65{ 66 if (m_hMenu != NULL) { 67 /* 68 * Don't verify -- may not be a valid anymore if its window 69 * was disposed of first. 70 */ 71 ::DestroyMenu(m_hMenu); 72 m_hMenu = NULL; 73 } 74 AwtMenuItem::Dispose(); 75} 76 77LPCTSTR AwtMenu::GetClassName() { 78 return TEXT("SunAwtMenu"); 79} 80 81/* Create a new AwtMenu object and menu. */ 82AwtMenu* AwtMenu::Create(jobject self, jobject parent) 83{ 84 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 85 86 jobject target = NULL; 87 AwtMenu* menu = NULL; 88 89 try { 90 if (env->EnsureLocalCapacity(1) < 0) { 91 return NULL; 92 } 93 94 JNI_CHECK_NULL_GOTO(parent, "peer", done); 95 AwtMenu* parentMenu = (AwtMenu*) JNI_GET_PDATA(parent); 96 97 target = env->GetObjectField(self, AwtObject::targetID); 98 JNI_CHECK_NULL_GOTO(target, "null target", done); 99 100 menu = new AwtMenu(); 101 102 SetLastError(0); 103 HMENU hMenu = ::CreateMenu(); 104 // fix for 5088782 105 if (!CheckMenuCreation(env, self, hMenu)) 106 { 107 env->DeleteLocalRef(target); 108 return NULL; 109 } 110 111 menu->SetHMenu(hMenu); 112 113 menu->LinkObjects(env, self); 114 menu->SetMenuContainer(parentMenu); 115 if (parentMenu != NULL) { 116 parentMenu->AddItem(menu); 117 } 118 } catch (...) { 119 env->DeleteLocalRef(target); 120 throw; 121 } 122 123done: 124 if (target != NULL) { 125 env->DeleteLocalRef(target); 126 } 127 128 return menu; 129} 130 131void AwtMenu::_AddSeparator(void *param) 132{ 133 if (AwtToolkit::IsMainThread()) { 134 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 135 136 jobject self = (jobject)param; 137 AwtMenu *m = NULL; 138 PDATA pData; 139 JNI_CHECK_PEER_GOTO(self, ret); 140 m = (AwtMenu *)pData; 141 m->AddSeparator(); 142ret: 143 env->DeleteGlobalRef(self); 144 } else { 145 AwtToolkit::GetInstance().InvokeFunction(AwtMenu::_AddSeparator, param); 146 } 147} 148 149void AwtMenu::_DelItem(void *param) 150{ 151 if (AwtToolkit::IsMainThread()) { 152 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 153 154 DelItemStruct *dis = (DelItemStruct*) param; 155 jobject self = dis->menuitem; 156 jint index = dis->index; 157 158 AwtMenu *m = NULL; 159 PDATA pData; 160 JNI_CHECK_PEER_GOTO(self, ret); 161 m = (AwtMenu *)pData; 162 m->DeleteItem(static_cast<UINT>(index)); 163ret: 164 env->DeleteGlobalRef(self); 165 delete dis; 166 } else { 167 AwtToolkit::GetInstance().InvokeFunction(AwtMenu::_DelItem, param); 168 } 169} 170 171void AwtMenu::UpdateLayout() 172{ 173 UpdateLayout(GetHMenu()); 174 RedrawMenuBar(); 175} 176 177void AwtMenu::UpdateLayout(const HMENU hmenu) 178{ 179 const int nMenuItemCount = ::GetMenuItemCount(hmenu); 180 static MENUITEMINFO mii; 181 for (int idx = 0; idx < nMenuItemCount; ++idx) { 182 memset(&mii, 0, sizeof(mii)); 183 mii.cbSize = sizeof(mii); 184 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID 185 | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; 186 if (::GetMenuItemInfo(hmenu, idx, TRUE, &mii)) { 187 VERIFY(::RemoveMenu(hmenu, idx, MF_BYPOSITION)); 188 VERIFY(::InsertMenuItem(hmenu, idx, TRUE, &mii)); 189 if (mii.hSubMenu != NULL) { 190 UpdateLayout(mii.hSubMenu); 191 } 192 } 193 } 194} 195 196void AwtMenu::UpdateContainerLayout() 197{ 198 AwtMenu* menu = GetMenuContainer(); 199 if (menu != NULL) { 200 menu->UpdateLayout(); 201 } else { 202 UpdateLayout(); 203 } 204} 205 206AwtMenuBar* AwtMenu::GetMenuBar() { 207 return (GetMenuContainer() == NULL) ? NULL : GetMenuContainer()->GetMenuBar(); 208} 209 210HWND AwtMenu::GetOwnerHWnd() { 211 return (GetMenuContainer() == NULL) ? NULL : GetMenuContainer()->GetOwnerHWnd(); 212} 213 214void AwtMenu::AddSeparator() { 215 VERIFY(::AppendMenu(GetHMenu(), MF_SEPARATOR, 0, 0)); 216} 217 218void AwtMenu::AddItem(AwtMenuItem* item) 219{ 220 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 221 if (env->EnsureLocalCapacity(2) < 0) { 222 return; 223 } 224 225 if (item->IsSeparator()) { 226 AddSeparator(); 227 } else { 228 /* jitem is a java.awt.MenuItem */ 229 jobject jitem = item->GetTarget(env); 230 231 jboolean enabled = 232 (jboolean)env->GetBooleanField(jitem, AwtMenuItem::enabledID); 233 234 UINT flags = MF_STRING | (enabled ? MF_ENABLED : MF_GRAYED); 235 flags |= MF_OWNERDRAW; 236 LPCTSTR itemInfo = (LPCTSTR) this; 237 238 if (_tcscmp(item->GetClassName(), TEXT("SunAwtMenu")) == 0) { 239 flags |= MF_POPUP; 240 itemInfo = (LPCTSTR) item; 241 } 242 243 VERIFY(::AppendMenu(GetHMenu(), flags, item->GetID(), itemInfo)); 244 if (GetRTL()) { 245 MENUITEMINFO mif; 246 memset(&mif, 0, sizeof(MENUITEMINFO)); 247 mif.cbSize = sizeof(MENUITEMINFO); 248 mif.fMask = MIIM_TYPE; 249 ::GetMenuItemInfo(GetHMenu(), item->GetID(), FALSE, &mif); 250 mif.fType |= MFT_RIGHTJUSTIFY | MFT_RIGHTORDER; 251 ::SetMenuItemInfo(GetHMenu(), item->GetID(), FALSE, &mif); 252 } 253 254 env->DeleteLocalRef(jitem); 255 } 256} 257 258void AwtMenu::DeleteItem(UINT index) 259{ 260 VERIFY(::RemoveMenu(GetHMenu(), index, MF_BYPOSITION)); 261} 262 263void AwtMenu::SendDrawItem(AwtMenuItem* awtMenuItem, 264 DRAWITEMSTRUCT& drawInfo) 265{ 266 awtMenuItem->DrawItem(drawInfo); 267} 268 269void AwtMenu::SendMeasureItem(AwtMenuItem* awtMenuItem, 270 HDC hDC, MEASUREITEMSTRUCT& measureInfo) 271{ 272 awtMenuItem->MeasureItem(hDC, measureInfo); 273} 274 275int AwtMenu::CountItem(jobject target) 276{ 277 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 278 jint nCount = env->CallIntMethod(target, AwtMenu::countItemsMID); 279 DASSERT(!safe_ExceptionOccurred(env)); 280 return nCount; 281} 282 283AwtMenuItem* AwtMenu::GetItem(jobject target, jint index) 284{ 285 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 286 if (env->EnsureLocalCapacity(2) < 0) { 287 return NULL; 288 } 289 jobject menuItem = env->CallObjectMethod(target, AwtMenu::getItemMID, 290 index); 291 if (!menuItem) return NULL; // menu item was removed concurrently 292 DASSERT(!safe_ExceptionOccurred(env)); 293 294 jobject wMenuItemPeer = GetPeerForTarget(env, menuItem); 295 296 PDATA pData; 297 AwtMenuItem* awtMenuItem = NULL; 298 299 JNI_CHECK_PEER_GOTO(wMenuItemPeer, done); 300 awtMenuItem = (AwtMenuItem*)pData; 301 302 done: 303 env->DeleteLocalRef(menuItem); 304 env->DeleteLocalRef(wMenuItemPeer); 305 306 return awtMenuItem; 307} 308 309void AwtMenu::DrawItems(DRAWITEMSTRUCT& drawInfo) 310{ 311 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 312 if (env->EnsureLocalCapacity(1) < 0) { 313 return; 314 } 315 /* target is a java.awt.Menu */ 316 jobject target = GetTarget(env); 317 if(!target || env->ExceptionCheck()) return; 318 int nCount = CountItem(target); 319 for (int i = 0; i < nCount && !env->ExceptionCheck(); i++) { 320 AwtMenuItem* awtMenuItem = GetItem(target, i); 321 if (awtMenuItem != NULL) { 322 SendDrawItem(awtMenuItem, drawInfo); 323 } 324 } 325 env->DeleteLocalRef(target); 326} 327 328void AwtMenu::DrawItem(DRAWITEMSTRUCT& drawInfo) 329{ 330 DASSERT(drawInfo.CtlType == ODT_MENU); 331 332 if (drawInfo.itemID == GetID()) { 333 DrawSelf(drawInfo); 334 return; 335 } 336 DrawItems(drawInfo); 337} 338 339void AwtMenu::MeasureItems(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 340{ 341 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 342 if (env->EnsureLocalCapacity(1) < 0) { 343 return; 344 } 345 /* target is a java.awt.Menu */ 346 jobject target = GetTarget(env); 347 if(!target || env->ExceptionCheck()) return; 348 int nCount = CountItem(target); 349 for (int i = 0; i < nCount && !env->ExceptionCheck(); i++) { 350 AwtMenuItem* awtMenuItem = GetItem(target, i); 351 if (awtMenuItem != NULL) { 352 SendMeasureItem(awtMenuItem, hDC, measureInfo); 353 } 354 } 355 env->DeleteLocalRef(target); 356} 357 358void AwtMenu::MeasureItem(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 359{ 360 DASSERT(measureInfo.CtlType == ODT_MENU); 361 362 if (measureInfo.itemID == GetID()) { 363 MeasureSelf(hDC, measureInfo); 364 return; 365 } 366 367 MeasureItems(hDC, measureInfo); 368} 369 370BOOL AwtMenu::IsTopMenu() 371{ 372 return (GetMenuBar() == GetMenuContainer()); 373} 374 375/************************************************************************ 376 * WMenuPeer native methods 377 */ 378 379extern "C" { 380 381JNIEXPORT void JNICALL 382Java_java_awt_Menu_initIDs(JNIEnv *env, jclass cls) 383{ 384 TRY; 385 386 AwtMenu::countItemsMID = env->GetMethodID(cls, "countItemsImpl", "()I"); 387 DASSERT(AwtMenu::countItemsMID != NULL); 388 CHECK_NULL(AwtMenu::countItemsMID); 389 390 AwtMenu::getItemMID = env->GetMethodID(cls, "getItemImpl", 391 "(I)Ljava/awt/MenuItem;"); 392 DASSERT(AwtMenu::getItemMID != NULL); 393 394 CATCH_BAD_ALLOC; 395} 396 397} /* extern "C" */ 398 399 400/************************************************************************ 401 * WMenuPeer native methods 402 */ 403 404extern "C" { 405 406/* 407 * Class: sun_awt_windows_WMenuPeer 408 * Method: addSeparator 409 * Signature: ()V 410 */ 411JNIEXPORT void JNICALL 412Java_sun_awt_windows_WMenuPeer_addSeparator(JNIEnv *env, jobject self) 413{ 414 TRY; 415 416 jobject selfGlobalRef = env->NewGlobalRef(self); 417 418 AwtToolkit::GetInstance().SyncCall(AwtMenu::_AddSeparator, selfGlobalRef); 419 // selfGlobalRef is deleted in _AddSeparator 420 421 CATCH_BAD_ALLOC; 422} 423 424/* 425 * Class: sun_awt_windows_WMenuPeer 426 * Method: delItem 427 * Signature: (I)V 428 */ 429JNIEXPORT void JNICALL 430Java_sun_awt_windows_WMenuPeer_delItem(JNIEnv *env, jobject self, 431 jint index) 432{ 433 TRY; 434 435 DelItemStruct *dis = new DelItemStruct; 436 dis->menuitem = env->NewGlobalRef(self); 437 dis->index = index; 438 439 AwtToolkit::GetInstance().SyncCall(AwtMenu::_DelItem, dis); 440 // global refs and dis are deleted in _DelItem 441 442 CATCH_BAD_ALLOC; 443} 444 445/* 446 * Class: sun_awt_windows_WMenuPeer 447 * Method: createMenu 448 * Signature: (Lsun/awt/windows/WMenuBarPeer;)V 449 */ 450JNIEXPORT void JNICALL 451Java_sun_awt_windows_WMenuPeer_createMenu(JNIEnv *env, jobject self, 452 jobject menuBar) 453{ 454 TRY; 455 456 AwtToolkit::CreateComponent(self, menuBar, 457 (AwtToolkit::ComponentFactory)AwtMenu::Create); 458 459 CATCH_BAD_ALLOC; 460} 461 462/* 463 * Class: sun_awt_windows_WMenuPeer 464 * Method: createSubMenu 465 * Signature: (Lsun/awt/windows/WMenuPeer;)V 466 */ 467JNIEXPORT void JNICALL 468Java_sun_awt_windows_WMenuPeer_createSubMenu(JNIEnv *env, jobject self, 469 jobject menu) 470{ 471 TRY; 472 473 AwtToolkit::CreateComponent(self, menu, 474 (AwtToolkit::ComponentFactory)AwtMenu::Create); 475 476 CATCH_BAD_ALLOC; 477} 478 479} /* extern "C" */ 480