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 
AwtMenuBar()57 AwtMenuBar::AwtMenuBar() {
58     m_frame = NULL;
59 }
60 
~AwtMenuBar()61 AwtMenuBar::~AwtMenuBar()
62 {
63 }
64 
Dispose()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 
GetClassName()75 LPCTSTR AwtMenuBar::GetClassName() {
76   return TEXT("SunAwtMenuBar");
77 }
78 
79 /* Create a new AwtMenuBar object and menu.   */
Create(jobject self,jobject framePeer)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 
GetOwnerHWnd()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 
CountItem(jobject menuBar)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 
GetItem(jobject target,long index)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 
DrawItem(DRAWITEMSTRUCT & drawInfo)172 void AwtMenuBar::DrawItem(DRAWITEMSTRUCT& drawInfo)
173 {
174     DASSERT(drawInfo.CtlType == ODT_MENU);
175     AwtMenu::DrawItems(drawInfo);
176 }
177 
MeasureItem(HDC hDC,MEASUREITEMSTRUCT & measureInfo)178 void AwtMenuBar::MeasureItem(HDC hDC,
179                              MEASUREITEMSTRUCT& measureInfo)
180 {
181     DASSERT(measureInfo.CtlType == ODT_MENU);
182     AwtMenu::MeasureItem(hDC, measureInfo);
183 }
184 
AddItem(AwtMenuItem * item)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 
DeleteItem(UINT index)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  */
RedrawMenuBar()208 void AwtMenuBar::RedrawMenuBar() {
209     HWND hOwnerWnd = GetOwnerHWnd();
210     if (hOwnerWnd != NULL) {
211         VERIFY(::DrawMenuBar(hOwnerWnd));
212     }
213 }
214 
_AddMenu(void * param)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 
_DelItem(void * param)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
Java_java_awt_MenuBar_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_windows_WMenuBarPeer_addMenu(JNIEnv * env,jobject self,jobject menu)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
Java_sun_awt_windows_WMenuBarPeer_delMenu(JNIEnv * env,jobject self,jint index)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
Java_sun_awt_windows_WMenuBarPeer_create(JNIEnv * env,jobject self,jobject frame)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" */
361