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" */