1/*
2 * Copyright (c) 2011, 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#import <JavaNativeFoundation/JavaNativeFoundation.h>
27#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
28
29
30#import "CMenu.h"
31#import "CMenuBar.h"
32#import "ThreadUtilities.h"
33
34#import "sun_lwawt_macosx_CMenu.h"
35
36@implementation CMenu
37
38- (id)initWithPeer:(jobject)peer {
39AWT_ASSERT_APPKIT_THREAD;
40    // Create the new NSMenu
41    self = [super initWithPeer:peer asSeparator:NO];
42    if (self) {
43        fMenu = [NSMenu javaMenuWithTitle:@""];
44        [fMenu retain];
45        [fMenu setAutoenablesItems:NO];
46    }
47    return self;
48}
49
50- (void)dealloc {
51    [fMenu release];
52    fMenu = nil;
53    [super dealloc];
54}
55
56- (void)addJavaSubmenu:(CMenu *)submenu {
57    [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:submenu waitUntilDone:YES];
58}
59
60- (void)addJavaMenuItem:(CMenuItem *)theMenuItem {
61    [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:theMenuItem waitUntilDone:YES];
62}
63
64- (void)addNativeItem_OnAppKitThread:(CMenuItem *)itemModified {
65AWT_ASSERT_APPKIT_THREAD;
66    [itemModified addNSMenuItemToMenu:[self menu]];
67}
68
69- (void)setJavaMenuTitle:(NSString *)title {
70
71    if (title) {
72        [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) on:self withObject:title waitUntilDone:YES];
73    }
74}
75
76- (void)setNativeMenuTitle_OnAppKitThread:(NSString *)title {
77AWT_ASSERT_APPKIT_THREAD;
78
79    [fMenu setTitle:title];
80    // If we are a submenu we need to set our name in the parent menu's menu item.
81    NSMenu *parent = [fMenu supermenu];
82    if (parent) {
83        NSInteger index = [parent indexOfItemWithSubmenu:fMenu];
84        NSMenuItem *menuItem = [parent itemAtIndex:index];
85        [menuItem setTitle:title];
86    }
87}
88
89- (void)addSeparator {
90    // Nothing calls this, which is good because we need a CMenuItem here.
91}
92
93- (void)deleteJavaItem:(jint)index {
94
95    [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES];
96}
97
98- (void)deleteNativeJavaItem_OnAppKitThread:(NSNumber *)number {
99AWT_ASSERT_APPKIT_THREAD;
100
101    int n = [number intValue];
102    if (n < [[self menu] numberOfItems]) {
103        [[self menu] removeItemAtIndex:n];
104    }
105}
106
107- (void)addNSMenuItemToMenu:(NSMenu *)inMenu {
108    if (fMenuItem == nil) return;
109    [fMenuItem setSubmenu:fMenu];
110    [inMenu addItem:fMenuItem];
111}
112
113- (NSMenu *)menu {
114    return [[fMenu retain] autorelease];
115}
116
117- (void)setNativeEnabled_OnAppKitThread:(NSNumber *)boolNumber {
118AWT_ASSERT_APPKIT_THREAD;
119
120    @synchronized(self) {
121        fIsEnabled = [boolNumber boolValue];
122
123        NSMenu* supermenu = [fMenu supermenu];
124        [[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:fMenu]] setEnabled:fIsEnabled];
125    }
126}
127
128- (NSString *)description {
129    return [NSString stringWithFormat:@"CMenu[ %@ ]", fMenu];
130}
131
132@end
133
134CMenu * createCMenu (jobject cPeerObjGlobal) {
135
136    __block CMenu *aCMenu = nil;
137
138    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
139
140        aCMenu = [[CMenu alloc] initWithPeer:cPeerObjGlobal];
141        // the aCMenu is released in CMenuComponent.dispose()
142    }];
143
144    if (aCMenu == nil) {
145        return 0L;
146    }
147
148    return aCMenu;
149
150}
151
152/*
153 * Class:     sun_lwawt_macosx_CMenu
154 * Method:    nativeCreateSubMenu
155 * Signature: (J)J
156 */
157JNIEXPORT jlong JNICALL
158Java_sun_lwawt_macosx_CMenu_nativeCreateSubMenu
159(JNIEnv *env, jobject peer, jlong parentMenu)
160{
161    CMenu *aCMenu = nil;
162JNF_COCOA_ENTER(env);
163
164    jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
165
166    aCMenu = createCMenu (cPeerObjGlobal);
167
168    // Add it to the parent menu
169    [((CMenu *)jlong_to_ptr(parentMenu)) addJavaSubmenu: aCMenu];
170
171JNF_COCOA_EXIT(env);
172
173    return ptr_to_jlong(aCMenu);
174}
175
176
177
178/*
179 * Class:     sun_lwawt_macosx_CMenu
180 * Method:    nativeCreateMenu
181 * Signature: (JZ)J
182 */
183JNIEXPORT jlong JNICALL
184Java_sun_lwawt_macosx_CMenu_nativeCreateMenu
185(JNIEnv *env, jobject peer,
186        jlong parentMenuBar, jboolean isHelpMenu, jint insertLocation)
187{
188    CMenu *aCMenu = nil;
189    CMenuBar *parent = (CMenuBar *)jlong_to_ptr(parentMenuBar);
190JNF_COCOA_ENTER(env);
191
192    jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
193
194    aCMenu = createCMenu (cPeerObjGlobal);
195
196    // Add it to the menu bar.
197    [parent javaAddMenu:aCMenu atIndex:insertLocation];
198
199    // If the menu is already the help menu (because we are creating an entire
200    // menu bar) we need to note that now, because we can't rely on
201    // setHelpMenu() being called again.
202    if (isHelpMenu == JNI_TRUE) {
203        [parent javaSetHelpMenu: aCMenu];
204    }
205
206JNF_COCOA_EXIT(env);
207    return ptr_to_jlong(aCMenu);
208}
209
210
211/*
212 * Class:     sun_lwawt_macosx_CMenu
213 * Method:    nativeSetMenuTitle
214 * Signature: (JLjava/lang/String;)V
215 */
216JNIEXPORT void JNICALL
217Java_sun_lwawt_macosx_CMenu_nativeSetMenuTitle
218(JNIEnv *env, jobject peer, jlong menuObject, jstring label)
219{
220JNF_COCOA_ENTER(env);
221    // Set the menu's title.
222    [((CMenu *)jlong_to_ptr(menuObject)) setJavaMenuTitle:JNFJavaToNSString(env, label)];
223JNF_COCOA_EXIT(env);
224}
225
226/*
227 * Class:     sun_lwawt_macosx_CMenu
228 * Method:    nativeAddSeparator
229 * Signature: (J)V
230 */
231JNIEXPORT void JNICALL
232Java_sun_lwawt_macosx_CMenu_nativeAddSeparator
233(JNIEnv *env, jobject peer, jlong menuObject)
234{
235JNF_COCOA_ENTER(env);
236    // Add a separator item.
237    [((CMenu *)jlong_to_ptr(menuObject))addSeparator];
238JNF_COCOA_EXIT(env);
239}
240
241/*
242 * Class:     sun_lwawt_macosx_CMenu
243 * Method:    nativeDeleteItem
244 * Signature: (JI)V
245 */
246JNIEXPORT void JNICALL
247Java_sun_lwawt_macosx_CMenu_nativeDeleteItem
248(JNIEnv *env, jobject peer, jlong menuObject, jint index)
249{
250JNF_COCOA_ENTER(env);
251    // Remove the specified item.
252    [((CMenu *)jlong_to_ptr(menuObject)) deleteJavaItem: index];
253JNF_COCOA_EXIT(env);
254}
255
256/*
257 * Class:     sun_lwawt_macosx_CMenu
258 * Method:    nativeGetNSMenu
259 * Signature: (J)J
260 */
261JNIEXPORT jlong JNICALL
262Java_sun_lwawt_macosx_CMenu_nativeGetNSMenu
263(JNIEnv *env, jobject peer, jlong menuObject)
264{
265    NSMenu* nsMenu = NULL;
266
267JNF_COCOA_ENTER(env);
268    // Strong retain this menu; it'll get released in Java_apple_laf_ScreenMenu_addMenuListeners
269    nsMenu = [[((CMenu *)jlong_to_ptr(menuObject)) menu] retain];
270JNF_COCOA_EXIT(env);
271
272    return ptr_to_jlong(nsMenu);
273}
274