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 <JavaRuntimeSupport/JavaRuntimeSupport.h> 27 28 29 #import "CMenu.h" 30 #import "CMenuBar.h" 31 #import "ThreadUtilities.h" 32 #import "JNIUtilities.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: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 { 65 AWT_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 { 77 AWT_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 { 99 AWT_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 { 118 AWT_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 134 CMenu * 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 */ 157 JNIEXPORT jlong JNICALL 158 Java_sun_lwawt_macosx_CMenu_nativeCreateSubMenu 159 (JNIEnv *env, jobject peer, jlong parentMenu) 160 { 161 CMenu *aCMenu = nil; 162 JNI_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 171 JNI_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 */ 183 JNIEXPORT jlong JNICALL 184 Java_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); 190 JNI_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 206 JNI_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 */ 216 JNIEXPORT void JNICALL 217 Java_sun_lwawt_macosx_CMenu_nativeSetMenuTitle 218 (JNIEnv *env, jobject peer, jlong menuObject, jstring label) 219 { 220 JNI_COCOA_ENTER(env); 221 // Set the menu's title. 222 [((CMenu *)jlong_to_ptr(menuObject)) setJavaMenuTitle:JavaStringToNSString(env, label)]; 223 JNI_COCOA_EXIT(env); 224 } 225 226 /* 227 * Class: sun_lwawt_macosx_CMenu 228 * Method: nativeAddSeparator 229 * Signature: (J)V 230 */ 231 JNIEXPORT void JNICALL 232 Java_sun_lwawt_macosx_CMenu_nativeAddSeparator 233 (JNIEnv *env, jobject peer, jlong menuObject) 234 { 235 JNI_COCOA_ENTER(env); 236 // Add a separator item. 237 [((CMenu *)jlong_to_ptr(menuObject))addSeparator]; 238 JNI_COCOA_EXIT(env); 239 } 240 241 /* 242 * Class: sun_lwawt_macosx_CMenu 243 * Method: nativeDeleteItem 244 * Signature: (JI)V 245 */ 246 JNIEXPORT void JNICALL 247 Java_sun_lwawt_macosx_CMenu_nativeDeleteItem 248 (JNIEnv *env, jobject peer, jlong menuObject, jint index) 249 { 250 JNI_COCOA_ENTER(env); 251 // Remove the specified item. 252 [((CMenu *)jlong_to_ptr(menuObject)) deleteJavaItem: index]; 253 JNI_COCOA_EXIT(env); 254 } 255 256 /* 257 * Class: sun_lwawt_macosx_CMenu 258 * Method: nativeGetNSMenu 259 * Signature: (J)J 260 */ 261 JNIEXPORT jlong JNICALL 262 Java_sun_lwawt_macosx_CMenu_nativeGetNSMenu 263 (JNIEnv *env, jobject peer, jlong menuObject) 264 { 265 NSMenu* nsMenu = NULL; 266 267 JNI_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]; 270 JNI_COCOA_EXIT(env); 271 272 return ptr_to_jlong(nsMenu); 273 }