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
34struct DelItemStruct {
35    jobject menuitem;
36    jint index;
37};
38/***********************************************************************/
39// struct for _AddMenu() method
40struct AddMenuStruct {
41    jobject menubar;
42    jobject menu;
43};
44/************************************************************************
45 * AwtMenuBar fields
46 */
47
48jmethodID AwtMenuBar::getMenuMID;
49jmethodID AwtMenuBar::getMenuCountMID;
50
51
52/************************************************************************
53 * AwtMenuBar methods
54 */
55
56
57AwtMenuBar::AwtMenuBar() {
58    m_frame = NULL;
59}
60
61AwtMenuBar::~AwtMenuBar()
62{
63}
64
65void 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
75LPCTSTR AwtMenuBar::GetClassName() {
76  return TEXT("SunAwtMenuBar");
77}
78
79/* Create a new AwtMenuBar object and menu.   */
80AwtMenuBar* 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
122done:
123    if (target != NULL) {
124        env->DeleteLocalRef(target);
125    }
126
127    return menuBar;
128}
129
130HWND AwtMenuBar::GetOwnerHWnd()
131{
132    AwtFrame *myFrame = m_frame;
133    if (myFrame == NULL)
134        return NULL;
135    else
136        return myFrame->GetHWnd();
137}
138
139int 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
148AwtMenuItem* 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
165done:
166    env->DeleteLocalRef(menu);
167    env->DeleteLocalRef(menuItemPeer);
168
169    return awtMenuItem;
170}
171
172void AwtMenuBar::DrawItem(DRAWITEMSTRUCT& drawInfo)
173{
174    DASSERT(drawInfo.CtlType == ODT_MENU);
175    AwtMenu::DrawItems(drawInfo);
176}
177
178void AwtMenuBar::MeasureItem(HDC hDC,
179                             MEASUREITEMSTRUCT& measureInfo)
180{
181    DASSERT(measureInfo.CtlType == ODT_MENU);
182    AwtMenu::MeasureItem(hDC, measureInfo);
183}
184
185void 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
194void 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 */
208void AwtMenuBar::RedrawMenuBar() {
209    VERIFY(::DrawMenuBar(GetOwnerHWnd()));
210}
211
212void 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    }
231ret:
232    env->DeleteGlobalRef(self);
233    if (menu != NULL) {
234        env->DeleteGlobalRef(menu);
235    }
236
237    delete ams;
238}
239
240void 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));
254ret:
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
266extern "C" {
267
268/*
269 * Class:     java_awt_MenuBar
270 * Method:    initIDs
271 * Signature: ()V
272 */
273JNIEXPORT void JNICALL
274Java_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
296extern "C" {
297
298/*
299 * Class:     sun_awt_windows_WMenuBarPeer
300 * Method:    addMenu
301 * Signature: (Ljava/awt/Menu;)V
302 */
303JNIEXPORT void JNICALL
304Java_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 */
324JNIEXPORT void JNICALL
325Java_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 */
345JNIEXPORT void JNICALL
346Java_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" */
358