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