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 "common.h" 27 #import "com_sun_glass_events_mac_NpapiEvent.h" 28 #import "com_sun_glass_ui_Window.h" 29 #import "com_sun_glass_ui_mac_MacWindow.h" 30 31 #import "GlassMacros.h" 32 #import "GlassEmbeddedWindow+Npapi.h" 33 #import "GlassNSEvent.h" 34 #import "GlassHelper.h" 35 36 //#define VERBOSE 37 #ifndef VERBOSE 38 #define LOG(MSG, ...) 39 #else 40 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 41 #endif 42 43 #pragma mark --- Internal utilities 44 45 inline GlassEmbeddedWindow *getGlassEmbeddedWindow(JNIEnv *env, jlong jPtr) 46 { 47 if (jPtr != 0L) 48 { 49 return (GlassEmbeddedWindow*)jlong_to_ptr(jPtr); 50 } 51 else 52 { 53 return nil; 54 } 55 } 56 57 #pragma mark --- GlassEmbeddedWindow (Npapi) 58 59 @implementation GlassEmbeddedWindow (Npapi) 60 61 @end 62 63 #pragma mark --- Java APIs 64 65 /* 66 * Class: com_sun_glass_events_mac_NpapiEvent 67 * Method: _dispatchCocoaNpapiDrawEvent 68 * Signature: (JIJDDDD)V 69 */ 70 JNIEXPORT void JNICALL Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiDrawEvent 71 (JNIEnv *env, jclass jNpapiClass, jlong jPtr, jint jType, jlong jContext, jdouble jX, jdouble jY, jdouble jWidth, jdouble jHeight) 72 { 73 LOG("Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiDrawEvent"); 74 75 // NOP, we use layer based architecture, so we will never get draw event 76 NSLog(@"WARNING: GlassEmbeddedWindow+Npapi received _dispatchCocoaNpapiDrawEvent"); 77 } 78 79 /* 80 * Class: com_sun_glass_events_mac_NpapiEvent 81 * Method: _dispatchCocoaNpapiMouseEvent 82 * Signature: (JIIDDIIDDD)V 83 */ 84 JNIEXPORT void JNICALL Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiMouseEvent 85 (JNIEnv *env, jclass jNpapiClass, jlong jPtr, jint jType, jint jModifierFlags, jdouble jPluginX, jdouble jPluginY, jint jButtonNumber, jint jClickCount, jdouble jDeltaX, jdouble jDeltaY, jdouble jDeltaZ) 86 { 87 LOG("Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiMouseEvent"); 88 89 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 90 GLASS_POOL_ENTER; 91 { 92 GlassEmbeddedWindow *window = getGlassEmbeddedWindow(env, jPtr); 93 if ((window != nil) && (window->child != nil)) 94 { 95 NSEventType type = 0; 96 switch (jType) 97 { 98 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseEntered: 99 LOG(" NSMouseEntered"); 100 type = NSMouseEntered; 101 break; 102 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseExited: 103 LOG(" NSMouseExited"); 104 type = NSMouseExited; 105 break; 106 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseDown: 107 LOG(" NSLeftMouseDown"); 108 if (jButtonNumber == 0) { 109 type = NSLeftMouseDown; 110 } else if (jButtonNumber == 1) { 111 type = NSRightMouseDown; 112 } else { 113 type = NSOtherMouseDown; 114 } 115 break; 116 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseUp: 117 LOG(" NSLeftMouseUp"); 118 if (jButtonNumber == 0) { 119 type = NSLeftMouseUp; 120 } else if (jButtonNumber == 1) { 121 type = NSRightMouseUp; 122 } else { 123 type = NSOtherMouseUp; 124 } 125 break; 126 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseDragged: 127 LOG(" NSLeftMouseDragged"); 128 if (jButtonNumber == 0) { 129 type = NSLeftMouseDragged; 130 } else if (jButtonNumber == 1) { 131 type = NSRightMouseDragged; 132 } else { 133 type = NSOtherMouseDragged; 134 } 135 break; 136 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventMouseMoved: 137 LOG(" NSMouseMoved"); 138 type = NSMouseMoved; 139 break; 140 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventScrollWheel: 141 LOG(" NSScrollWheel"); 142 type = NSScrollWheel; 143 break; 144 } 145 146 NSEvent *event = nil; 147 jdouble windowY = [window->child frame].size.height - jPluginY; 148 if ((type == NSMouseEntered) || (type == NSMouseExited)) 149 { 150 event = [NSEvent enterExitEventWithType:type 151 location:NSMakePoint((CGFloat)jPluginX, (CGFloat)windowY) 152 modifierFlags:(NSUInteger)jModifierFlags 153 timestamp:[NSDate timeIntervalSinceReferenceDate] 154 windowNumber:[window->child windowNumber] 155 context:nil 156 eventNumber:0 157 trackingNumber:0 158 userData:nil]; 159 [event setValue:window->child forKey:@"window"]; 160 LOG(" NPAPI mouse event: %s", [[event description] UTF8String]); 161 } else if (type != NSScrollWheel) { 162 NSPoint eventPoint = NSMakePoint((CGFloat)jPluginX, (CGFloat)windowY); 163 event = [NSEvent mouseEventWithType:type 164 location:eventPoint 165 modifierFlags:(NSUInteger)jModifierFlags 166 timestamp:[NSDate timeIntervalSinceReferenceDate] 167 windowNumber:[window->child windowNumber] 168 context:nil 169 eventNumber:0 170 clickCount:jClickCount 171 pressure:0.0f]; 172 [event setValue:window->child forKey:@"window"]; 173 LOG(" NPAPI mouse event: %s", [[event description] UTF8String]); 174 } 175 else 176 { 177 CGEventRef scrollEvent = CGEventCreateScrollWheelEvent 178 (NULL, kCGScrollEventUnitPixel, 3, (int)jDeltaY, (int)jDeltaX, (int)jDeltaZ); 179 event = [NSEvent eventWithCGEvent:scrollEvent]; 180 NSValue *location = [NSValue valueWithPoint:NSMakePoint((CGFloat)jPluginX, (CGFloat)windowY)]; 181 [event setValue:location forKey:@"location"]; 182 [event setValue:[NSNumber numberWithInteger:[window->child windowNumber]] forKey:@"windowNumber"]; 183 } 184 185 if (event != nil) 186 { 187 [window->child sendEvent:event]; 188 } 189 } 190 } 191 GLASS_POOL_EXIT; 192 GLASS_CHECK_EXCEPTION(env); 193 } 194 195 /* 196 * Class: com_sun_glass_events_mac_NpapiEvent 197 * Method: _dispatchCocoaNpapiKeyEvent 198 * Signature: (JIILjava/lang/String;Ljava/lang/String;ZI)V 199 */ 200 JNIEXPORT void JNICALL Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiKeyEvent 201 (JNIEnv *env, jclass jNpapiClass, jlong jPtr, jint jType, jint jModifierFlags, jstring jCharacters, 202 jstring jCharactersIgnoringModifiers, jboolean jIsrepeat, jint jKeyCode, jboolean jNeedsKeyTyped) 203 { 204 LOG("Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiKeyEvent"); 205 206 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 207 GLASS_POOL_ENTER; 208 { 209 GlassEmbeddedWindow *window = getGlassEmbeddedWindow(env, jPtr); 210 if ((window != nil) && (window->child != nil)) 211 { 212 NSEventType type = 0; 213 switch (jType) 214 { 215 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventKeyDown: 216 type = NSKeyDown; 217 break; 218 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventKeyUp: 219 type = NSKeyUp; 220 break; 221 case com_sun_glass_events_mac_NpapiEvent_NPCocoaEventFlagsChanged: 222 type = NSFlagsChanged; 223 break; 224 } 225 226 GlassNSEvent *event = (GlassNSEvent *)[GlassNSEvent keyEventWithType:type 227 location:NSMakePoint(0.0, 0.0) 228 modifierFlags:(NSUInteger)jModifierFlags 229 timestamp:[NSDate timeIntervalSinceReferenceDate] 230 windowNumber:[window->child windowNumber] 231 context:nil 232 characters:[GlassHelper nsStringWithJavaString:jCharacters withEnv:env] 233 charactersIgnoringModifiers:[GlassHelper nsStringWithJavaString:jCharactersIgnoringModifiers 234 withEnv:env] 235 isARepeat:(jIsrepeat==JNI_TRUE) 236 keyCode:(unsigned short)jKeyCode]; 237 LOG(" NPAPI key event: %s", [[event description] UTF8String]); 238 if (event != nil) 239 { 240 [event setNeedsKeyTyped:(jNeedsKeyTyped==JNI_TRUE)]; 241 [window->child sendEvent:event]; 242 } 243 } 244 } 245 GLASS_POOL_EXIT; 246 GLASS_CHECK_EXCEPTION(env); 247 } 248 249 /* 250 * Class: com_sun_glass_events_mac_NpapiEvent 251 * Method: _dispatchCocoaNpapiFocusEvent 252 * Signature: (JIZ)V 253 */ 254 JNIEXPORT void JNICALL Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiFocusEvent 255 (JNIEnv *env, jclass jNpapiClass, jlong jPtr, jint jType, jboolean jHasFocus) 256 { 257 LOG("Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiFocusEvent"); 258 LOG(" jPtr: %p", jPtr); 259 LOG(" jHasFocus: %d", jHasFocus); 260 261 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 262 GLASS_POOL_ENTER; 263 { 264 GlassEmbeddedWindow *window = getGlassEmbeddedWindow(env, jPtr); 265 if ((window != nil) && (window->child != nil)) 266 { 267 if (jHasFocus == JNI_TRUE) 268 { 269 [window->child performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:NO]; 270 } 271 else 272 { 273 [window->child performSelectorOnMainThread:@selector(resignKeyWindow) withObject:nil waitUntilDone:NO]; 274 } 275 } 276 } 277 GLASS_POOL_EXIT; 278 GLASS_CHECK_EXCEPTION(env); 279 } 280 281 /* 282 * Class: com_sun_glass_events_mac_NpapiEvent 283 * Method: _dispatchCocoaNpapiTextInputEvent 284 * Signature: (JILjava/lang/String;)V 285 */ 286 JNIEXPORT void JNICALL Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiTextInputEvent 287 (JNIEnv *env, jclass jNpapiClass, jlong jPtr, jint jType, jstring jText) 288 { 289 LOG("Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiTextInputEvent"); 290 291 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 292 GLASS_POOL_ENTER; 293 { 294 GlassEmbeddedWindow *window = getGlassEmbeddedWindow(env, jPtr); 295 NSString *chars = [GlassHelper nsStringWithJavaString:jText withEnv:env]; 296 if ((window != nil) && (window->child != nil)) 297 { 298 unichar *unichars = malloc([chars length] * sizeof(unichar)); 299 [chars getCharacters:unichars range:NSMakeRange(0, [chars length])]; 300 301 // Create a key-typed event for each character in the text input event. 302 // This is better than sending a text input event because in the NPAPI 303 // case there is no in-progress text to display. 304 for (NSUInteger i = 0; i < [chars length]; i++) { 305 NSString *singleChar = [NSString stringWithCharacters:&unichars[i] length:1]; 306 GlassNSEvent *event = 307 (GlassNSEvent *)[GlassNSEvent keyEventWithType:NSKeyDown 308 location:NSMakePoint(0.0, 0.0) 309 modifierFlags:0 310 timestamp:[NSDate timeIntervalSinceReferenceDate] 311 windowNumber:[window->child windowNumber] 312 context:nil 313 characters:singleChar 314 charactersIgnoringModifiers:singleChar 315 isARepeat:NO 316 keyCode:0]; 317 [event setSyntheticKeyTyped:YES]; 318 [window->child sendEvent:event]; 319 } 320 } 321 322 if ([chars length] == 1) { 323 Java_com_sun_glass_events_mac_NpapiEvent__1dispatchCocoaNpapiKeyEvent( 324 env, jNpapiClass, jPtr, com_sun_glass_events_mac_NpapiEvent_NPCocoaEventKeyUp, 325 0, jText, jText, JNI_FALSE, 0, JNI_FALSE); 326 } 327 } 328 GLASS_POOL_EXIT; 329 GLASS_CHECK_EXCEPTION(env); 330 }