1 /*
   2  * Copyright (c) 2011, 2017, 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 "jni_util.h"
  27 #import "CGLGraphicsConfig.h"
  28 #import "AWTView.h"
  29 #import "AWTWindow.h"
  30 #import "JavaComponentAccessibility.h"
  31 #import "JavaTextAccessibility.h"
  32 #import "JavaAccessibilityUtilities.h"
  33 #import "GeomUtilities.h"
  34 #import "OSVersion.h"
  35 #import "ThreadUtilities.h"
  36 
  37 #import <Carbon/Carbon.h>
  38 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  39 
  40 @interface AWTView()
  41 @property (retain) CDropTarget *_dropTarget;
  42 @property (retain) CDragSource *_dragSource;
  43 
  44 -(void) deliverResize: (NSRect) rect;
  45 -(void) resetTrackingArea;
  46 -(void) deliverJavaKeyEventHelper: (NSEvent*) event;
  47 -(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint;
  48 -(NSMutableString *) parseString : (id) complexString;
  49 @end
  50 
  51 // Uncomment this line to see fprintfs of each InputMethod API being called on this View
  52 //#define IM_DEBUG TRUE
  53 //#define EXTRA_DEBUG
  54 
  55 static BOOL shouldUsePressAndHold() {
  56     static int shouldUsePressAndHold = -1;
  57     if (shouldUsePressAndHold != -1) return shouldUsePressAndHold;
  58     shouldUsePressAndHold = !isSnowLeopardOrLower();
  59     return shouldUsePressAndHold;
  60 }
  61 
  62 @implementation AWTView
  63 
  64 @synthesize _dropTarget;
  65 @synthesize _dragSource;
  66 @synthesize cglLayer;
  67 @synthesize mouseIsOver;
  68 
  69 // Note: Must be called on main (AppKit) thread only
  70 - (id) initWithRect: (NSRect) rect
  71        platformView: (jobject) cPlatformView
  72         windowLayer: (CALayer*) windowLayer
  73 {
  74     AWT_ASSERT_APPKIT_THREAD;
  75     // Initialize ourselves
  76     self = [super initWithFrame: rect];
  77     if (self == nil) return self;
  78 
  79     m_cPlatformView = cPlatformView;
  80     fInputMethodLOCKABLE = NULL;
  81     fKeyEventsNeeded = NO;
  82     fProcessingKeystroke = NO;
  83 
  84     fEnablePressAndHold = shouldUsePressAndHold();
  85     fInPressAndHold = NO;
  86     fPAHNeedsToSelect = NO;
  87 
  88     mouseIsOver = NO;
  89     [self resetTrackingArea];
  90     [self setAutoresizesSubviews:NO];
  91 
  92     if (windowLayer != nil) {
  93         self.cglLayer = windowLayer;
  94         //Layer hosting view
  95         [self setLayer: cglLayer];
  96         [self setWantsLayer: YES];
  97         //Layer backed view
  98         //[self.layer addSublayer: (CALayer *)cglLayer];
  99         //[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
 100         //[self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft];
 101         //[self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
 102 
 103 #ifdef REMOTELAYER
 104         CGLLayer *parentLayer = (CGLLayer*)self.cglLayer;
 105         parentLayer.parentLayer = NULL;
 106         parentLayer.remoteLayer = NULL;
 107         if (JRSRemotePort != 0 && remoteSocketFD > 0) {
 108             CGLLayer *remoteLayer = [[CGLLayer alloc] initWithJavaLayer: parentLayer.javaLayer];
 109             remoteLayer.target = GL_TEXTURE_2D;
 110             NSLog(@"Creating Parent=%p, Remote=%p", parentLayer, remoteLayer);
 111             parentLayer.remoteLayer = remoteLayer;
 112             remoteLayer.parentLayer = parentLayer;
 113             remoteLayer.remoteLayer = NULL;
 114             remoteLayer.jrsRemoteLayer = [remoteLayer createRemoteLayerBoundTo:JRSRemotePort];
 115             [remoteLayer retain];  // REMIND
 116             remoteLayer.frame = CGRectMake(0, 0, 720, 500); // REMIND
 117             [remoteLayer.jrsRemoteLayer retain]; // REMIND
 118             int layerID = [remoteLayer.jrsRemoteLayer layerID];
 119             NSLog(@"layer id to send = %d", layerID);
 120             sendLayerID(layerID);
 121         }
 122 #endif /* REMOTELAYER */
 123     }
 124 
 125     return self;
 126 }
 127 
 128 - (void) dealloc {
 129     AWT_ASSERT_APPKIT_THREAD;
 130 
 131     self.cglLayer = nil;
 132 
 133     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 134     (*env)->DeleteWeakGlobalRef(env, m_cPlatformView);
 135     m_cPlatformView = NULL;
 136 
 137     if (fInputMethodLOCKABLE != NULL)
 138     {
 139         JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 140 
 141         JNFDeleteGlobalRef(env, fInputMethodLOCKABLE);
 142         fInputMethodLOCKABLE = NULL;
 143     }
 144 
 145 
 146     [super dealloc];
 147 }
 148 
 149 - (void) viewDidMoveToWindow {
 150     AWT_ASSERT_APPKIT_THREAD;
 151 
 152     [AWTToolkit eventCountPlusPlus];
 153 
 154     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^() {
 155         [[self window] makeFirstResponder: self];
 156     }];
 157     if ([self window] != NULL) {
 158         [self resetTrackingArea];
 159     }
 160 }
 161 
 162 - (BOOL) acceptsFirstMouse: (NSEvent *)event {
 163     return YES;
 164 }
 165 
 166 - (BOOL) acceptsFirstResponder {
 167     return YES;
 168 }
 169 
 170 - (BOOL) becomeFirstResponder {
 171     return YES;
 172 }
 173 
 174 - (BOOL) preservesContentDuringLiveResize {
 175     return YES;
 176 }
 177 
 178 /*
 179  * Automatically triggered functions.
 180  */
 181 
 182 - (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize {
 183     [super resizeWithOldSuperviewSize: oldBoundsSize];
 184     [self deliverResize: [self frame]];
 185 }
 186 
 187 /*
 188  * MouseEvents support
 189  */
 190 
 191 - (void) mouseDown: (NSEvent *)event {
 192     NSInputManager *inputManager = [NSInputManager currentInputManager];
 193     if ([inputManager wantsToHandleMouseEvents]) {
 194 #if IM_DEBUG
 195         NSLog(@"-> IM wants to handle event");
 196 #endif
 197         if (![inputManager handleMouseEvent:event]) {
 198             [self deliverJavaMouseEvent: event];
 199         } else {
 200 #if IM_DEBUG
 201             NSLog(@"-> Event was handled.");
 202 #endif
 203         }
 204     } else {
 205 #if IM_DEBUG
 206         NSLog(@"-> IM does not want to handle event");
 207 #endif
 208         [self deliverJavaMouseEvent: event];
 209     }
 210 }
 211 
 212 - (void) mouseUp: (NSEvent *)event {
 213     [self deliverJavaMouseEvent: event];
 214 }
 215 
 216 - (void) rightMouseDown: (NSEvent *)event {
 217     [self deliverJavaMouseEvent: event];
 218 }
 219 
 220 - (void) rightMouseUp: (NSEvent *)event {
 221     [self deliverJavaMouseEvent: event];
 222 }
 223 
 224 - (void) otherMouseDown: (NSEvent *)event {
 225     [self deliverJavaMouseEvent: event];
 226 }
 227 
 228 - (void) otherMouseUp: (NSEvent *)event {
 229     [self deliverJavaMouseEvent: event];
 230 }
 231 
 232 - (void) mouseMoved: (NSEvent *)event {
 233     // TODO: better way to redirect move events to the "under" view
 234 
 235     NSPoint eventLocation = [event locationInWindow];
 236     NSPoint localPoint = [self convertPoint: eventLocation fromView: nil];
 237 
 238     if  ([self mouse: localPoint inRect: [self bounds]]) {
 239         [self deliverJavaMouseEvent: event];
 240     } else {
 241         [[self nextResponder] mouseDown:event];
 242     }
 243 }
 244 
 245 - (void) mouseDragged: (NSEvent *)event {
 246     [self deliverJavaMouseEvent: event];
 247 }
 248 
 249 - (void) rightMouseDragged: (NSEvent *)event {
 250     [self deliverJavaMouseEvent: event];
 251 }
 252 
 253 - (void) otherMouseDragged: (NSEvent *)event {
 254     [self deliverJavaMouseEvent: event];
 255 }
 256 
 257 - (void) mouseEntered: (NSEvent *)event {
 258     [[self window] setAcceptsMouseMovedEvents:YES];
 259     //[[self window] makeFirstResponder:self];
 260     [self deliverJavaMouseEvent: event];
 261 }
 262 
 263 - (void) mouseExited: (NSEvent *)event {
 264     [[self window] setAcceptsMouseMovedEvents:NO];
 265     [self deliverJavaMouseEvent: event];
 266     //Restore the cursor back.
 267     //[CCursorManager _setCursor: [NSCursor arrowCursor]];
 268 }
 269 
 270 - (void) scrollWheel: (NSEvent*) event {
 271     [self deliverJavaMouseEvent: event];
 272 }
 273 
 274 /*
 275  * KeyEvents support
 276  */
 277 
 278 - (void) keyDown: (NSEvent *)event {
 279     fProcessingKeystroke = YES;
 280     fKeyEventsNeeded = YES;
 281 
 282     // Allow TSM to look at the event and potentially send back NSTextInputClient messages.
 283     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
 284 
 285     if (fEnablePressAndHold && [event willBeHandledByComplexInputMethod] && 
 286         fInputMethodLOCKABLE)
 287     {
 288         fProcessingKeystroke = NO;
 289         if (!fInPressAndHold) {
 290             fInPressAndHold = YES;
 291             fPAHNeedsToSelect = YES;
 292         } else {
 293             // Abandon input to reset IM and unblock input after canceling 
 294             // input accented symbols
 295 
 296             switch([event keyCode]) {
 297                 case kVK_Escape:
 298                 case kVK_Delete:
 299                 case kVK_Return:
 300                 case kVK_ForwardDelete:
 301                 case kVK_PageUp:
 302                 case kVK_PageDown:
 303                 case kVK_DownArrow:
 304                 case kVK_UpArrow:
 305                 case kVK_Home:
 306                 case kVK_End:
 307                    [self abandonInput];
 308                    break;
 309             }
 310         }
 311         return;
 312     }
 313 
 314     NSString *eventCharacters = [event characters];
 315     BOOL isDeadKey = (eventCharacters != nil && [eventCharacters length] == 0);
 316 
 317     if ((![self hasMarkedText] && fKeyEventsNeeded) || isDeadKey) {
 318         [self deliverJavaKeyEventHelper: event];
 319     }
 320 
 321     fProcessingKeystroke = NO;
 322 }
 323 
 324 - (void) keyUp: (NSEvent *)event {
 325     [self deliverJavaKeyEventHelper: event];
 326 }
 327 
 328 - (void) flagsChanged: (NSEvent *)event {
 329     [self deliverJavaKeyEventHelper: event];
 330 }
 331 
 332 - (BOOL) performKeyEquivalent: (NSEvent *) event {
 333     // if IM is active key events should be ignored
 334     if (![self hasMarkedText] && !fInPressAndHold) {
 335         [self deliverJavaKeyEventHelper: event];
 336     }
 337 
 338     // Workaround for 8020209: special case for "Cmd =" and "Cmd ."
 339     // because Cocoa calls performKeyEquivalent twice for these keystrokes
 340     NSUInteger modFlags = [event modifierFlags] &
 341     (NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask);
 342     if (modFlags == NSCommandKeyMask) {
 343         NSString *eventChars = [event charactersIgnoringModifiers];
 344         if ([eventChars length] == 1) {
 345             unichar ch = [eventChars characterAtIndex:0];
 346             if (ch == '=' || ch == '.') {
 347                 [[NSApp mainMenu] performKeyEquivalent: event];
 348                 return YES;
 349             }
 350         }
 351 
 352     }
 353 
 354     return NO;
 355 }
 356 
 357 /**
 358  * Utility methods and accessors
 359  */
 360 
 361 -(void) deliverJavaMouseEvent: (NSEvent *) event {
 362     BOOL isEnabled = YES;
 363     NSWindow* window = [self window];
 364     if ([window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]]) {
 365         isEnabled = [(AWTWindow*)[window delegate] isEnabled];
 366     }
 367 
 368     if (!isEnabled) {
 369         return;
 370     }
 371 
 372     NSEventType type = [event type];
 373 
 374     // check synthesized mouse entered/exited events
 375     if ((type == NSMouseEntered && mouseIsOver) || (type == NSMouseExited && !mouseIsOver)) {
 376         return;
 377     }else if ((type == NSMouseEntered && !mouseIsOver) || (type == NSMouseExited && mouseIsOver)) {
 378         mouseIsOver = !mouseIsOver;
 379     }
 380 
 381     [AWTToolkit eventCountPlusPlus];
 382 
 383     JNIEnv *env = [ThreadUtilities getJNIEnv];
 384 
 385     NSPoint eventLocation = [event locationInWindow];
 386     NSPoint localPoint = [self convertPoint: eventLocation fromView: nil];
 387     NSPoint absP = [NSEvent mouseLocation];
 388 
 389     // Convert global numbers between Cocoa's coordinate system and Java.
 390     // TODO: need consitent way for doing that both with global as well as with local coordinates.
 391     // The reason to do it here is one more native method for getting screen dimension otherwise.
 392 
 393     NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
 394     absP.y = screenRect.size.height - absP.y;
 395     jint clickCount;
 396 
 397     if (type == NSMouseEntered ||
 398         type == NSMouseExited ||
 399         type == NSScrollWheel ||
 400         type == NSMouseMoved) {
 401         clickCount = 0;
 402     } else {
 403         clickCount = [event clickCount];
 404     }
 405 
 406     jdouble deltaX = [event deltaX];
 407     jdouble deltaY = [event deltaY];
 408     if ([AWTToolkit hasPreciseScrollingDeltas: event]) {
 409         deltaX = [event scrollingDeltaX] * 0.1;
 410         deltaY = [event scrollingDeltaY] * 0.1;
 411     }
 412 
 413     static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent");
 414     static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V");
 415     jobject jEvent = JNFNewObject(env, jctor_NSEvent,
 416                                   [event type],
 417                                   [event modifierFlags],
 418                                   clickCount,
 419                                   [event buttonNumber],
 420                                   (jint)localPoint.x, (jint)localPoint.y,
 421                                   (jint)absP.x, (jint)absP.y,
 422                                   deltaY,
 423                                   deltaX,
 424                                   [AWTToolkit scrollStateWithEvent: event]);
 425     CHECK_NULL(jEvent);
 426 
 427     static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
 428     static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
 429     jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
 430     if (!(*env)->IsSameObject(env, jlocal, NULL)) {
 431         JNFCallVoidMethod(env, jlocal, jm_deliverMouseEvent, jEvent);
 432         (*env)->DeleteLocalRef(env, jlocal);
 433     }
 434     (*env)->DeleteLocalRef(env, jEvent);
 435 }
 436 
 437 - (void) resetTrackingArea {
 438     if (rolloverTrackingArea != nil) {
 439         [self removeTrackingArea:rolloverTrackingArea];
 440         [rolloverTrackingArea release];
 441     }
 442 
 443     int options = (NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited |
 444                    NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag);
 445 
 446     rolloverTrackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect]
 447                                                         options: options
 448                                                           owner:self
 449                                                        userInfo:nil
 450                             ];
 451     [self addTrackingArea:rolloverTrackingArea];
 452 }
 453 
 454 - (void)updateTrackingAreas {
 455     [super updateTrackingAreas];
 456     [self resetTrackingArea];
 457 }
 458 
 459 - (void) resetCursorRects {
 460     [super resetCursorRects];
 461     [self resetTrackingArea];
 462 }
 463 
 464 -(void) deliverJavaKeyEventHelper: (NSEvent *) event {
 465     static NSEvent* sLastKeyEvent = nil;
 466     if (event == sLastKeyEvent) {
 467         // The event is repeatedly delivered by keyDown: after performKeyEquivalent:
 468         return;
 469     }
 470     [sLastKeyEvent release];
 471     sLastKeyEvent = [event retain];
 472 
 473     [AWTToolkit eventCountPlusPlus];
 474     JNIEnv *env = [ThreadUtilities getJNIEnv];
 475 
 476     jstring characters = NULL;
 477     jstring charactersIgnoringModifiers = NULL;
 478     if ([event type] != NSFlagsChanged) {
 479         characters = JNFNSToJavaString(env, [event characters]);
 480         charactersIgnoringModifiers = JNFNSToJavaString(env, [event charactersIgnoringModifiers]);
 481     }
 482 
 483     static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent");
 484     static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IISLjava/lang/String;Ljava/lang/String;)V");
 485     jobject jEvent = JNFNewObject(env, jctor_NSEvent,
 486                                   [event type],
 487                                   [event modifierFlags],
 488                                   [event keyCode],
 489                                   characters,
 490                                   charactersIgnoringModifiers);
 491     CHECK_NULL(jEvent);
 492 
 493     static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
 494     static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_PlatformView,
 495                             "deliverKeyEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
 496     jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
 497     if (!(*env)->IsSameObject(env, jlocal, NULL)) {
 498         JNFCallVoidMethod(env, jlocal, jm_deliverKeyEvent, jEvent);
 499         (*env)->DeleteLocalRef(env, jlocal);
 500     }
 501     if (characters != NULL) {
 502         (*env)->DeleteLocalRef(env, characters);
 503     }
 504     (*env)->DeleteLocalRef(env, jEvent);
 505 }
 506 
 507 -(void) deliverResize: (NSRect) rect {
 508     jint x = (jint) rect.origin.x;
 509     jint y = (jint) rect.origin.y;
 510     jint w = (jint) rect.size.width;
 511     jint h = (jint) rect.size.height;
 512     JNIEnv *env = [ThreadUtilities getJNIEnv];
 513     static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
 514     static JNF_MEMBER_CACHE(jm_deliverResize, jc_PlatformView, "deliverResize", "(IIII)V");
 515 
 516     jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
 517     if (!(*env)->IsSameObject(env, jlocal, NULL)) {
 518         JNFCallVoidMethod(env, jlocal, jm_deliverResize, x,y,w,h);
 519         (*env)->DeleteLocalRef(env, jlocal);
 520     }
 521 }
 522 
 523 
 524 - (void) drawRect:(NSRect)dirtyRect {
 525     AWT_ASSERT_APPKIT_THREAD;
 526 
 527     [super drawRect:dirtyRect];
 528     JNIEnv *env = [ThreadUtilities getJNIEnv];
 529     if (env != NULL) {
 530         /*
 531          if ([self inLiveResize]) {
 532          NSRect rs[4];
 533          NSInteger count;
 534          [self getRectsExposedDuringLiveResize:rs count:&count];
 535          for (int i = 0; i < count; i++) {
 536          JNU_CallMethodByName(env, NULL, [m_awtWindow cPlatformView],
 537          "deliverWindowDidExposeEvent", "(FFFF)V",
 538          (jfloat)rs[i].origin.x, (jfloat)rs[i].origin.y,
 539          (jfloat)rs[i].size.width, (jfloat)rs[i].size.height);
 540          if ((*env)->ExceptionOccurred(env)) {
 541          (*env)->ExceptionDescribe(env);
 542          (*env)->ExceptionClear(env);
 543          }
 544          }
 545          } else {
 546          */
 547         static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView");
 548         static JNF_MEMBER_CACHE(jm_deliverWindowDidExposeEvent, jc_CPlatformView, "deliverWindowDidExposeEvent", "()V");
 549         jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
 550         if (!(*env)->IsSameObject(env, jlocal, NULL)) {
 551             JNFCallVoidMethod(env, jlocal, jm_deliverWindowDidExposeEvent);
 552             (*env)->DeleteLocalRef(env, jlocal);
 553         }
 554         /*
 555          }
 556          */
 557     }
 558 }
 559 
 560 -(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint {
 561     if ((codePoint == 0x0024) || (codePoint == 0x00A3) ||
 562         (codePoint == 0x00A5) ||
 563         ((codePoint >= 0x20A3) && (codePoint <= 0x20BF)) ||
 564         ((codePoint >= 0x3000) && (codePoint <= 0x303F)) ||
 565         ((codePoint >= 0xFF00) && (codePoint <= 0xFFEF))) {
 566         // Code point is in 'CJK Symbols and Punctuation' or
 567         // 'Halfwidth and Fullwidth Forms' Unicode block or
 568         // currency symbols unicode
 569         return YES;
 570     }
 571     return NO;
 572 }
 573 
 574 -(NSMutableString *) parseString : (id) complexString {
 575     if ([complexString isKindOfClass:[NSString class]]) {
 576         return [complexString mutableCopy];
 577     }
 578     else {
 579         return [complexString mutableString];
 580     }
 581 }
 582 
 583 // NSAccessibility support
 584 - (jobject)awtComponent:(JNIEnv*)env
 585 {
 586     static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView");
 587     static JNF_MEMBER_CACHE(jf_Peer, jc_CPlatformView, "peer", "Lsun/lwawt/LWWindowPeer;");
 588     if ((env == NULL) || (m_cPlatformView == NULL)) {
 589         NSLog(@"Apple AWT : Error AWTView:awtComponent given bad parameters.");
 590         if (env != NULL)
 591         {
 592             JNFDumpJavaStack(env);
 593         }
 594         return NULL;
 595     }
 596 
 597     jobject peer = NULL;
 598     jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
 599     if (!(*env)->IsSameObject(env, jlocal, NULL)) {
 600         peer = JNFGetObjectField(env, jlocal, jf_Peer);
 601         (*env)->DeleteLocalRef(env, jlocal);
 602     }
 603     static JNF_CLASS_CACHE(jc_LWWindowPeer, "sun/lwawt/LWWindowPeer");
 604     static JNF_MEMBER_CACHE(jf_Target, jc_LWWindowPeer, "target", "Ljava/awt/Component;");
 605     if (peer == NULL) {
 606         NSLog(@"Apple AWT : Error AWTView:awtComponent got null peer from CPlatformView");
 607         JNFDumpJavaStack(env);
 608         return NULL;
 609     }
 610     jobject comp = JNFGetObjectField(env, peer, jf_Target);
 611     (*env)->DeleteLocalRef(env, peer);
 612     return comp;
 613 }
 614 
 615 + (AWTView *) awtView:(JNIEnv*)env ofAccessible:(jobject)jaccessible
 616 {
 617     static JNF_STATIC_MEMBER_CACHE(jm_getAWTView, sjc_CAccessibility, "getAWTView", "(Ljavax/accessibility/Accessible;)J");
 618 
 619     jlong jptr = JNFCallStaticLongMethod(env, jm_getAWTView, jaccessible);
 620     if (jptr == 0) return nil;
 621 
 622     return (AWTView *)jlong_to_ptr(jptr);
 623 }
 624 
 625 - (id)getAxData:(JNIEnv*)env
 626 {
 627     jobject jcomponent = [self awtComponent:env];
 628     id ax = [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
 629     (*env)->DeleteLocalRef(env, jcomponent);
 630     return ax;
 631 }
 632 
 633 - (NSArray *)accessibilityAttributeNames
 634 {
 635     return [[super accessibilityAttributeNames] arrayByAddingObject:NSAccessibilityChildrenAttribute];
 636 }
 637 
 638 // NSAccessibility messages
 639 // attribute methods
 640 - (id)accessibilityAttributeValue:(NSString *)attribute
 641 {
 642     AWT_ASSERT_APPKIT_THREAD;
 643 
 644     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
 645     {
 646         JNIEnv *env = [ThreadUtilities getJNIEnv];
 647 
 648         (*env)->PushLocalFrame(env, 4);
 649 
 650         id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]);
 651 
 652         (*env)->PopLocalFrame(env, NULL);
 653 
 654         return result;
 655     }
 656     else
 657     {
 658         return [super accessibilityAttributeValue:attribute];
 659     }
 660 }
 661 - (BOOL)accessibilityIsIgnored
 662 {
 663     return YES;
 664 }
 665 
 666 - (id)accessibilityHitTest:(NSPoint)point
 667 {
 668     AWT_ASSERT_APPKIT_THREAD;
 669     JNIEnv *env = [ThreadUtilities getJNIEnv];
 670 
 671     (*env)->PushLocalFrame(env, 4);
 672 
 673     id result = [[self getAxData:env] accessibilityHitTest:point withEnv:env];
 674 
 675     (*env)->PopLocalFrame(env, NULL);
 676 
 677     return result;
 678 }
 679 
 680 - (id)accessibilityFocusedUIElement
 681 {
 682     AWT_ASSERT_APPKIT_THREAD;
 683 
 684     JNIEnv *env = [ThreadUtilities getJNIEnv];
 685 
 686     (*env)->PushLocalFrame(env, 4);
 687 
 688     id result = [[self getAxData:env] accessibilityFocusedUIElement];
 689 
 690     (*env)->PopLocalFrame(env, NULL);
 691 
 692     return result;
 693 }
 694 
 695 // --- Services menu support for lightweights ---
 696 
 697 // finds the focused accessible element, and if it is a text element, obtains the text from it
 698 - (NSString *)accessibleSelectedText
 699 {
 700     id focused = [self accessibilityFocusedUIElement];
 701     if (![focused isKindOfClass:[JavaTextAccessibility class]]) return nil;
 702     return [(JavaTextAccessibility *)focused accessibilitySelectedTextAttribute];
 703 }
 704 
 705 // same as above, but converts to RTFD
 706 - (NSData *)accessibleSelectedTextAsRTFD
 707 {
 708     NSString *selectedText = [self accessibleSelectedText];
 709     NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText];
 710     NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length])
 711                               documentAttributes:
 712                                 @{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}];
 713     [styledText release];
 714     return rtfdData;
 715 }
 716 
 717 // finds the focused accessible element, and if it is a text element, sets the text in it
 718 - (BOOL)replaceAccessibleTextSelection:(NSString *)text
 719 {
 720     id focused = [self accessibilityFocusedUIElement];
 721     if (![focused isKindOfClass:[JavaTextAccessibility class]]) return NO;
 722     [(JavaTextAccessibility *)focused accessibilitySetSelectedTextAttribute:text];
 723     return YES;
 724 }
 725 
 726 // called for each service in the Services menu - only handle text for now
 727 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
 728 {
 729     if ([[self window] firstResponder] != self) return nil; // let AWT components handle themselves
 730 
 731     if ([sendType isEqual:NSStringPboardType] || [returnType isEqual:NSStringPboardType]) {
 732         NSString *selectedText = [self accessibleSelectedText];
 733         if (selectedText) return self;
 734     }
 735 
 736     return nil;
 737 }
 738 
 739 // fetch text from Java and hand off to the service
 740 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types
 741 {
 742     if ([types containsObject:NSStringPboardType])
 743     {
 744         [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
 745         return [pboard setString:[self accessibleSelectedText] forType:NSStringPboardType];
 746     }
 747 
 748     if ([types containsObject:NSRTFDPboardType])
 749     {
 750         [pboard declareTypes:[NSArray arrayWithObject:NSRTFDPboardType] owner:nil];
 751         return [pboard setData:[self accessibleSelectedTextAsRTFD] forType:NSRTFDPboardType];
 752     }
 753 
 754     return NO;
 755 }
 756 
 757 // write text back to Java from the service
 758 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard
 759 {
 760     if ([[pboard types] containsObject:NSStringPboardType])
 761     {
 762         NSString *text = [pboard stringForType:NSStringPboardType];
 763         return [self replaceAccessibleTextSelection:text];
 764     }
 765 
 766     if ([[pboard types] containsObject:NSRTFDPboardType])
 767     {
 768         NSData *rtfdData = [pboard dataForType:NSRTFDPboardType];
 769         NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:NULL];
 770         NSString *text = [styledText string];
 771         [styledText release];
 772 
 773         return [self replaceAccessibleTextSelection:text];
 774     }
 775 
 776     return NO;
 777 }
 778 
 779 
 780 -(void) setDragSource:(CDragSource *)source {
 781     self._dragSource = source;
 782 }
 783 
 784 
 785 - (void) setDropTarget:(CDropTarget *)target {
 786     self._dropTarget = target;
 787     [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) on:self._dropTarget withObject:nil waitUntilDone:YES];
 788 }
 789 
 790 /********************************  BEGIN NSDraggingSource Interface  ********************************/
 791 
 792 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
 793 {
 794     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 795     CDragSource *dragSource = self._dragSource;
 796     NSDragOperation dragOp = NSDragOperationNone;
 797 
 798     if (dragSource != nil) {
 799         dragOp = [dragSource draggingSourceOperationMaskForLocal:flag];
 800     }
 801     return dragOp;
 802 }
 803 
 804 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
 805 {
 806     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 807     CDragSource *dragSource = self._dragSource;
 808     NSArray* array = nil;
 809 
 810     if (dragSource != nil) {
 811         array = [dragSource namesOfPromisedFilesDroppedAtDestination:dropDestination];
 812     }
 813     return array;
 814 }
 815 
 816 - (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint
 817 {
 818     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 819     CDragSource *dragSource = self._dragSource;
 820 
 821     if (dragSource != nil) {
 822         [dragSource draggedImage:image beganAt:screenPoint];
 823     }
 824 }
 825 
 826 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation
 827 {
 828     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 829     CDragSource *dragSource = self._dragSource;
 830 
 831     if (dragSource != nil) {
 832         [dragSource draggedImage:image endedAt:screenPoint operation:operation];
 833     }
 834 }
 835 
 836 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint
 837 {
 838     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 839     CDragSource *dragSource = self._dragSource;
 840 
 841     if (dragSource != nil) {
 842         [dragSource draggedImage:image movedTo:screenPoint];
 843     }
 844 }
 845 
 846 - (BOOL)ignoreModifierKeysWhileDragging
 847 {
 848     // If draggingSource is nil route the message to the superclass (if responding to the selector):
 849     CDragSource *dragSource = self._dragSource;
 850     BOOL result = FALSE;
 851 
 852     if (dragSource != nil) {
 853         result = [dragSource ignoreModifierKeysWhileDragging];
 854     }
 855     return result;
 856 }
 857 
 858 /********************************  END NSDraggingSource Interface  ********************************/
 859 
 860 /********************************  BEGIN NSDraggingDestination Interface  ********************************/
 861 
 862 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 863 {
 864     // If draggingDestination is nil route the message to the superclass:
 865     CDropTarget *dropTarget = self._dropTarget;
 866     NSDragOperation dragOp = NSDragOperationNone;
 867 
 868     if (dropTarget != nil) {
 869         dragOp = [dropTarget draggingEntered:sender];
 870     }
 871     return dragOp;
 872 }
 873 
 874 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
 875 {
 876     // If draggingDestination is nil route the message to the superclass:
 877     CDropTarget *dropTarget = self._dropTarget;
 878     NSDragOperation dragOp = NSDragOperationNone;
 879 
 880     if (dropTarget != nil) {
 881         dragOp = [dropTarget draggingUpdated:sender];
 882     }
 883     return dragOp;
 884 }
 885 
 886 - (void)draggingExited:(id <NSDraggingInfo>)sender
 887 {
 888     // If draggingDestination is nil route the message to the superclass:
 889     CDropTarget *dropTarget = self._dropTarget;
 890 
 891     if (dropTarget != nil) {
 892         [dropTarget draggingExited:sender];
 893     }
 894 }
 895 
 896 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
 897 {
 898     // If draggingDestination is nil route the message to the superclass:
 899     CDropTarget *dropTarget = self._dropTarget;
 900     BOOL result = FALSE;
 901 
 902     if (dropTarget != nil) {
 903         result = [dropTarget prepareForDragOperation:sender];
 904     }
 905     return result;
 906 }
 907 
 908 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 909 {
 910     // If draggingDestination is nil route the message to the superclass:
 911     CDropTarget *dropTarget = self._dropTarget;
 912     BOOL result = FALSE;
 913 
 914     if (dropTarget != nil) {
 915         result = [dropTarget performDragOperation:sender];
 916     }
 917     return result;
 918 }
 919 
 920 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
 921 {
 922     // If draggingDestination is nil route the message to the superclass:
 923     CDropTarget *dropTarget = self._dropTarget;
 924 
 925     if (dropTarget != nil) {
 926         [dropTarget concludeDragOperation:sender];
 927     }
 928 }
 929 
 930 - (void)draggingEnded:(id <NSDraggingInfo>)sender
 931 {
 932     // If draggingDestination is nil route the message to the superclass:
 933     CDropTarget *dropTarget = self._dropTarget;
 934 
 935     if (dropTarget != nil) {
 936         [dropTarget draggingEnded:sender];
 937     }
 938 }
 939 
 940 /********************************  END NSDraggingDestination Interface  ********************************/
 941 
 942 /********************************  BEGIN NSTextInputClient Protocol  ********************************/
 943 
 944 
 945 JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod");
 946 
 947 - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
 948 {
 949 #ifdef IM_DEBUG
 950     fprintf(stderr, "AWTView InputMethod Selector Called : [insertText]: %s\n", [aString UTF8String]);
 951 #endif // IM_DEBUG
 952 
 953     if (fInputMethodLOCKABLE == NULL) {
 954         return;
 955     }
 956 
 957     // Insert happens at the end of PAH
 958     fInPressAndHold = NO;
 959 
 960     // insertText gets called when the user commits text generated from an input method.  It also gets
 961     // called during ordinary input as well.  We only need to send an input method event when we have marked
 962     // text, or 'text in progress'.  We also need to send the event if we get an insert text out of the blue!
 963     // (i.e., when the user uses the Character palette or Inkwell), or when the string to insert is a complex
 964     // Unicode value.
 965 
 966     NSMutableString * useString = [self parseString:aString];
 967     NSUInteger utf16Length = [useString lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
 968     NSUInteger utf8Length = [useString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
 969     BOOL aStringIsComplex = NO;
 970     if ((utf16Length > 2) ||
 971         ((utf8Length > 1) && [self isCodePointInUnicodeBlockNeedingIMEvent:[useString characterAtIndex:0]])) {
 972         aStringIsComplex = YES;
 973     }
 974 
 975     if ([self hasMarkedText] || !fProcessingKeystroke || aStringIsComplex) {
 976         JNIEnv *env = [ThreadUtilities getJNIEnv];
 977 
 978         static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
 979         // We need to select the previous glyph so that it is overwritten.
 980         if (fPAHNeedsToSelect) {
 981             JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
 982             fPAHNeedsToSelect = NO;
 983         }
 984 
 985         static JNF_MEMBER_CACHE(jm_insertText, jc_CInputMethod, "insertText", "(Ljava/lang/String;)V");
 986         jstring insertedText =  JNFNSToJavaString(env, useString);
 987         JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_insertText, insertedText); // AWT_THREADING Safe (AWTRunLoopMode)
 988         (*env)->DeleteLocalRef(env, insertedText);
 989 
 990         // The input method event will create psuedo-key events for each character in the committed string.
 991         // We also don't want to send the character that triggered the insertText, usually a return. [3337563]
 992         fKeyEventsNeeded = NO;
 993     }
 994     else {
 995         // Need to set back the fKeyEventsNeeded flag so that the string following the
 996         // marked text is not ignored by keyDown
 997         if ([useString length] > 0) {
 998             fKeyEventsNeeded = YES;
 999         }
1000     }
1001     fPAHNeedsToSelect = NO;
1002 
1003     // Abandon input to reset IM and unblock input after entering accented
1004     // symbols
1005 
1006     [self abandonInput];
1007 }
1008 
1009 - (void) doCommandBySelector:(SEL)aSelector
1010 {
1011 #ifdef IM_DEBUG
1012     fprintf(stderr, "AWTView InputMethod Selector Called : [doCommandBySelector]\n");
1013     NSLog(@"%@", NSStringFromSelector(aSelector));
1014 #endif // IM_DEBUG
1015     if (@selector(insertNewline:) == aSelector || @selector(insertTab:) == aSelector || @selector(deleteBackward:) == aSelector)
1016     {
1017         fKeyEventsNeeded = YES;
1018     }
1019 }
1020 
1021 // setMarkedText: cannot take a nil first argument. aString can be NSString or NSAttributedString
1022 - (void) setMarkedText:(id)aString selectedRange:(NSRange)selectionRange replacementRange:(NSRange)replacementRange
1023 {
1024     if (!fInputMethodLOCKABLE)
1025         return;
1026 
1027     BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
1028     NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil);
1029     NSString *incomingString = (isAttributedString ? [aString string] : aString);
1030 #ifdef IM_DEBUG
1031     fprintf(stderr, "AWTView InputMethod Selector Called : [setMarkedText] \"%s\", loc=%lu, length=%lu\n", [incomingString UTF8String], (unsigned long)selectionRange.location, (unsigned long)selectionRange.length);
1032 #endif // IM_DEBUG
1033     static JNF_MEMBER_CACHE(jm_startIMUpdate, jc_CInputMethod, "startIMUpdate", "(Ljava/lang/String;)V");
1034     static JNF_MEMBER_CACHE(jm_addAttribute, jc_CInputMethod, "addAttribute", "(ZZII)V");
1035     static JNF_MEMBER_CACHE(jm_dispatchText, jc_CInputMethod, "dispatchText", "(IIZ)V");
1036     JNIEnv *env = [ThreadUtilities getJNIEnv];
1037 
1038     // NSInputContext already did the analysis of the TSM event and created attributes indicating
1039     // the underlining and color that should be done to the string.  We need to look at the underline
1040     // style and color to determine what kind of Java hilighting needs to be done.
1041     jstring inProcessText = JNFNSToJavaString(env, incomingString);
1042     JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_startIMUpdate, inProcessText); // AWT_THREADING Safe (AWTRunLoopMode)
1043     (*env)->DeleteLocalRef(env, inProcessText);
1044 
1045     if (isAttributedString) {
1046         NSUInteger length;
1047         NSRange effectiveRange;
1048         NSDictionary *attributes;
1049         length = [attrString length];
1050         effectiveRange = NSMakeRange(0, 0);
1051         while (NSMaxRange(effectiveRange) < length) {
1052             attributes = [attrString attributesAtIndex:NSMaxRange(effectiveRange)
1053                                         effectiveRange:&effectiveRange];
1054             if (attributes) {
1055                 BOOL isThickUnderline, isGray;
1056                 NSNumber *underlineSizeObj =
1057                 (NSNumber *)[attributes objectForKey:NSUnderlineStyleAttributeName];
1058                 NSInteger underlineSize = [underlineSizeObj integerValue];
1059                 isThickUnderline = (underlineSize > 1);
1060 
1061                 NSColor *underlineColorObj =
1062                 (NSColor *)[attributes objectForKey:NSUnderlineColorAttributeName];
1063                 isGray = !([underlineColorObj isEqual:[NSColor blackColor]]);
1064 
1065                 JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_addAttribute, isThickUnderline, isGray, effectiveRange.location, effectiveRange.length); // AWT_THREADING Safe (AWTRunLoopMode)
1066             }
1067         }
1068     }
1069 
1070     static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
1071     // We need to select the previous glyph so that it is overwritten.
1072     if (fPAHNeedsToSelect) {
1073         JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
1074         fPAHNeedsToSelect = NO;
1075     }
1076 
1077     JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_dispatchText, selectionRange.location, selectionRange.length, JNI_FALSE); // AWT_THREADING Safe (AWTRunLoopMode)
1078 
1079     // If the marked text is being cleared (zero-length string) don't handle the key event.
1080     if ([incomingString length] == 0) {
1081         fKeyEventsNeeded = NO;
1082     }
1083 }
1084 
1085 - (void) unmarkText
1086 {
1087 #ifdef IM_DEBUG
1088     fprintf(stderr, "AWTView InputMethod Selector Called : [unmarkText]\n");
1089 #endif // IM_DEBUG
1090 
1091     if (!fInputMethodLOCKABLE) {
1092         return;
1093     }
1094 
1095     // unmarkText cancels any input in progress and commits it to the text field.
1096     static JNF_MEMBER_CACHE(jm_unmarkText, jc_CInputMethod, "unmarkText", "()V");
1097     JNIEnv *env = [ThreadUtilities getJNIEnv];
1098     JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_unmarkText); // AWT_THREADING Safe (AWTRunLoopMode)
1099 
1100 }
1101 
1102 - (BOOL) hasMarkedText
1103 {
1104 #ifdef IM_DEBUG
1105     fprintf(stderr, "AWTView InputMethod Selector Called : [hasMarkedText]\n");
1106 #endif // IM_DEBUG
1107 
1108     if (!fInputMethodLOCKABLE) {
1109         return NO;
1110     }
1111 
1112     static JNF_MEMBER_CACHE(jf_fCurrentText, jc_CInputMethod, "fCurrentText", "Ljava/text/AttributedString;");
1113     static JNF_MEMBER_CACHE(jf_fCurrentTextLength, jc_CInputMethod, "fCurrentTextLength", "I");
1114     JNIEnv *env = [ThreadUtilities getJNIEnv];
1115     jobject currentText = JNFGetObjectField(env, fInputMethodLOCKABLE, jf_fCurrentText);
1116 
1117     jint currentTextLength = JNFGetIntField(env, fInputMethodLOCKABLE, jf_fCurrentTextLength);
1118 
1119     BOOL hasMarkedText = (currentText != NULL && currentTextLength > 0);
1120 
1121     if (currentText != NULL) {
1122         (*env)->DeleteLocalRef(env, currentText);
1123     }
1124 
1125     return hasMarkedText;
1126 }
1127 
1128 - (NSInteger) conversationIdentifier
1129 {
1130 #ifdef IM_DEBUG
1131     fprintf(stderr, "AWTView InputMethod Selector Called : [conversationIdentifier]\n");
1132 #endif // IM_DEBUG
1133 
1134     return (NSInteger) self;
1135 }
1136 
1137 /* Returns attributed string at the range.  This allows input mangers to
1138  query any range in backing-store (Andy's request)
1139  */
1140 - (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
1141 {
1142 #ifdef IM_DEBUG
1143     fprintf(stderr, "AWTView InputMethod Selector Called : [attributedSubstringFromRange] location=%lu, length=%lu\n", (unsigned long)theRange.location, (unsigned long)theRange.length);
1144 #endif // IM_DEBUG
1145 
1146     static JNF_MEMBER_CACHE(jm_substringFromRange, jc_CInputMethod, "attributedSubstringFromRange", "(II)Ljava/lang/String;");
1147     JNIEnv *env = [ThreadUtilities getJNIEnv];
1148     jobject theString = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_substringFromRange, theRange.location, theRange.length); // AWT_THREADING Safe (AWTRunLoopMode)
1149 
1150     id result = [[[NSAttributedString alloc] initWithString:JNFJavaToNSString(env, theString)] autorelease];
1151 #ifdef IM_DEBUG
1152     NSLog(@"attributedSubstringFromRange returning \"%@\"", result);
1153 #endif // IM_DEBUG
1154 
1155     (*env)->DeleteLocalRef(env, theString);
1156     return result;
1157 }
1158 
1159 /* This method returns the range for marked region.  If hasMarkedText == false,
1160  it'll return NSNotFound location & 0 length range.
1161  */
1162 - (NSRange) markedRange
1163 {
1164 
1165 #ifdef IM_DEBUG
1166     fprintf(stderr, "AWTView InputMethod Selector Called : [markedRange]\n");
1167 #endif // IM_DEBUG
1168 
1169     if (!fInputMethodLOCKABLE) {
1170         return NSMakeRange(NSNotFound, 0);
1171     }
1172 
1173     static JNF_MEMBER_CACHE(jm_markedRange, jc_CInputMethod, "markedRange", "()[I");
1174     JNIEnv *env = [ThreadUtilities getJNIEnv];
1175     jarray array;
1176     jboolean isCopy;
1177     jint *_array;
1178     NSRange range = NSMakeRange(NSNotFound, 0);
1179 
1180     array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_markedRange); // AWT_THREADING Safe (AWTRunLoopMode)
1181 
1182     if (array) {
1183         _array = (*env)->GetIntArrayElements(env, array, &isCopy);
1184         if (_array != NULL) {
1185             range.location = _array[0];
1186             range.length = _array[1];
1187 #ifdef IM_DEBUG
1188             fprintf(stderr, "markedRange returning (%lu, %lu)\n",
1189                     (unsigned long)range.location, (unsigned long)range.length);
1190 #endif // IM_DEBUG
1191             (*env)->ReleaseIntArrayElements(env, array, _array, 0);
1192         }
1193         (*env)->DeleteLocalRef(env, array);
1194     }
1195 
1196     return range;
1197 }
1198 
1199 /* This method returns the range for selected region.  Just like markedRange method,
1200  its location field contains char index from the text beginning.
1201  */
1202 - (NSRange) selectedRange
1203 {
1204     if (!fInputMethodLOCKABLE) {
1205         return NSMakeRange(NSNotFound, 0);
1206     }
1207 
1208     static JNF_MEMBER_CACHE(jm_selectedRange, jc_CInputMethod, "selectedRange", "()[I");
1209     JNIEnv *env = [ThreadUtilities getJNIEnv];
1210     jarray array;
1211     jboolean isCopy;
1212     jint *_array;
1213     NSRange range = NSMakeRange(NSNotFound, 0);
1214 
1215 #ifdef IM_DEBUG
1216     fprintf(stderr, "AWTView InputMethod Selector Called : [selectedRange]\n");
1217 #endif // IM_DEBUG
1218 
1219     array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_selectedRange); // AWT_THREADING Safe (AWTRunLoopMode)
1220     if (array) {
1221         _array = (*env)->GetIntArrayElements(env, array, &isCopy);
1222         if (_array != NULL) {
1223             range.location = _array[0];
1224             range.length = _array[1];
1225             (*env)->ReleaseIntArrayElements(env, array, _array, 0);
1226         }
1227         (*env)->DeleteLocalRef(env, array);
1228     }
1229 
1230     return range;
1231 }
1232 
1233 /* This method returns the first frame of rects for theRange in screen coordindate system.
1234  */
1235 - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
1236 {
1237     if (!fInputMethodLOCKABLE) {
1238         return NSZeroRect;
1239     }
1240 
1241     static JNF_MEMBER_CACHE(jm_firstRectForCharacterRange, jc_CInputMethod,
1242                             "firstRectForCharacterRange", "(I)[I");
1243     JNIEnv *env = [ThreadUtilities getJNIEnv];
1244     jarray array;
1245     jboolean isCopy;
1246     jint *_array;
1247     NSRect rect;
1248 
1249 #ifdef IM_DEBUG
1250     fprintf(stderr,
1251             "AWTView InputMethod Selector Called : [firstRectForCharacterRange:] location=%lu, length=%lu\n",
1252             (unsigned long)theRange.location, (unsigned long)theRange.length);
1253 #endif // IM_DEBUG
1254 
1255     array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_firstRectForCharacterRange,
1256                                 theRange.location); // AWT_THREADING Safe (AWTRunLoopMode)
1257 
1258     _array = (*env)->GetIntArrayElements(env, array, &isCopy);
1259     if (_array) {
1260         rect = ConvertNSScreenRect(env, NSMakeRect(_array[0], _array[1], _array[2], _array[3]));
1261         (*env)->ReleaseIntArrayElements(env, array, _array, 0);
1262     } else {
1263         rect = NSZeroRect;
1264     }
1265     (*env)->DeleteLocalRef(env, array);
1266 
1267 #ifdef IM_DEBUG
1268     fprintf(stderr,
1269             "firstRectForCharacterRange returning x=%f, y=%f, width=%f, height=%f\n",
1270             rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
1271 #endif // IM_DEBUG
1272     return rect;
1273 }
1274 
1275 /* This method returns the index for character that is nearest to thePoint.  thPoint is in
1276  screen coordinate system.
1277  */
1278 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1279 {
1280     if (!fInputMethodLOCKABLE) {
1281         return NSNotFound;
1282     }
1283 
1284     static JNF_MEMBER_CACHE(jm_characterIndexForPoint, jc_CInputMethod,
1285                             "characterIndexForPoint", "(II)I");
1286     JNIEnv *env = [ThreadUtilities getJNIEnv];
1287 
1288     NSPoint flippedLocation = ConvertNSScreenPoint(env, thePoint);
1289 
1290 #ifdef IM_DEBUG
1291     fprintf(stderr, "AWTView InputMethod Selector Called : [characterIndexForPoint:(NSPoint)thePoint] x=%f, y=%f\n", flippedLocation.x, flippedLocation.y);
1292 #endif // IM_DEBUG
1293 
1294     jint index = JNFCallIntMethod(env, fInputMethodLOCKABLE, jm_characterIndexForPoint, (jint)flippedLocation.x, (jint)flippedLocation.y); // AWT_THREADING Safe (AWTRunLoopMode)
1295 
1296 #ifdef IM_DEBUG
1297     fprintf(stderr, "characterIndexForPoint returning %ld\n", index);
1298 #endif // IM_DEBUG
1299 
1300     if (index == -1) {
1301         return NSNotFound;
1302     } else {
1303         return (NSUInteger)index;
1304     }
1305 }
1306 
1307 - (NSArray*) validAttributesForMarkedText
1308 {
1309 #ifdef IM_DEBUG
1310     fprintf(stderr, "AWTView InputMethod Selector Called : [validAttributesForMarkedText]\n");
1311 #endif // IM_DEBUG
1312 
1313     return [NSArray array];
1314 }
1315 
1316 - (void)setInputMethod:(jobject)inputMethod
1317 {
1318 #ifdef IM_DEBUG
1319     fprintf(stderr, "AWTView InputMethod Selector Called : [setInputMethod]\n");
1320 #endif // IM_DEBUG
1321 
1322     JNIEnv *env = [ThreadUtilities getJNIEnv];
1323 
1324     // Get rid of the old one
1325     if (fInputMethodLOCKABLE) {
1326         JNFDeleteGlobalRef(env, fInputMethodLOCKABLE);
1327     }
1328 
1329     // Save a global ref to the new input method.
1330     if (inputMethod != NULL)
1331         fInputMethodLOCKABLE = JNFNewGlobalRef(env, inputMethod);
1332     else
1333         fInputMethodLOCKABLE = NULL;
1334 }
1335 
1336 - (void)abandonInput
1337 {
1338 #ifdef IM_DEBUG
1339     fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n");
1340 #endif // IM_DEBUG
1341 
1342     [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES];
1343     [self unmarkText];
1344 }
1345 
1346 /********************************   END NSTextInputClient Protocol   ********************************/
1347 
1348 
1349 
1350 
1351 @end // AWTView
1352 
1353 /*
1354  * Class:     sun_lwawt_macosx_CPlatformView
1355  * Method:    nativeCreateView
1356  * Signature: (IIII)J
1357  */
1358 JNIEXPORT jlong JNICALL
1359 Java_sun_lwawt_macosx_CPlatformView_nativeCreateView
1360 (JNIEnv *env, jobject obj, jint originX, jint originY, jint width, jint height, jlong windowLayerPtr)
1361 {
1362     __block AWTView *newView = nil;
1363 
1364     JNF_COCOA_ENTER(env);
1365 
1366     NSRect rect = NSMakeRect(originX, originY, width, height);
1367     jobject cPlatformView = (*env)->NewWeakGlobalRef(env, obj);
1368 
1369     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1370 
1371         CALayer *windowLayer = jlong_to_ptr(windowLayerPtr);
1372         newView = [[AWTView alloc] initWithRect:rect
1373                                    platformView:cPlatformView
1374                                     windowLayer:windowLayer];
1375     }];
1376 
1377     JNF_COCOA_EXIT(env);
1378 
1379     return ptr_to_jlong(newView);
1380 }
1381 
1382 /*
1383  * Class:     sun_lwawt_macosx_CPlatformView
1384  * Method:    nativeSetAutoResizable
1385  * Signature: (JZ)V;
1386  */
1387 
1388 JNIEXPORT void JNICALL
1389 Java_sun_lwawt_macosx_CPlatformView_nativeSetAutoResizable
1390 (JNIEnv *env, jclass cls, jlong viewPtr, jboolean toResize)
1391 {
1392     JNF_COCOA_ENTER(env);
1393 
1394     NSView *view = (NSView *)jlong_to_ptr(viewPtr);
1395 
1396     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1397 
1398         if (toResize) {
1399             [view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
1400         } else {
1401             [view setAutoresizingMask: NSViewMinYMargin | NSViewMaxXMargin];
1402         }
1403 
1404         if ([view superview] != nil) {
1405             [[view superview] setAutoresizesSubviews:(BOOL)toResize];
1406         }
1407 
1408     }];
1409     JNF_COCOA_EXIT(env);
1410 }
1411 
1412 /*
1413  * Class:     sun_lwawt_macosx_CPlatformView
1414  * Method:    nativeGetNSViewDisplayID
1415  * Signature: (J)I;
1416  */
1417 
1418 JNIEXPORT jint JNICALL
1419 Java_sun_lwawt_macosx_CPlatformView_nativeGetNSViewDisplayID
1420 (JNIEnv *env, jclass cls, jlong viewPtr)
1421 {
1422     __block jint ret; //CGDirectDisplayID
1423 
1424     JNF_COCOA_ENTER(env);
1425 
1426     NSView *view = (NSView *)jlong_to_ptr(viewPtr);
1427     NSWindow *window = [view window];
1428 
1429     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1430 
1431         ret = (jint)[[AWTWindow getNSWindowDisplayID_AppKitThread: window] intValue];
1432     }];
1433 
1434     JNF_COCOA_EXIT(env);
1435 
1436     return ret;
1437 }
1438 
1439 /*
1440  * Class:     sun_lwawt_macosx_CPlatformView
1441  * Method:    nativeGetLocationOnScreen
1442  * Signature: (J)Ljava/awt/Rectangle;
1443  */
1444 
1445 JNIEXPORT jobject JNICALL
1446 Java_sun_lwawt_macosx_CPlatformView_nativeGetLocationOnScreen
1447 (JNIEnv *env, jclass cls, jlong viewPtr)
1448 {
1449     jobject jRect = NULL;
1450 
1451     JNF_COCOA_ENTER(env);
1452 
1453     __block NSRect rect = NSZeroRect;
1454 
1455     NSView *view = (NSView *)jlong_to_ptr(viewPtr);
1456     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1457 
1458         NSRect viewBounds = [view bounds];
1459         NSRect frameInWindow = [view convertRect:viewBounds toView:nil];
1460         rect = [[view window] convertRectToScreen:frameInWindow];
1461         //Convert coordinates to top-left corner origin
1462         rect = ConvertNSScreenRect(NULL, rect);
1463 
1464     }];
1465     jRect = NSToJavaRect(env, rect);
1466 
1467     JNF_COCOA_EXIT(env);
1468 
1469     return jRect;
1470 }
1471 
1472 /*
1473  * Class:     sun_lwawt_macosx_CPlatformView
1474  * Method:    nativeIsViewUnderMouse
1475  * Signature: (J)Z;
1476  */
1477 
1478 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPlatformView_nativeIsViewUnderMouse
1479 (JNIEnv *env, jclass clazz, jlong viewPtr)
1480 {
1481     __block jboolean underMouse = JNI_FALSE;
1482 
1483     JNF_COCOA_ENTER(env);
1484 
1485     NSView *nsView = OBJC(viewPtr);
1486     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1487         NSPoint ptWindowCoords = [[nsView window] mouseLocationOutsideOfEventStream];
1488         NSPoint ptViewCoords = [nsView convertPoint:ptWindowCoords fromView:nil];
1489         underMouse = [nsView hitTest:ptViewCoords] != nil;
1490     }];
1491 
1492     JNF_COCOA_EXIT(env);
1493 
1494     return underMouse;
1495 }