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 DASSERT(!safe_ExceptionOccurred(env)); 243 244 jobject wMenuItemPeer = GetPeerForTarget(env, menuItem); 245 246 PDATA pData; 247 AwtMenuItem* awtMenuItem = NULL; 248 249 JNI_CHECK_PEER_GOTO(wMenuItemPeer, done); 250 awtMenuItem = (AwtMenuItem*)pData; 251 252 done: 253 env->DeleteLocalRef(menuItem); 254 env->DeleteLocalRef(wMenuItemPeer); 255 256 return awtMenuItem; 257 } 258 259 void AwtMenu::DrawItems(DRAWITEMSTRUCT& drawInfo) 260 { 261 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 262 if (env->EnsureLocalCapacity(1) < 0) { 263 return; 264 } 265 /* target is a java.awt.Menu */ 266 jobject target = GetTarget(env); 267 268 int nCount = CountItem(target); 269 for (int i = 0; i < nCount; i++) { 270 AwtMenuItem* awtMenuItem = GetItem(target, i); 271 if (awtMenuItem != NULL) { 272 SendDrawItem(awtMenuItem, drawInfo); 273 } 274 } 275 env->DeleteLocalRef(target); 276 } 277 278 void AwtMenu::DrawItem(DRAWITEMSTRUCT& drawInfo) 279 { 280 DASSERT(drawInfo.CtlType == ODT_MENU); 281 282 if (drawInfo.itemID == GetID()) { 283 DrawSelf(drawInfo); 284 return; 285 } 286 DrawItems(drawInfo); 287 } 288 289 void AwtMenu::MeasureItems(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 290 { 291 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 292 if (env->EnsureLocalCapacity(1) < 0) { 293 return; 294 } 295 /* target is a java.awt.Menu */ 296 jobject target = GetTarget(env); 297 int nCount = CountItem(target); 298 for (int i = 0; i < nCount; i++) { 299 AwtMenuItem* awtMenuItem = GetItem(target, i); 300 if (awtMenuItem != NULL) { 301 SendMeasureItem(awtMenuItem, hDC, measureInfo); 302 } 303 } 304 env->DeleteLocalRef(target); 305 } 306 307 void AwtMenu::MeasureItem(HDC hDC, MEASUREITEMSTRUCT& measureInfo) 308 { 309 DASSERT(measureInfo.CtlType == ODT_MENU); 310 311 if (measureInfo.itemID == GetID()) { 312 MeasureSelf(hDC, measureInfo); 313 return; 314 } 315 316 MeasureItems(hDC, measureInfo); 317 } 318 319 BOOL AwtMenu::IsTopMenu() 320 { 321 return (GetMenuBar() == GetMenuContainer()); 322 } 323 324 LRESULT AwtMenu::WinThreadExecProc(ExecuteArgs * args) 325 { 326 switch( args->cmdId ) { 327 case MENU_ADDSEPARATOR: 328 this->AddSeparator(); 329 break; 330 331 case MENU_DELITEM: 332 this->DeleteItem(static_cast<UINT>(args->param1)); 333 break; 334 335 default: 336 AwtMenuItem::WinThreadExecProc(args); 337 break; 338 } 339 return 0L; 340 } 341 342 /************************************************************************ 343 * WMenuPeer native methods 344 */ 345 346 extern "C" { 347 348 JNIEXPORT void JNICALL 349 Java_java_awt_Menu_initIDs(JNIEnv *env, jclass cls) 350 { 351 TRY; 352 353 AwtMenu::countItemsMID = env->GetMethodID(cls, "countItemsImpl", "()I"); 354 DASSERT(AwtMenu::countItemsMID != NULL); 355 CHECK_NULL(AwtMenu::countItemsMID); 356 357 AwtMenu::getItemMID = env->GetMethodID(cls, "getItemImpl", 358 "(I)Ljava/awt/MenuItem;"); 359 DASSERT(AwtMenu::getItemMID != NULL); 360 361 CATCH_BAD_ALLOC; 362 } 363 364 } /* extern "C" */ 365 366 367 /************************************************************************ 368 * WMenuPeer native methods 369 */ 370 371 extern "C" { 372 373 /* 374 * Class: sun_awt_windows_WMenuPeer 375 * Method: addSeparator 376 * Signature: ()V 377 */ 378 JNIEXPORT void JNICALL 379 Java_sun_awt_windows_WMenuPeer_addSeparator(JNIEnv *env, jobject self) 380 { 381 TRY; 382 383 PDATA pData; 384 JNI_CHECK_PEER_RETURN(self); 385 386 AwtObject::WinThreadExec(self, AwtMenu::MENU_ADDSEPARATOR); 387 388 CATCH_BAD_ALLOC; 389 } 390 391 392 /* 393 * Class: sun_awt_windows_WMenuPeer 394 * Method: delItem 395 * Signature: (I)V 396 */ 397 JNIEXPORT void JNICALL 398 Java_sun_awt_windows_WMenuPeer_delItem(JNIEnv *env, jobject self, 399 jint index) 400 { 401 TRY; 402 403 PDATA pData; 404 JNI_CHECK_PEER_RETURN(self); 405 406 AwtObject::WinThreadExec(self, AwtMenu::MENU_DELITEM, index); 407 408 CATCH_BAD_ALLOC; 409 } 410 411 /* 412 * Class: sun_awt_windows_WMenuPeer 413 * Method: createMenu 414 * Signature: (Lsun/awt/windows/WMenuBarPeer;)V 415 */ 416 JNIEXPORT void JNICALL 417 Java_sun_awt_windows_WMenuPeer_createMenu(JNIEnv *env, jobject self, 418 jobject menuBar) 419 { 420 TRY; 421 422 PDATA pData; 423 JNI_CHECK_PEER_RETURN(menuBar); 424 425 AwtMenuBar* awtMenuBar = (AwtMenuBar *)pData; 426 AwtToolkit::CreateComponent(self, awtMenuBar, 427 (AwtToolkit::ComponentFactory)AwtMenu::Create,FALSE); 428 JNI_CHECK_PEER_CREATION_RETURN(self); 429 430 CATCH_BAD_ALLOC; 431 } 432 433 /* 434 * Class: sun_awt_windows_WMenuPeer 435 * Method: createSubMenu 436 * Signature: (Lsun/awt/windows/WMenuPeer;)V 437 */ 438 JNIEXPORT void JNICALL 439 Java_sun_awt_windows_WMenuPeer_createSubMenu(JNIEnv *env, jobject self, 440 jobject menu) 441 { 442 TRY; 443 444 PDATA pData; 445 JNI_CHECK_PEER_RETURN(menu); 446 447 AwtMenu* awtMenu = (AwtMenu *)pData; 448 AwtToolkit::CreateComponent(self, awtMenu, 449 (AwtToolkit::ComponentFactory)AwtMenu::Create,FALSE); 450 JNI_CHECK_PEER_CREATION_RETURN(self); 451 452 CATCH_BAD_ALLOC; 453 } 454 455 } /* extern "C" */