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