1 /*
   2  * Copyright (c) 1996, 2018, 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_MenuBar.h"
  27 #include "awt_Frame.h"
  28 
  29 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  30  */
  31 
  32 /***********************************************************************/
  33 // struct for _DelItem() method
  34 struct DelItemStruct {
  35     jobject menuitem;
  36     jint index;
  37 };
  38 /***********************************************************************/
  39 // struct for _AddMenu() method
  40 struct AddMenuStruct {
  41     jobject menubar;
  42     jobject menu;
  43 };
  44 /************************************************************************
  45  * AwtMenuBar fields
  46  */
  47 
  48 jmethodID AwtMenuBar::getMenuMID;
  49 jmethodID AwtMenuBar::getMenuCountMID;
  50 
  51 
  52 /************************************************************************
  53  * AwtMenuBar methods
  54  */
  55 
  56 
  57 AwtMenuBar::AwtMenuBar() {
  58     m_frame = NULL;
  59 }
  60 
  61 AwtMenuBar::~AwtMenuBar()
  62 {
  63 }
  64 
  65 void AwtMenuBar::Dispose()
  66 {
  67     if (m_frame != NULL && m_frame->GetMenuBar() == this) {
  68         m_frame->SetMenuBar(NULL);
  69     }
  70     m_frame = NULL;
  71 
  72     AwtMenu::Dispose();
  73 }
  74 
  75 LPCTSTR AwtMenuBar::GetClassName() {
  76   return TEXT("SunAwtMenuBar");
  77 }
  78 
  79 /* Create a new AwtMenuBar object and menu.   */
  80 AwtMenuBar* AwtMenuBar::Create(jobject self, jobject framePeer)
  81 {
  82     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  83 
  84     jobject target = NULL;
  85     AwtMenuBar* menuBar = NULL;
  86 
  87     try {
  88         if (env->EnsureLocalCapacity(1) < 0) {
  89             return NULL;
  90         }
  91 
  92         /* target is a java.awt.MenuBar */
  93         target = env->GetObjectField(self, AwtObject::targetID);
  94         JNI_CHECK_NULL_GOTO(target, "null target", done);
  95 
  96         menuBar = new AwtMenuBar();
  97 
  98         SetLastError(0);
  99         HMENU hMenu = ::CreateMenu();
 100         // fix for 5088782
 101         if (!CheckMenuCreation(env, self, hMenu))
 102         {
 103             env->DeleteLocalRef(target);
 104             return NULL;
 105         }
 106 
 107         menuBar->SetHMenu(hMenu);
 108 
 109         menuBar->LinkObjects(env, self);
 110         if (framePeer != NULL) {
 111             PDATA pData;
 112             JNI_CHECK_PEER_GOTO(framePeer, done);
 113             menuBar->m_frame = (AwtFrame *)pData;
 114         } else {
 115             menuBar->m_frame = NULL;
 116         }
 117     } catch (...) {
 118         env->DeleteLocalRef(target);
 119         throw;
 120     }
 121 
 122 done:
 123     if (target != NULL) {
 124         env->DeleteLocalRef(target);
 125     }
 126 
 127     return menuBar;
 128 }
 129 
 130 HWND AwtMenuBar::GetOwnerHWnd()
 131 {
 132     AwtFrame *myFrame = m_frame;
 133     if (myFrame == NULL)
 134         return NULL;
 135     else
 136         return myFrame->GetHWnd();
 137 }
 138 
 139 int AwtMenuBar::CountItem(jobject menuBar)
 140 {
 141     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 142     jint nCount = env->CallIntMethod(menuBar, AwtMenuBar::getMenuCountMID);
 143     DASSERT(!safe_ExceptionOccurred(env));
 144 
 145     return nCount;
 146 }
 147 
 148 AwtMenuItem* AwtMenuBar::GetItem(jobject target, long index)
 149 {
 150     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 151     if (env->EnsureLocalCapacity(2) < 0) {
 152         return NULL;
 153     }
 154 
 155     jobject menu = env->CallObjectMethod(target, AwtMenuBar::getMenuMID,index);
 156     if (!menu) return NULL; // menu item was removed concurrently
 157     DASSERT(!safe_ExceptionOccurred(env));
 158 
 159     jobject menuItemPeer = GetPeerForTarget(env, menu);
 160     PDATA pData;
 161     AwtMenuItem* awtMenuItem = NULL;
 162     JNI_CHECK_PEER_GOTO(menuItemPeer, done);
 163     awtMenuItem = (AwtMenuItem*)pData;
 164 
 165 done:
 166     env->DeleteLocalRef(menu);
 167     env->DeleteLocalRef(menuItemPeer);
 168 
 169     return awtMenuItem;
 170 }
 171 
 172 void AwtMenuBar::DrawItem(DRAWITEMSTRUCT& drawInfo)
 173 {
 174     DASSERT(drawInfo.CtlType == ODT_MENU);
 175     AwtMenu::DrawItems(drawInfo);
 176 }
 177 
 178 void AwtMenuBar::MeasureItem(HDC hDC,
 179                              MEASUREITEMSTRUCT& measureInfo)
 180 {
 181     DASSERT(measureInfo.CtlType == ODT_MENU);
 182     AwtMenu::MeasureItem(hDC, measureInfo);
 183 }
 184 
 185 void AwtMenuBar::AddItem(AwtMenuItem* item)
 186 {
 187     AwtMenu::AddItem(item);
 188     HWND hOwnerWnd = GetOwnerHWnd();
 189     if (hOwnerWnd != NULL) {
 190         VERIFY(::InvalidateRect(hOwnerWnd,0,TRUE));
 191     }
 192 }
 193 
 194 void AwtMenuBar::DeleteItem(UINT index)
 195 {
 196     AwtMenu::DeleteItem(index);
 197     HWND hOwnerWnd = GetOwnerHWnd();
 198     if (hOwnerWnd != NULL) {
 199         VERIFY(::InvalidateRect(hOwnerWnd,0,TRUE));
 200     }
 201     RedrawMenuBar();
 202 }
 203 
 204 /**
 205  * If the menu changes after the system has created the window,
 206  * this function must be called to draw the changed menu bar.
 207  */
 208 void AwtMenuBar::RedrawMenuBar() {
 209     HWND hOwnerWnd = GetOwnerHWnd();
 210     if (hOwnerWnd != NULL) {
 211         VERIFY(::DrawMenuBar(hOwnerWnd));
 212     }
 213 }
 214 
 215 void AwtMenuBar::_AddMenu(void *param)
 216 {
 217     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 218 
 219     AddMenuStruct *ams = (AddMenuStruct *)param;
 220     jobject self = ams->menubar;
 221     jobject menu = ams->menu;
 222 
 223     AwtMenuBar *m = NULL;
 224 
 225     PDATA pData;
 226     JNI_CHECK_PEER_GOTO(self, ret);
 227     JNI_CHECK_NULL_GOTO(menu, "null menu", ret);
 228     m = (AwtMenuBar *)pData;
 229     if (::IsWindow(m->GetOwnerHWnd()))
 230     {
 231         /* The menu was already created and added during peer creation -- redraw */
 232         m->RedrawMenuBar();
 233     }
 234 ret:
 235     env->DeleteGlobalRef(self);
 236     if (menu != NULL) {
 237         env->DeleteGlobalRef(menu);
 238     }
 239 
 240     delete ams;
 241 }
 242 
 243 void AwtMenuBar::_DelItem(void *param)
 244 {
 245     if (AwtToolkit::IsMainThread()) {
 246         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 247 
 248         DelItemStruct *dis = (DelItemStruct*) param;
 249         jobject self = dis->menuitem;
 250         jint index = dis->index;
 251 
 252         AwtMenuBar *m = NULL;
 253         PDATA pData;
 254         JNI_CHECK_PEER_GOTO(self, ret);
 255         m = (AwtMenuBar *)pData;
 256         m->DeleteItem(static_cast<UINT>(index));
 257 ret:
 258         env->DeleteGlobalRef(self);
 259         delete dis;
 260     } else {
 261         AwtToolkit::GetInstance().InvokeFunction(AwtMenuBar::_DelItem, param);
 262     }
 263 }
 264 
 265 /************************************************************************
 266  * MenuBar native methods
 267  */
 268 
 269 extern "C" {
 270 
 271 /*
 272  * Class:     java_awt_MenuBar
 273  * Method:    initIDs
 274  * Signature: ()V
 275  */
 276 JNIEXPORT void JNICALL
 277 Java_java_awt_MenuBar_initIDs(JNIEnv *env, jclass cls)
 278 {
 279     TRY;
 280 
 281     AwtMenuBar::getMenuCountMID = env->GetMethodID(cls, "getMenuCountImpl", "()I");
 282     DASSERT(AwtMenuBar::getMenuCountMID != NULL);
 283     CHECK_NULL(AwtMenuBar::getMenuCountMID);
 284 
 285     AwtMenuBar::getMenuMID = env->GetMethodID(cls, "getMenuImpl",
 286                                               "(I)Ljava/awt/Menu;");
 287     DASSERT(AwtMenuBar::getMenuMID != NULL);
 288 
 289     CATCH_BAD_ALLOC;
 290 }
 291 
 292 } /* extern "C" */
 293 
 294 
 295 /************************************************************************
 296  * WMenuBarPeer native methods
 297  */
 298 
 299 extern "C" {
 300 
 301 /*
 302  * Class:     sun_awt_windows_WMenuBarPeer
 303  * Method:    addMenu
 304  * Signature: (Ljava/awt/Menu;)V
 305  */
 306 JNIEXPORT void JNICALL
 307 Java_sun_awt_windows_WMenuBarPeer_addMenu(JNIEnv *env, jobject self,
 308                                           jobject menu)
 309 {
 310     TRY;
 311 
 312     AddMenuStruct *ams = new AddMenuStruct;
 313     ams->menubar = env->NewGlobalRef(self);
 314     ams->menu = env->NewGlobalRef(menu);
 315 
 316     AwtToolkit::GetInstance().SyncCall(AwtMenuBar::_AddMenu, ams);
 317     // global refs and ams are deleted in _AddMenu()
 318 
 319     CATCH_BAD_ALLOC;
 320 }
 321 
 322 /*
 323  * Class:     sun_awt_windows_WMenuBarPeer
 324  * Method:    delMenu
 325  * Signature: (I)V
 326  */
 327 JNIEXPORT void JNICALL
 328 Java_sun_awt_windows_WMenuBarPeer_delMenu(JNIEnv *env, jobject self,
 329                                           jint index)
 330 {
 331     TRY;
 332 
 333     DelItemStruct *dis = new DelItemStruct;
 334     dis->menuitem = env->NewGlobalRef(self);
 335     dis->index = index;
 336 
 337     AwtToolkit::GetInstance().SyncCall(AwtMenuBar::_DelItem, dis);
 338     // global refs and dis are deleted in _DelItem
 339 
 340     CATCH_BAD_ALLOC;
 341 }
 342 
 343 /*
 344  * Class:     sun_awt_windows_WMenuBarPeer
 345  * Method:    create
 346  * Signature: (Lsun/awt/windows/WFramePeer;)V
 347  */
 348 JNIEXPORT void JNICALL
 349 Java_sun_awt_windows_WMenuBarPeer_create(JNIEnv *env, jobject self,
 350                                          jobject frame)
 351 {
 352     TRY;
 353 
 354     AwtToolkit::CreateComponent(self, frame,
 355                                 (AwtToolkit::ComponentFactory)
 356                                 AwtMenuBar::Create);
 357     CATCH_BAD_ALLOC;
 358 }
 359 
 360 } /* extern "C" */