1 /*
   2  * Copyright (c) 1996, 2016, 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     VERIFY(::DrawMenuBar(GetOwnerHWnd()));
 210 }
 211 
 212 void AwtMenuBar::_AddMenu(void *param)
 213 {
 214     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 215 
 216     AddMenuStruct *ams = (AddMenuStruct *)param;
 217     jobject self = ams->menubar;
 218     jobject menu = ams->menu;
 219 
 220     AwtMenuBar *m = NULL;
 221 
 222     PDATA pData;
 223     JNI_CHECK_PEER_GOTO(self, ret);
 224     JNI_CHECK_NULL_GOTO(menu, "null menu", ret);
 225     m = (AwtMenuBar *)pData;
 226     if (::IsWindow(m->GetOwnerHWnd()))
 227     {
 228         /* The menu was already created and added during peer creation -- redraw */
 229         m->RedrawMenuBar();
 230     }
 231 ret:
 232     env->DeleteGlobalRef(self);
 233     if (menu != NULL) {
 234         env->DeleteGlobalRef(menu);
 235     }
 236 
 237     delete ams;
 238 }
 239 
 240 void AwtMenuBar::_DelItem(void *param)
 241 {
 242     if (AwtToolkit::IsMainThread()) {
 243         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 244 
 245         DelItemStruct *dis = (DelItemStruct*) param;
 246         jobject self = dis->menuitem;
 247         jint index = dis->index;
 248 
 249         AwtMenuBar *m = NULL;
 250         PDATA pData;
 251         JNI_CHECK_PEER_GOTO(self, ret);
 252         m = (AwtMenuBar *)pData;
 253         m->DeleteItem(static_cast<UINT>(index));
 254 ret:
 255         env->DeleteGlobalRef(self);
 256         delete dis;
 257     } else {
 258         AwtToolkit::GetInstance().InvokeFunction(AwtMenuBar::_DelItem, param);
 259     }
 260 }
 261 
 262 /************************************************************************
 263  * MenuBar native methods
 264  */
 265 
 266 extern "C" {
 267 
 268 /*
 269  * Class:     java_awt_MenuBar
 270  * Method:    initIDs
 271  * Signature: ()V
 272  */
 273 JNIEXPORT void JNICALL
 274 Java_java_awt_MenuBar_initIDs(JNIEnv *env, jclass cls)
 275 {
 276     TRY;
 277 
 278     AwtMenuBar::getMenuCountMID = env->GetMethodID(cls, "getMenuCountImpl", "()I");
 279     DASSERT(AwtMenuBar::getMenuCountMID != NULL);
 280     CHECK_NULL(AwtMenuBar::getMenuCountMID);
 281 
 282     AwtMenuBar::getMenuMID = env->GetMethodID(cls, "getMenuImpl",
 283                                               "(I)Ljava/awt/Menu;");
 284     DASSERT(AwtMenuBar::getMenuMID != NULL);
 285 
 286     CATCH_BAD_ALLOC;
 287 }
 288 
 289 } /* extern "C" */
 290 
 291 
 292 /************************************************************************
 293  * WMenuBarPeer native methods
 294  */
 295 
 296 extern "C" {
 297 
 298 /*
 299  * Class:     sun_awt_windows_WMenuBarPeer
 300  * Method:    addMenu
 301  * Signature: (Ljava/awt/Menu;)V
 302  */
 303 JNIEXPORT void JNICALL
 304 Java_sun_awt_windows_WMenuBarPeer_addMenu(JNIEnv *env, jobject self,
 305                                           jobject menu)
 306 {
 307     TRY;
 308 
 309     AddMenuStruct *ams = new AddMenuStruct;
 310     ams->menubar = env->NewGlobalRef(self);
 311     ams->menu = env->NewGlobalRef(menu);
 312 
 313     AwtToolkit::GetInstance().SyncCall(AwtMenuBar::_AddMenu, ams);
 314     // global refs and ams are deleted in _AddMenu()
 315 
 316     CATCH_BAD_ALLOC;
 317 }
 318 
 319 /*
 320  * Class:     sun_awt_windows_WMenuBarPeer
 321  * Method:    delMenu
 322  * Signature: (I)V
 323  */
 324 JNIEXPORT void JNICALL
 325 Java_sun_awt_windows_WMenuBarPeer_delMenu(JNIEnv *env, jobject self,
 326                                           jint index)
 327 {
 328     TRY;
 329 
 330     DelItemStruct *dis = new DelItemStruct;
 331     dis->menuitem = env->NewGlobalRef(self);
 332     dis->index = index;
 333 
 334     AwtToolkit::GetInstance().SyncCall(AwtMenuBar::_DelItem, dis);
 335     // global refs and dis are deleted in _DelItem
 336 
 337     CATCH_BAD_ALLOC;
 338 }
 339 
 340 /*
 341  * Class:     sun_awt_windows_WMenuBarPeer
 342  * Method:    create
 343  * Signature: (Lsun/awt/windows/WFramePeer;)V
 344  */
 345 JNIEXPORT void JNICALL
 346 Java_sun_awt_windows_WMenuBarPeer_create(JNIEnv *env, jobject self,
 347                                          jobject frame)
 348 {
 349     TRY;
 350 
 351     AwtToolkit::CreateComponent(self, frame,
 352                                 (AwtToolkit::ComponentFactory)
 353                                 AwtMenuBar::Create);
 354     CATCH_BAD_ALLOC;
 355 }
 356 
 357 } /* extern "C" */