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 }