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