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:) onObject:self withObject:submenu waitUntilDone:YES awtMode:YES];
  59 }
  60 
  61 - (void)addJavaMenuItem:(CMenuItem *)theMenuItem {
  62     [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:theMenuItem waitUntilDone:YES awtMode: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:) onObject:self withObject:title waitUntilDone:YES awtMode: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:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode: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:) onObject:[CMenu alloc] withObject:args waitUntilDone:YES awtMode: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 }