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