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