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