1/* 2 * Copyright (c) 2011, 2012, 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 "ScreenMenu.h" 27 28#import "com_apple_laf_ScreenMenu.h" 29#import "java_awt_Event.h" 30#import "java_awt_event_KeyEvent.h" 31#import "java_awt_event_InputEvent.h" 32#import "java_awt_event_MouseEvent.h" 33 34#import <JavaNativeFoundation/JavaNativeFoundation.h> 35#import <JavaRuntimeSupport/JavaRuntimeSupport.h> 36 37#import "ThreadUtilities.h" 38#import "CMenuBar.h" 39 40/* Use THIS_FILE when it is available. */ 41#ifndef THIS_FILE 42 #define THIS_FILE __FILE__ 43#endif 44 45static JNF_CLASS_CACHE(sjc_ScreenMenu, "com/apple/laf/ScreenMenu"); 46 47static jint ns2awtModifiers(NSUInteger keyMods) { 48 jint result = 0; 49 if (keyMods & NSShiftKeyMask) result |= java_awt_Event_SHIFT_MASK; 50 if (keyMods & NSControlKeyMask) result |= java_awt_Event_CTRL_MASK; 51 if (keyMods & NSAlternateKeyMask) result |= java_awt_Event_ALT_MASK; 52 if (keyMods & NSCommandKeyMask) result |= java_awt_Event_META_MASK; 53 return result; 54} 55 56static jint ns2awtMouseButton(NSInteger mouseButton) { 57 switch (mouseButton) { 58 case 1: return java_awt_event_InputEvent_BUTTON1_MASK; 59 case 2: return java_awt_event_InputEvent_BUTTON2_MASK; 60 case 3: return java_awt_event_InputEvent_BUTTON3_MASK; 61 } 62 return 0; 63} 64 65 66@interface NativeToJavaDelegate : NSObject <JRSMenuDelegate, NSMenuDelegate> 67{ 68@public 69 NSMenu *nsmenu; 70 JNFJObjectWrapper *javaObjectWrapper; 71} 72 73@property (nonatomic, retain) NSMenu *nsmenu; 74@property (nonatomic, retain) JNFJObjectWrapper *javaObjectWrapper; 75 76- (id)initFromMenu:(NSMenu *)menu javaObj:(JNFJObjectWrapper *)obj; 77- (NSMenu*)menu; 78@end 79 80 81@implementation NativeToJavaDelegate 82 83@synthesize nsmenu; 84@synthesize javaObjectWrapper; 85 86- (id)initFromMenu:(NSMenu *)aMenu javaObj:(JNFJObjectWrapper *)obj 87{ 88 self = [super init]; 89 if (self) { 90 self.nsmenu = aMenu; 91 self.javaObjectWrapper = obj; 92 } 93 return self; 94} 95 96- (NSMenu *)menu { 97 return self.nsmenu; 98} 99 100- (void)menuWillOpen:(NSMenu *)menu 101{ 102 if (self.javaObjectWrapper == nil) { 103#ifdef DEBUG 104 NSLog(@"_javaObject is NULL: (%s - %s : %d)", THIS_FILE, __FUNCTION__, __LINE__); 105#endif 106 return; 107 } 108 109 JNIEnv *env = [ThreadUtilities getJNIEnv]; 110JNF_COCOA_ENTER(env); 111 //NSLog(@"menuWillOpen %@", [menu title]); 112 static JNF_MEMBER_CACHE(jm_ScreenMenu_invokeOpenLater, sjc_ScreenMenu, "invokeOpenLater", "()V"); 113 JNFCallVoidMethod(env, [self.javaObjectWrapper jObject], jm_ScreenMenu_invokeOpenLater); // AWT_THREADING Safe (AWTRunLoopMode) 114JNF_COCOA_EXIT(env); 115 116} 117 118- (void)menuDidClose:(NSMenu *)menu 119{ 120 if (self.javaObjectWrapper == nil) { 121#ifdef DEBUG 122 NSLog(@"_javaObject is NULL: (%s - %s : %d)", THIS_FILE, __FUNCTION__, __LINE__); 123#endif 124 return; 125 } 126 127 JNIEnv *env = [ThreadUtilities getJNIEnv]; 128JNF_COCOA_ENTER(env); 129 //NSLog(@"menuDidClose %@", [menu title]); 130 static JNF_MEMBER_CACHE(jm_ScreenMenu_invokeMenuClosing, sjc_ScreenMenu, "invokeMenuClosing", "()V"); 131 JNFCallVoidMethod(env, [self.javaObjectWrapper jObject], jm_ScreenMenu_invokeMenuClosing); // AWT_THREADING Safe (AWTRunLoopMode) 132JNF_COCOA_EXIT(env); 133} 134 135 136- (void)handleJavaMenuItemTargetedAtIndex:(NSUInteger)menuIndex rect:(NSRect)rect 137{ 138 if (self.javaObjectWrapper == nil) { 139#ifdef DEBUG 140 NSLog(@"_javaObject is NULL: (%s - %s : %d)", THIS_FILE, __FUNCTION__, __LINE__); 141#endif 142 return; 143 } 144 145 JNIEnv *env = [ThreadUtilities getJNIEnv]; 146JNF_COCOA_ENTER(env); 147 // Send that to Java so we can test which item was hit. 148 static JNF_MEMBER_CACHE(jm_ScreenMenu_updateSelectedItem, sjc_ScreenMenu, "handleItemTargeted", "(IIIII)V"); 149 JNFCallVoidMethod(env, [self.javaObjectWrapper jObject], jm_ScreenMenu_updateSelectedItem, menuIndex, 150 NSMinY(rect), NSMinX(rect), NSMaxY(rect), NSMaxX(rect)); // AWT_THREADING Safe (AWTRunLoopMode) 151 152JNF_COCOA_EXIT(env); 153} 154 155 156// Called from event handler callback 157- (void)handleJavaMouseEvent:(NSEvent *)event 158{ 159 NSInteger kind = [event type]; 160 jint javaKind = 0; 161 162 switch (kind) { 163 case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: 164 javaKind = java_awt_event_MouseEvent_MOUSE_RELEASED; 165 break; 166 case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: 167 javaKind = java_awt_event_MouseEvent_MOUSE_PRESSED; 168 break; 169 case NSMouseMoved: 170 javaKind = java_awt_event_MouseEvent_MOUSE_MOVED; 171 break; 172 case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: 173 javaKind = java_awt_event_MouseEvent_MOUSE_DRAGGED; 174 break; 175 } 176 177 // Get the coordinates of the mouse in global coordinates (must be global, since our tracking rects are global.) 178 NSPoint globalPoint = [event locationInWindow]; 179 jint javaX = globalPoint.x; 180 jint javaY = globalPoint.y; 181 182 // Convert the event modifiers into Java modifiers 183 jint javaModifiers = ns2awtModifiers([event modifierFlags]) | ns2awtMouseButton([event buttonNumber]); 184 185 // Get the event time 186 jlong javaWhen = JNFNSTimeIntervalToJavaMillis([event timestamp]); 187 188 // Call the mouse event handler, which will generate Java mouse events. 189 JNIEnv *env = [ThreadUtilities getJNIEnv]; 190JNF_COCOA_ENTER(env); 191 static JNF_MEMBER_CACHE(jm_ScreenMenu_handleMouseEvent, sjc_ScreenMenu, "handleMouseEvent", "(IIIIJ)V"); 192 JNFCallVoidMethod(env, [self.javaObjectWrapper jObject], jm_ScreenMenu_handleMouseEvent, javaKind, javaX, javaY, javaModifiers, javaWhen); // AWT_THREADING Safe (AWTRunLoopMode) 193JNF_COCOA_EXIT(env); 194} 195 196@end 197 198 199/* 200 * Class: com_apple_laf_ScreenMenu 201 * Method: addMenuListeners 202 * Signature: (Lcom/apple/laf/ScreenMenu;J[J)V 203 */ 204JNIEXPORT jlong JNICALL Java_com_apple_laf_ScreenMenu_addMenuListeners 205(JNIEnv *env, jclass clz, jobject listener, jlong nativeMenu) 206{ 207 NativeToJavaDelegate *delegate = nil; 208 209JNF_COCOA_ENTER(env); 210 211 JNFJObjectWrapper *wrapper = [JNFJObjectWrapper wrapperWithJObject:listener withEnv:env]; 212 NSMenu *menu = jlong_to_ptr(nativeMenu); 213 214 delegate = [[[NativeToJavaDelegate alloc] initFromMenu:menu javaObj:wrapper] autorelease]; 215 CFRetain(delegate); // GC 216 217 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^{ 218 NSMenu *menu = delegate.nsmenu; 219 if ([menu isJavaMenu]) { 220 [menu setDelegate:delegate]; 221 [menu setJavaMenuDelegate:delegate]; 222 } 223 }]; 224 225JNF_COCOA_EXIT(env); 226 227 return ptr_to_jlong(delegate); 228} 229 230/* 231 * Class: com_apple_laf_ScreenMenu 232 * Method: removeMenuListeners 233 * Signature: (JJ)V 234 */ 235JNIEXPORT void JNICALL Java_com_apple_laf_ScreenMenu_removeMenuListeners 236(JNIEnv *env, jclass clz, jlong fModelPtr) 237{ 238 if (fModelPtr == 0L) return; 239 240JNF_COCOA_ENTER(env); 241 242 NativeToJavaDelegate *delegate = (NativeToJavaDelegate *)jlong_to_ptr(fModelPtr); 243 244 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^{ 245 NSMenu *menu = delegate.nsmenu; 246 [menu setJavaMenuDelegate:nil]; 247 [menu setDelegate:nil]; 248 delegate.nsmenu = nil; 249 delegate.javaObjectWrapper = nil; 250 }]; 251 252 CFRelease(delegate); // GC 253 254JNF_COCOA_EXIT(env); 255} 256