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