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