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