jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/CMenuBar.m
changeset 25859 3317bb8137f4
parent 23651 e41298d0da2f
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2011, 2013, 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 <AppKit/AppKit.h>
       
    27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
       
    28 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
       
    29 
       
    30 
       
    31 #import "CMenuBar.h"
       
    32 #import "CMenu.h"
       
    33 #import "ThreadUtilities.h"
       
    34 
       
    35 #import "sun_lwawt_macosx_CMenuBar.h"
       
    36 
       
    37 __attribute__((visibility("default")))
       
    38 NSString *CMenuBarDidReuseItemNotification =
       
    39     @"CMenuBarDidReuseItemNotification";
       
    40 
       
    41 static CMenuBar *sActiveMenuBar = nil;
       
    42 static NSMenu *sDefaultHelpMenu = nil;
       
    43 static BOOL sSetupHelpMenu = NO;
       
    44 
       
    45 @interface CMenuBar (CMenuBar_Private)
       
    46 + (void) addDefaultHelpMenu;
       
    47 @end
       
    48 
       
    49 @implementation CMenuBar
       
    50 
       
    51 + (void)clearMenuBarExcludingAppleMenu_OnAppKitThread:(BOOL) excludingAppleMenu {
       
    52     AWT_ASSERT_APPKIT_THREAD;
       
    53     // Remove all Java menus from the main bar.
       
    54     NSMenu *theMainMenu = [NSApp mainMenu];
       
    55     NSUInteger i, menuCount = [theMainMenu numberOfItems];
       
    56 
       
    57     for (i = menuCount; i > 1; i--) {
       
    58         NSUInteger index = i-1;
       
    59 
       
    60         NSMenuItem *currItem = [theMainMenu itemAtIndex:index];
       
    61         NSMenu *currMenu = [currItem submenu];
       
    62 
       
    63         if (excludingAppleMenu && ![currMenu isJavaMenu]) {
       
    64             continue;
       
    65         }
       
    66         [currItem setSubmenu:nil];
       
    67         [theMainMenu removeItemAtIndex:index];
       
    68     }
       
    69 
       
    70     [CMenuBar addDefaultHelpMenu];
       
    71 }
       
    72 
       
    73 + (BOOL) isActiveMenuBar:(CMenuBar *)inMenuBar {
       
    74     return (sActiveMenuBar == inMenuBar);
       
    75 }
       
    76 
       
    77 - (id) initWithPeer:(jobject)peer {
       
    78     AWT_ASSERT_APPKIT_THREAD;
       
    79     self = [super initWithPeer: peer];
       
    80     if (self) {
       
    81         fMenuList = [[NSMutableArray alloc] init];
       
    82     }
       
    83     return self;
       
    84 }
       
    85 
       
    86 -(void) dealloc {
       
    87     [fMenuList release];
       
    88     fMenuList = nil;
       
    89 
       
    90     [fHelpMenu release];
       
    91     fHelpMenu = nil;
       
    92 
       
    93     [super dealloc];
       
    94 }
       
    95 
       
    96 + (void) activate:(CMenuBar *)menubar modallyDisabled:(BOOL)modallyDisabled {
       
    97     AWT_ASSERT_APPKIT_THREAD;
       
    98 
       
    99     if (!menubar) {
       
   100         [CMenuBar clearMenuBarExcludingAppleMenu_OnAppKitThread:YES];
       
   101         return;
       
   102     }
       
   103 
       
   104     @synchronized([CMenuBar class]) {
       
   105         sActiveMenuBar = menubar;
       
   106     }
       
   107 
       
   108     @synchronized(menubar) {
       
   109         menubar->fModallyDisabled = modallyDisabled;
       
   110     }
       
   111 
       
   112     NSUInteger i = 0, newMenuListSize = [menubar->fMenuList count];
       
   113 
       
   114     NSMenu *theMainMenu = [NSApp mainMenu];
       
   115     NSUInteger menuIndex, menuCount = [theMainMenu numberOfItems];
       
   116 
       
   117     NSUInteger cmenuIndex = 0, cmenuCount = newMenuListSize;
       
   118     NSMutableArray *removedMenuArray = [NSMutableArray array];
       
   119 
       
   120     for (menuIndex = 0; menuIndex < menuCount; menuIndex++) {
       
   121         NSMenuItem *currItem = [theMainMenu itemAtIndex:menuIndex];
       
   122         NSMenu *currMenu = [currItem submenu];
       
   123 
       
   124         if ([currMenu isJavaMenu]) {
       
   125             // Ready to replace, find next candidate
       
   126             CMenu *newMenu = nil;
       
   127             if (cmenuIndex < cmenuCount) {
       
   128                 newMenu = (CMenu *)[menubar->fMenuList objectAtIndex:cmenuIndex];
       
   129                 if (newMenu == menubar->fHelpMenu) {
       
   130                     cmenuIndex++;
       
   131                     if (cmenuIndex < cmenuCount) {
       
   132                         newMenu = (CMenu *)[menubar->fMenuList objectAtIndex:cmenuIndex];
       
   133                     }
       
   134                 }
       
   135             }
       
   136             if (newMenu) {
       
   137                 NSMenu *menuToAdd = [newMenu menu];
       
   138                 if ([theMainMenu indexOfItemWithSubmenu:menuToAdd] == -1) {
       
   139                     [[NSNotificationCenter defaultCenter] postNotificationName:CMenuBarDidReuseItemNotification object:theMainMenu];
       
   140 
       
   141                     [currItem setSubmenu:menuToAdd];
       
   142                     [currItem setTitle:[menuToAdd title]];
       
   143                     cmenuIndex++;
       
   144                 }
       
   145 
       
   146                 BOOL newEnabledState = [newMenu isEnabled] && !menubar->fModallyDisabled;
       
   147                 [currItem setEnabled:newEnabledState];
       
   148             } else {
       
   149                 [removedMenuArray addObject:[NSNumber numberWithInteger:menuIndex]];
       
   150             }
       
   151         }
       
   152     }
       
   153 
       
   154     // Clean up extra items
       
   155     NSUInteger removedIndex, removedCount = [removedMenuArray count];
       
   156     for (removedIndex=removedCount; removedIndex > 0; removedIndex--) {
       
   157         NSUInteger index = [[removedMenuArray objectAtIndex:(removedIndex-1)] integerValue];
       
   158         NSMenuItem *currItem = [theMainMenu itemAtIndex:index];
       
   159         [currItem setSubmenu:nil];
       
   160         [theMainMenu removeItemAtIndex:index];
       
   161     }
       
   162 
       
   163     i = cmenuIndex;
       
   164 
       
   165     // Add all of the menus in the menu list.
       
   166     for (; i < newMenuListSize; i++) {
       
   167         CMenu *newMenu = (CMenu *)[menubar->fMenuList objectAtIndex:i];
       
   168 
       
   169         if (newMenu != menubar->fHelpMenu) {
       
   170             NSArray *args = [NSArray arrayWithObjects:newMenu, [NSNumber numberWithInt:-1], nil];
       
   171             [menubar nativeAddMenuAtIndex_OnAppKitThread:args];
       
   172         }
       
   173     }
       
   174 
       
   175     // Add the help menu last.
       
   176     if (menubar->fHelpMenu) {
       
   177         NSArray *args = [NSArray arrayWithObjects:menubar->fHelpMenu, [NSNumber numberWithInt:-1], nil];
       
   178         [menubar nativeAddMenuAtIndex_OnAppKitThread:args];
       
   179     } else {
       
   180         [CMenuBar addDefaultHelpMenu];
       
   181     }
       
   182 }
       
   183 
       
   184 -(void) deactivate {
       
   185     AWT_ASSERT_APPKIT_THREAD;
       
   186 
       
   187     @synchronized([CMenuBar class]) {
       
   188         sActiveMenuBar = nil;
       
   189     }
       
   190 
       
   191     @synchronized(self) {
       
   192         fModallyDisabled = NO;
       
   193     }
       
   194 }
       
   195 
       
   196 -(void) javaAddMenu: (CMenu *)theMenu {
       
   197     @synchronized(self) {
       
   198         [fMenuList addObject: theMenu];
       
   199     }
       
   200 
       
   201     if (self == sActiveMenuBar) {
       
   202         NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:-1], nil];
       
   203         [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES];
       
   204         [args release];
       
   205     }
       
   206 }
       
   207 
       
   208 // This method is a special case for use by the screen menu bar.
       
   209 // See ScreenMenuBar.java -- used to implement setVisible(boolean) by
       
   210 // removing or adding the menu from the current menu bar's list.
       
   211 -(void) javaAddMenu: (CMenu *)theMenu atIndex:(jint)index {
       
   212     @synchronized(self) {
       
   213         if (index == -1){
       
   214             [fMenuList addObject:theMenu];
       
   215         }else{
       
   216             [fMenuList insertObject:theMenu atIndex:index];
       
   217         }
       
   218     }
       
   219 
       
   220     if (self == sActiveMenuBar) {
       
   221         NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:index], nil];
       
   222         [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES];
       
   223         [args release];
       
   224     }
       
   225 }
       
   226 
       
   227 - (NSInteger) javaIndexToNSMenuIndex_OnAppKitThread:(jint)javaIndex {
       
   228     AWT_ASSERT_APPKIT_THREAD;
       
   229     NSInteger returnValue = -1;
       
   230     NSMenu *theMainMenu = [NSApp mainMenu];
       
   231 
       
   232     if (javaIndex == -1) {
       
   233         if (fHelpMenu) {
       
   234             returnValue = [theMainMenu indexOfItemWithSubmenu:[fHelpMenu menu]];
       
   235         }
       
   236     } else {
       
   237         CMenu *requestedMenu = [fMenuList objectAtIndex:javaIndex];
       
   238 
       
   239         if (requestedMenu == fHelpMenu) {
       
   240             returnValue = [theMainMenu indexOfItemWithSubmenu:[fHelpMenu menu]];
       
   241         } else {
       
   242             NSUInteger i, menuCount = [theMainMenu numberOfItems];
       
   243             jint currJavaMenuIndex = 0;
       
   244             for (i = 0; i < menuCount; i++) {
       
   245                 NSMenuItem *currItem = [theMainMenu itemAtIndex:i];
       
   246                 NSMenu *currMenu = [currItem submenu];
       
   247 
       
   248                 if ([currMenu isJavaMenu]) {
       
   249                     if (javaIndex == currJavaMenuIndex) {
       
   250                         returnValue = i;
       
   251                         break;
       
   252                     }
       
   253 
       
   254                     currJavaMenuIndex++;
       
   255                 }
       
   256             }
       
   257         }
       
   258     }
       
   259 
       
   260     return returnValue;
       
   261 }
       
   262 
       
   263 - (void) nativeAddMenuAtIndex_OnAppKitThread:(NSArray *)args {
       
   264     AWT_ASSERT_APPKIT_THREAD;
       
   265     CMenu *theNewMenu = (CMenu*)[args objectAtIndex:0];
       
   266     jint index = [(NSNumber*)[args objectAtIndex:1] intValue];
       
   267     NSApplication *theApp = [NSApplication sharedApplication];
       
   268     NSMenu *theMainMenu = [theApp mainMenu];
       
   269     NSMenu *menuToAdd = [theNewMenu menu];
       
   270 
       
   271     if ([theMainMenu indexOfItemWithSubmenu:menuToAdd] == -1) {
       
   272         NSMenuItem *newItem = [[NSMenuItem alloc] init];
       
   273         [newItem setSubmenu:[theNewMenu menu]];
       
   274         [newItem setTitle:[[theNewMenu menu] title]];
       
   275 
       
   276         NSInteger nsMenuIndex = [self javaIndexToNSMenuIndex_OnAppKitThread:index];
       
   277 
       
   278         if (nsMenuIndex == -1) {
       
   279             [theMainMenu addItem:newItem];
       
   280         } else {
       
   281             [theMainMenu insertItem:newItem atIndex:nsMenuIndex];
       
   282         }
       
   283 
       
   284         BOOL newEnabledState = [theNewMenu isEnabled] && !fModallyDisabled;
       
   285         [newItem setEnabled:newEnabledState];
       
   286         [newItem release];
       
   287     }
       
   288 }
       
   289 
       
   290 - (void) javaDeleteMenu: (jint)index {
       
   291     if (self == sActiveMenuBar) {
       
   292         [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES];
       
   293     }
       
   294 
       
   295     @synchronized(self) {
       
   296         CMenu *menuToRemove = [fMenuList objectAtIndex:index];
       
   297 
       
   298         if (menuToRemove == fHelpMenu) {
       
   299             [fHelpMenu release];
       
   300             fHelpMenu = nil;
       
   301         }
       
   302 
       
   303         [fMenuList removeObjectAtIndex:index];
       
   304     }
       
   305 }
       
   306 
       
   307 - (void) nativeDeleteMenu_OnAppKitThread:(id)indexObj {
       
   308     AWT_ASSERT_APPKIT_THREAD;
       
   309     NSApplication *theApp = [NSApplication sharedApplication];
       
   310     NSMenu *theMainMenu = [theApp mainMenu];
       
   311     jint menuToRemove = [(NSNumber *)indexObj intValue];
       
   312     NSInteger nsMenuToRemove = [self javaIndexToNSMenuIndex_OnAppKitThread:menuToRemove];
       
   313 
       
   314     if (nsMenuToRemove != -1) {
       
   315         [theMainMenu removeItemAtIndex:nsMenuToRemove];
       
   316     }
       
   317 }
       
   318 
       
   319 - (void) javaSetHelpMenu:(CMenu *)theMenu {
       
   320     @synchronized(self) {
       
   321         [theMenu retain];
       
   322         [fHelpMenu release];
       
   323         fHelpMenu = theMenu;
       
   324     }
       
   325 }
       
   326 
       
   327 + (void) addDefaultHelpMenu {
       
   328     AWT_ASSERT_APPKIT_THREAD;
       
   329 
       
   330     // Look for a help book tag. If it's there, add the help menu.
       
   331     @synchronized ([CMenuBar class]) {
       
   332         if (!sSetupHelpMenu) {
       
   333             if (sDefaultHelpMenu == nil) {
       
   334                 // If we are embedded, don't make a help menu.
       
   335                 // TODO(cpc): we don't have NSApplicationAWT yet...
       
   336                 //if (![NSApp isKindOfClass:[NSApplicationAWT class]]) {
       
   337                 //    sSetupHelpMenu = YES;
       
   338                 //    return;
       
   339                 //}
       
   340 
       
   341                 // If the developer specified a NIB, don't make a help menu.
       
   342                 // TODO(cpc): usingDefaultNib only defined on NSApplicationAWT
       
   343                 //if (![NSApp usingDefaultNib]) {
       
   344                 //    sSetupHelpMenu = YES;
       
   345                 //    return;
       
   346                 //}
       
   347 
       
   348             // TODO: not implemented
       
   349             }
       
   350 
       
   351             sSetupHelpMenu = YES;
       
   352         }
       
   353     }
       
   354 
       
   355     if (sDefaultHelpMenu) {
       
   356         NSMenu *theMainMenu = [NSApp mainMenu];
       
   357 
       
   358         if ([theMainMenu indexOfItemWithSubmenu:sDefaultHelpMenu] == -1) {
       
   359             // Since we're re-using this NSMenu, we need to clear its parent before
       
   360             // adding it to a new menu item, or else AppKit will complain.
       
   361             [sDefaultHelpMenu setSupermenu:nil];
       
   362 
       
   363             // Add the help menu to the main menu.
       
   364             NSMenuItem *newItem = [[NSMenuItem alloc] init];
       
   365             [newItem setSubmenu:sDefaultHelpMenu];
       
   366             [newItem setTitle:[sDefaultHelpMenu title]];
       
   367             [theMainMenu addItem:newItem];
       
   368 
       
   369             // Release it so the main menu owns it.
       
   370             [newItem release];
       
   371         }
       
   372     }
       
   373 }
       
   374 
       
   375 @end
       
   376 
       
   377 /*
       
   378  * Class:     sun_lwawt_macosx_CMenuBar
       
   379  * Method:    nativeCreateMenuBar
       
   380  * Signature: ()J
       
   381  */
       
   382 JNIEXPORT jlong JNICALL
       
   383 Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar
       
   384     (JNIEnv *env, jobject peer)
       
   385 {
       
   386     CMenuBar *aCMenuBar = nil;
       
   387     JNF_COCOA_ENTER(env);
       
   388 
       
   389     jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
       
   390 
       
   391     // We use an array here only to be able to get a return value
       
   392     NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil];
       
   393 
       
   394     [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenuBar alloc] withObject:args waitUntilDone:YES];
       
   395 
       
   396     aCMenuBar = (CMenuBar *)[args objectAtIndex: 0];
       
   397 
       
   398     if (aCMenuBar == nil) {
       
   399         return 0L;
       
   400     }
       
   401 
       
   402     // [args release];
       
   403 
       
   404     // A strange memory managment after that.
       
   405 
       
   406 
       
   407     JNF_COCOA_EXIT(env);
       
   408     return ptr_to_jlong(aCMenuBar);
       
   409 }
       
   410 
       
   411 /*
       
   412  * Class:     sun_lwawt_macosx_CMenuBar
       
   413  * Method:    nativeAddAtIndex
       
   414  * Signature: (JJI)V
       
   415  */
       
   416 JNIEXPORT void JNICALL
       
   417 Java_sun_lwawt_macosx_CMenuBar_nativeAddAtIndex
       
   418     (JNIEnv *env, jobject peer,
       
   419      jlong menuBarObject, jlong menuObject, jint index)
       
   420 {
       
   421     JNF_COCOA_ENTER(env);
       
   422     // Remove the specified item.
       
   423     [((CMenuBar *) jlong_to_ptr(menuBarObject)) javaAddMenu:(CMenu *) jlong_to_ptr(menuObject) atIndex:index];
       
   424     JNF_COCOA_EXIT(env);
       
   425 }
       
   426 
       
   427 /*
       
   428  * Class:     sun_lwawt_macosx_CMenuBar
       
   429  * Method:    nativeDelMenu
       
   430  * Signature: (JI)V
       
   431  */
       
   432 JNIEXPORT void JNICALL
       
   433 Java_sun_lwawt_macosx_CMenuBar_nativeDelMenu
       
   434     (JNIEnv *env, jobject peer, jlong menuBarObject, jint index)
       
   435 {
       
   436     JNF_COCOA_ENTER(env);
       
   437     // Remove the specified item.
       
   438     [((CMenuBar *) jlong_to_ptr(menuBarObject)) javaDeleteMenu: index];
       
   439     JNF_COCOA_EXIT(env);
       
   440 }
       
   441 
       
   442 /*
       
   443  * Class:     sun_lwawt_macosx_CMenuBar
       
   444  * Method:    nativeSetHelpMenu
       
   445  * Signature: (JJ)V
       
   446  */
       
   447 JNIEXPORT void JNICALL
       
   448 Java_sun_lwawt_macosx_CMenuBar_nativeSetHelpMenu
       
   449     (JNIEnv *env, jobject peer, jlong menuBarObject, jlong menuObject)
       
   450 {
       
   451     JNF_COCOA_ENTER(env);
       
   452     // Remove the specified item.
       
   453     [((CMenuBar *) jlong_to_ptr(menuBarObject)) javaSetHelpMenu: ((CMenu *)jlong_to_ptr(menuObject))];
       
   454     JNF_COCOA_EXIT(env);
       
   455 }