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