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 "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 45 static JNF_CLASS_CACHE(sjc_ScreenMenu, "com/apple/laf/ScreenMenu"); 46 47 static 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 56 static 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]; 110 JNF_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) 114 JNF_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]; 128 JNF_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) 132 JNF_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]; 146 JNF_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 152 JNF_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]; 190 JNF_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) 193 JNF_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 */ 204 JNIEXPORT jlong JNICALL Java_com_apple_laf_ScreenMenu_addMenuListeners 205 (JNIEnv *env, jclass clz, jobject listener, jlong nativeMenu) 206 { 207 NativeToJavaDelegate *delegate = nil; 208 209 JNF_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 225 JNF_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 */ 235 JNIEXPORT void JNICALL Java_com_apple_laf_ScreenMenu_removeMenuListeners 236 (JNIEnv *env, jclass clz, jlong fModelPtr) 237 { 238 if (fModelPtr == 0L) return; 239 240 JNF_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 254 JNF_COCOA_EXIT(env); 255 }