Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/native_NOTIOS/sun/awt/CMenuItem.m
38829 views
/*1* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#import <JavaNativeFoundation/JavaNativeFoundation.h>2627#import "CMenuItem.h"28#import "CMenu.h"29#import "AWTEvent.h"30#import "ThreadUtilities.h"3132#import "java_awt_Event.h"33#import "java_awt_event_KeyEvent.h"34#import "sun_lwawt_macosx_CMenuItem.h"3536#define NOT_A_CHECKBOXMENU -2373839@implementation CMenuItem4041- (id) initWithPeer:(jobject)peer asSeparator: (BOOL) asSeparator{42AWT_ASSERT_APPKIT_THREAD;43self = [super initWithPeer:peer];44if (self) {45if (asSeparator) {46fMenuItem = (NSMenuItem*)[NSMenuItem separatorItem];47[fMenuItem retain];48} else {49fMenuItem = [[NSMenuItem alloc] init];50[fMenuItem setAction:@selector(handleAction:)];51[fMenuItem setTarget:self];52}53fIsCheckbox = NO;54fIsEnabled = YES;55}56return self;57}5859// This is because NSApplication doesn't check the target's window when sending60// actions; they only check the target itself. We always return YES,61// since we shouldn't even be installed unless our window is active.62- (BOOL) worksWhenModal {63return YES;64}6566// Events67- (void)handleAction:(NSMenuItem *)sender {68AWT_ASSERT_APPKIT_THREAD;69JNIEnv *env = [ThreadUtilities getJNIEnv];70JNF_COCOA_ENTER(env);7172// If we are called as a result of user pressing a shortcut, do nothing,73// because AVTView has already sent corresponding key event to the Java74// layer from performKeyEquivalent.75// There is an exception from the rule above, though: if a window with76// a menu gets minimized by user and there are no other windows to take77// focus, the window's menu won't be removed from the global menu bar.78// However, the Java layer won't handle invocation by a shortcut coming79// from this "frameless" menu, because there are no active windows. This80// means we have to handle it here.81NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent];82if ([currEvent type] == NSKeyDown) {83NSString *menuKey = [sender keyEquivalent];84NSString *eventKey = [currEvent charactersIgnoringModifiers];8586// Apple uses characters from private Unicode range for some of the87// keys, so we need to do the same translation here that we do88// for the regular key down events89if ([eventKey length] == 1) {90unichar origChar = [eventKey characterAtIndex:0];91unichar newChar = NsCharToJavaChar(origChar, 0);92if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) {93newChar = origChar;94}9596eventKey = [NSString stringWithCharacters: &newChar length: 1];97}9899NSWindow *keyWindow = [NSApp keyWindow];100if ([menuKey isEqualToString:eventKey] && keyWindow != nil) {101return;102}103}104105if (fIsCheckbox) {106static JNF_CLASS_CACHE(jc_CCheckboxMenuItem, "sun/lwawt/macosx/CCheckboxMenuItem");107static JNF_MEMBER_CACHE(jm_ckHandleAction, jc_CCheckboxMenuItem, "handleAction", "(Z)V");108109// Send the opposite of what's currently checked -- the action110// indicates what state we're going to.111NSInteger state = [sender state];112jboolean newState = (state == NSOnState ? JNI_FALSE : JNI_TRUE);113JNFCallVoidMethod(env, fPeer, jm_ckHandleAction, newState);114} else {115static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");116static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)117118NSUInteger modifiers = [currEvent modifierFlags];119jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);120121JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)122}123JNF_COCOA_EXIT(env);124}125126- (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {127128NSUInteger modifierMask = 0;129130if (![theKeyEquivalent isEqualToString:@""]) {131// Force the key equivalent to lower case if not using the shift key.132// Otherwise AppKit will draw a Shift glyph in the menu.133if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) == 0) {134theKeyEquivalent = [theKeyEquivalent lowercaseString];135}136137// Hack for the question mark -- SHIFT and / means use the question mark.138if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) != 0 &&139[theKeyEquivalent isEqualToString:@"/"])140{141theKeyEquivalent = @"?";142modifiers &= ~java_awt_event_KeyEvent_SHIFT_MASK;143}144145modifierMask = JavaModifiersToNsKeyModifiers(modifiers, NO);146}147148[ThreadUtilities performOnMainThreadWaiting:YES block:^(){149[fMenuItem setKeyEquivalent:theKeyEquivalent];150[fMenuItem setKeyEquivalentModifierMask:modifierMask];151[fMenuItem setTitle:theLabel];152}];153}154155- (void) setJavaImage:(NSImage *)theImage {156157[ThreadUtilities performOnMainThreadWaiting:NO block:^(){158[fMenuItem setImage:theImage];159}];160}161162- (void) setJavaToolTipText:(NSString *)theText {163164[ThreadUtilities performOnMainThreadWaiting:NO block:^(){165[fMenuItem setToolTip:theText];166}];167}168169170- (void)setJavaEnabled:(BOOL) enabled {171172[ThreadUtilities performOnMainThreadWaiting:NO block:^(){173@synchronized(self) {174fIsEnabled = enabled;175176// Warning: This won't work if the parent menu is disabled.177// See [CMenu syncFromJava]. We still need to call it here so178// the NSMenuItem itself gets properly updated.179[fMenuItem setEnabled:fIsEnabled];180}181}];182}183184- (BOOL)isEnabled {185186BOOL enabled = NO;187@synchronized(self) {188enabled = fIsEnabled;189}190return enabled;191}192193194- (void)setJavaState:(BOOL)newState {195196[ThreadUtilities performOnMainThreadWaiting:NO block:^(){197[fMenuItem setState:(newState ? NSOnState : NSOffState)];198}];199}200201- (void)dealloc {202[fMenuItem setAction:NULL];203[fMenuItem setTarget:nil];204[fMenuItem release];205fMenuItem = nil;206207[super dealloc];208}209210- (void)addNSMenuItemToMenu:(NSMenu *)inMenu {211[inMenu addItem:fMenuItem];212}213214- (NSMenuItem *)menuItem {215return [[fMenuItem retain] autorelease];216}217218- (void)setIsCheckbox {219fIsCheckbox = YES;220}221222- (NSString *)description {223return [NSString stringWithFormat:@"CMenuItem[ %@ ]", fMenuItem];224}225226@end227228/** Convert a Java keycode for SetMenuItemCmd */229static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) {230unichar macKey = 0;231232if ((awtKey >= java_awt_event_KeyEvent_VK_0 && awtKey <= java_awt_event_KeyEvent_VK_9) ||233(awtKey >= java_awt_event_KeyEvent_VK_A && awtKey <= java_awt_event_KeyEvent_VK_Z))234{235// These ranges are the same in ASCII236macKey = awtKey;237} else if (awtKey >= java_awt_event_KeyEvent_VK_F1 && awtKey <= java_awt_event_KeyEvent_VK_F12) {238// Support for F1 - F12 has been around since Java 1.0 and fall into a lower range.239macKey = awtKey - java_awt_event_KeyEvent_VK_F1 + NSF1FunctionKey;240} else if (awtKey >= java_awt_event_KeyEvent_VK_F13 && awtKey <= java_awt_event_KeyEvent_VK_F24) {241// Support for F13-F24 came in Java 1.2 and are at a different range.242macKey = awtKey - java_awt_event_KeyEvent_VK_F13 + NSF13FunctionKey;243} else {244// Special characters245switch (awtKey) {246case java_awt_event_KeyEvent_VK_BACK_QUOTE : macKey = '`'; break;247case java_awt_event_KeyEvent_VK_QUOTE : macKey = '\''; break;248249case java_awt_event_KeyEvent_VK_ESCAPE : macKey = 0x1B; break;250// case java_awt_event_KeyEvent_VK_SPACE : macKey = kMenuSpaceGlyph; break;251case java_awt_event_KeyEvent_VK_PAGE_UP : macKey = NSPageUpFunctionKey; break;252case java_awt_event_KeyEvent_VK_PAGE_DOWN : macKey = NSPageDownFunctionKey; break;253case java_awt_event_KeyEvent_VK_END : macKey = NSEndFunctionKey; break;254case java_awt_event_KeyEvent_VK_HOME : macKey = NSHomeFunctionKey; break;255256case java_awt_event_KeyEvent_VK_LEFT : macKey = NSLeftArrowFunctionKey; break;257case java_awt_event_KeyEvent_VK_UP : macKey = NSUpArrowFunctionKey; break;258case java_awt_event_KeyEvent_VK_RIGHT : macKey = NSRightArrowFunctionKey; break;259case java_awt_event_KeyEvent_VK_DOWN : macKey = NSDownArrowFunctionKey; break;260261case java_awt_event_KeyEvent_VK_COMMA : macKey = ','; break;262263// Mac OS doesn't distinguish between the two '-' keys...264case java_awt_event_KeyEvent_VK_MINUS :265case java_awt_event_KeyEvent_VK_SUBTRACT : macKey = '-'; break;266267// or the two '.' keys...268case java_awt_event_KeyEvent_VK_DECIMAL :269case java_awt_event_KeyEvent_VK_PERIOD : macKey = '.'; break;270271// or the two '/' keys.272case java_awt_event_KeyEvent_VK_DIVIDE :273case java_awt_event_KeyEvent_VK_SLASH : macKey = '/'; break;274275case java_awt_event_KeyEvent_VK_SEMICOLON : macKey = ';'; break;276case java_awt_event_KeyEvent_VK_EQUALS : macKey = '='; break;277278case java_awt_event_KeyEvent_VK_OPEN_BRACKET : macKey = '['; break;279case java_awt_event_KeyEvent_VK_BACK_SLASH : macKey = '\\'; break;280case java_awt_event_KeyEvent_VK_CLOSE_BRACKET : macKey = ']'; break;281282case java_awt_event_KeyEvent_VK_MULTIPLY : macKey = '*'; break;283case java_awt_event_KeyEvent_VK_ADD : macKey = '+'; break;284285case java_awt_event_KeyEvent_VK_HELP : macKey = NSHelpFunctionKey; break;286case java_awt_event_KeyEvent_VK_TAB : macKey = NSTabCharacter; break;287case java_awt_event_KeyEvent_VK_ENTER : macKey = NSNewlineCharacter; break;288case java_awt_event_KeyEvent_VK_BACK_SPACE : macKey = NSBackspaceCharacter; break;289case java_awt_event_KeyEvent_VK_DELETE : macKey = NSDeleteCharacter; break;290case java_awt_event_KeyEvent_VK_CLEAR : macKey = NSClearDisplayFunctionKey; break;291case java_awt_event_KeyEvent_VK_AMPERSAND : macKey = '&'; break;292case java_awt_event_KeyEvent_VK_ASTERISK : macKey = '*'; break;293case java_awt_event_KeyEvent_VK_QUOTEDBL : macKey = '\"'; break;294case java_awt_event_KeyEvent_VK_LESS : macKey = '<'; break;295case java_awt_event_KeyEvent_VK_GREATER : macKey = '>'; break;296case java_awt_event_KeyEvent_VK_BRACELEFT : macKey = '{'; break;297case java_awt_event_KeyEvent_VK_BRACERIGHT : macKey = '}'; break;298case java_awt_event_KeyEvent_VK_AT : macKey = '@'; break;299case java_awt_event_KeyEvent_VK_COLON : macKey = ':'; break;300case java_awt_event_KeyEvent_VK_CIRCUMFLEX : macKey = '^'; break;301case java_awt_event_KeyEvent_VK_DOLLAR : macKey = '$'; break;302case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break;303case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break;304case java_awt_event_KeyEvent_VK_NUMBER_SIGN : macKey = '#'; break;305case java_awt_event_KeyEvent_VK_PLUS : macKey = '+'; break;306case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break;307case java_awt_event_KeyEvent_VK_UNDERSCORE : macKey = '_'; break;308}309}310return macKey;311}312313/*314* Class: sun_lwawt_macosx_CMenuItem315* Method: nativeSetLabel316* Signature: (JLjava/lang/String;CII)V317*/318JNIEXPORT void JNICALL319Java_sun_lwawt_macosx_CMenuItem_nativeSetLabel320(JNIEnv *env, jobject peer,321jlong menuItemObj, jstring label,322jchar shortcutKey, jint shortcutKeyCode, jint mods)323{324JNF_COCOA_ENTER(env);325NSString *theLabel = JNFJavaToNSString(env, label);326NSString *theKeyEquivalent = nil;327unichar macKey = shortcutKey;328329if (macKey == 0) {330macKey = AWTKeyToMacShortcut(shortcutKeyCode, (mods & java_awt_event_KeyEvent_SHIFT_MASK) != 0);331}332333if (macKey != 0) {334unichar equivalent[1] = {macKey};335theKeyEquivalent = [NSString stringWithCharacters:equivalent length:1];336} else {337theKeyEquivalent = @"";338}339340[((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods];341JNF_COCOA_EXIT(env);342}343344/*345* Class: sun_lwawt_macosx_CMenuItem346* Method: nativeSetTooltip347* Signature: (JLjava/lang/String;)V348*/349JNIEXPORT void JNICALL350Java_sun_lwawt_macosx_CMenuItem_nativeSetTooltip351(JNIEnv *env, jobject peer, jlong menuItemObj, jstring tooltip)352{353JNF_COCOA_ENTER(env);354NSString *theTooltip = JNFJavaToNSString(env, tooltip);355[((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaToolTipText:theTooltip];356JNF_COCOA_EXIT(env);357}358359/*360* Class: sun_lwawt_macosx_CMenuItem361* Method: nativeSetImage362* Signature: (JJ)V363*/364JNIEXPORT void JNICALL365Java_sun_lwawt_macosx_CMenuItem_nativeSetImage366(JNIEnv *env, jobject peer, jlong menuItemObj, jlong image)367{368JNF_COCOA_ENTER(env);369[((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaImage:(NSImage*)jlong_to_ptr(image)];370JNF_COCOA_EXIT(env);371}372373/*374* Class: sun_lwawt_macosx_CMenuItem375* Method: nativeCreate376* Signature: (JZ)J377*/378JNIEXPORT jlong JNICALL379Java_sun_lwawt_macosx_CMenuItem_nativeCreate380(JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator)381{382383__block CMenuItem *aCMenuItem = nil;384BOOL asSeparator = (isSeparator == JNI_TRUE) ? YES: NO;385CMenu *parentCMenu = (CMenu *)jlong_to_ptr(parentCMenuObj);386JNF_COCOA_ENTER(env);387388jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);389390[ThreadUtilities performOnMainThreadWaiting:YES block:^(){391aCMenuItem = [[CMenuItem alloc] initWithPeer: cPeerObjGlobal392asSeparator: asSeparator];393// the CMenuItem is released in CMenuComponent.dispose()394}];395396if (aCMenuItem == nil) {397return 0L;398}399400// and add it to the parent item.401[parentCMenu addJavaMenuItem: aCMenuItem];402403// setLabel will be called after creation completes.404405JNF_COCOA_EXIT(env);406return ptr_to_jlong(aCMenuItem);407}408409/*410* Class: sun_lwawt_macosx_CMenuItem411* Method: nativeSetEnabled412* Signature: (JZ)V413*/414JNIEXPORT void JNICALL415Java_sun_lwawt_macosx_CMenuItem_nativeSetEnabled416(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable)417{418JNF_COCOA_ENTER(env);419CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);420[item setJavaEnabled: (enable == JNI_TRUE)];421JNF_COCOA_EXIT(env);422}423424/*425* Class: sun_lwawt_macosx_CCheckboxMenuItem426* Method: nativeSetState427* Signature: (IZ)V428*/429JNIEXPORT void JNICALL430Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetState431(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean state)432{433JNF_COCOA_ENTER(env);434CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);435[item setJavaState: (state == JNI_TRUE)];436JNF_COCOA_EXIT(env);437}438439/*440* Class: sun_lwawt_macosx_CCheckboxMenuItem441* Method: nativeSetState442* Signature: (IZ)V443*/444JNIEXPORT void JNICALL445Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetIsCheckbox446(JNIEnv *env, jobject peer, jlong menuItemObj)447{448JNF_COCOA_ENTER(env);449CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);450[item setIsCheckbox];451JNF_COCOA_EXIT(env);452}453454455