| /* |
| * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #import "jni_util.h" |
| #import "CGLGraphicsConfig.h" |
| #import "AWTView.h" |
| #import "AWTWindow.h" |
| #import "JavaComponentAccessibility.h" |
| #import "JavaTextAccessibility.h" |
| #import "JavaAccessibilityUtilities.h" |
| #import "GeomUtilities.h" |
| #import "OSVersion.h" |
| #import "ThreadUtilities.h" |
| |
| #import <JavaNativeFoundation/JavaNativeFoundation.h> |
| |
| @interface AWTView() |
| @property (retain) CDropTarget *_dropTarget; |
| @property (retain) CDragSource *_dragSource; |
| |
| -(void) deliverResize: (NSRect) rect; |
| -(void) resetTrackingArea; |
| -(void) deliverJavaKeyEventHelper: (NSEvent*) event; |
| -(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint; |
| -(NSMutableString *) parseString : (id) complexString; |
| @end |
| |
| // Uncomment this line to see fprintfs of each InputMethod API being called on this View |
| //#define IM_DEBUG TRUE |
| //#define EXTRA_DEBUG |
| |
| static BOOL shouldUsePressAndHold() { |
| static int shouldUsePressAndHold = -1; |
| if (shouldUsePressAndHold != -1) return shouldUsePressAndHold; |
| shouldUsePressAndHold = !isSnowLeopardOrLower(); |
| return shouldUsePressAndHold; |
| } |
| |
| @implementation AWTView |
| |
| @synthesize _dropTarget; |
| @synthesize _dragSource; |
| @synthesize cglLayer; |
| @synthesize mouseIsOver; |
| |
| // Note: Must be called on main (AppKit) thread only |
| - (id) initWithRect: (NSRect) rect |
| platformView: (jobject) cPlatformView |
| windowLayer: (CALayer*) windowLayer |
| { |
| AWT_ASSERT_APPKIT_THREAD; |
| // Initialize ourselves |
| self = [super initWithFrame: rect]; |
| if (self == nil) return self; |
| |
| m_cPlatformView = cPlatformView; |
| fInputMethodLOCKABLE = NULL; |
| fKeyEventsNeeded = NO; |
| fProcessingKeystroke = NO; |
| |
| fEnablePressAndHold = shouldUsePressAndHold(); |
| fInPressAndHold = NO; |
| fPAHNeedsToSelect = NO; |
| |
| mouseIsOver = NO; |
| [self resetTrackingArea]; |
| [self setAutoresizesSubviews:NO]; |
| |
| if (windowLayer != nil) { |
| self.cglLayer = windowLayer; |
| //Layer hosting view |
| [self setLayer: cglLayer]; |
| [self setWantsLayer: YES]; |
| //Layer backed view |
| //[self.layer addSublayer: (CALayer *)cglLayer]; |
| //[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize]; |
| //[self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft]; |
| //[self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; |
| |
| #ifdef REMOTELAYER |
| CGLLayer *parentLayer = (CGLLayer*)self.cglLayer; |
| parentLayer.parentLayer = NULL; |
| parentLayer.remoteLayer = NULL; |
| if (JRSRemotePort != 0 && remoteSocketFD > 0) { |
| CGLLayer *remoteLayer = [[CGLLayer alloc] initWithJavaLayer: parentLayer.javaLayer]; |
| remoteLayer.target = GL_TEXTURE_2D; |
| NSLog(@"Creating Parent=%p, Remote=%p", parentLayer, remoteLayer); |
| parentLayer.remoteLayer = remoteLayer; |
| remoteLayer.parentLayer = parentLayer; |
| remoteLayer.remoteLayer = NULL; |
| remoteLayer.jrsRemoteLayer = [remoteLayer createRemoteLayerBoundTo:JRSRemotePort]; |
| [remoteLayer retain]; // REMIND |
| remoteLayer.frame = CGRectMake(0, 0, 720, 500); // REMIND |
| [remoteLayer.jrsRemoteLayer retain]; // REMIND |
| int layerID = [remoteLayer.jrsRemoteLayer layerID]; |
| NSLog(@"layer id to send = %d", layerID); |
| sendLayerID(layerID); |
| } |
| #endif /* REMOTELAYER */ |
| } |
| |
| return self; |
| } |
| |
| - (void) dealloc { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| self.cglLayer = nil; |
| |
| JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; |
| (*env)->DeleteWeakGlobalRef(env, m_cPlatformView); |
| m_cPlatformView = NULL; |
| |
| if (fInputMethodLOCKABLE != NULL) |
| { |
| JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; |
| |
| JNFDeleteGlobalRef(env, fInputMethodLOCKABLE); |
| fInputMethodLOCKABLE = NULL; |
| } |
| |
| |
| [super dealloc]; |
| } |
| |
| - (void) viewDidMoveToWindow { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| [AWTToolkit eventCountPlusPlus]; |
| |
| [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^() { |
| [[self window] makeFirstResponder: self]; |
| }]; |
| if ([self window] != NULL) { |
| [self resetTrackingArea]; |
| } |
| } |
| |
| - (BOOL) acceptsFirstMouse: (NSEvent *)event { |
| return YES; |
| } |
| |
| - (BOOL) acceptsFirstResponder { |
| return YES; |
| } |
| |
| - (BOOL) becomeFirstResponder { |
| return YES; |
| } |
| |
| - (BOOL) preservesContentDuringLiveResize { |
| return YES; |
| } |
| |
| /* |
| * Automatically triggered functions. |
| */ |
| |
| - (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize { |
| [super resizeWithOldSuperviewSize: oldBoundsSize]; |
| [self deliverResize: [self frame]]; |
| } |
| |
| /* |
| * MouseEvents support |
| */ |
| |
| - (void) mouseDown: (NSEvent *)event { |
| NSInputManager *inputManager = [NSInputManager currentInputManager]; |
| if ([inputManager wantsToHandleMouseEvents]) { |
| #if IM_DEBUG |
| NSLog(@"-> IM wants to handle event"); |
| #endif |
| if (![inputManager handleMouseEvent:event]) { |
| [self deliverJavaMouseEvent: event]; |
| } else { |
| #if IM_DEBUG |
| NSLog(@"-> Event was handled."); |
| #endif |
| } |
| } else { |
| #if IM_DEBUG |
| NSLog(@"-> IM does not want to handle event"); |
| #endif |
| [self deliverJavaMouseEvent: event]; |
| } |
| } |
| |
| - (void) mouseUp: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) rightMouseDown: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) rightMouseUp: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) otherMouseDown: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) otherMouseUp: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) mouseMoved: (NSEvent *)event { |
| // TODO: better way to redirect move events to the "under" view |
| |
| NSPoint eventLocation = [event locationInWindow]; |
| NSPoint localPoint = [self convertPoint: eventLocation fromView: nil]; |
| |
| if ([self mouse: localPoint inRect: [self bounds]]) { |
| [self deliverJavaMouseEvent: event]; |
| } else { |
| [[self nextResponder] mouseDown:event]; |
| } |
| } |
| |
| - (void) mouseDragged: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) rightMouseDragged: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) otherMouseDragged: (NSEvent *)event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) mouseEntered: (NSEvent *)event { |
| [[self window] setAcceptsMouseMovedEvents:YES]; |
| //[[self window] makeFirstResponder:self]; |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| - (void) mouseExited: (NSEvent *)event { |
| [[self window] setAcceptsMouseMovedEvents:NO]; |
| [self deliverJavaMouseEvent: event]; |
| //Restore the cursor back. |
| //[CCursorManager _setCursor: [NSCursor arrowCursor]]; |
| } |
| |
| - (void) scrollWheel: (NSEvent*) event { |
| [self deliverJavaMouseEvent: event]; |
| } |
| |
| /* |
| * KeyEvents support |
| */ |
| |
| - (void) keyDown: (NSEvent *)event { |
| fProcessingKeystroke = YES; |
| fKeyEventsNeeded = YES; |
| |
| // Allow TSM to look at the event and potentially send back NSTextInputClient messages. |
| [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| |
| if (fEnablePressAndHold && [event willBeHandledByComplexInputMethod] && fInputMethodLOCKABLE) { |
| fProcessingKeystroke = NO; |
| if (!fInPressAndHold) { |
| fInPressAndHold = YES; |
| fPAHNeedsToSelect = YES; |
| } |
| return; |
| } |
| |
| NSString *eventCharacters = [event characters]; |
| BOOL isDeadKey = (eventCharacters != nil && [eventCharacters length] == 0); |
| |
| if ((![self hasMarkedText] && fKeyEventsNeeded) || isDeadKey) { |
| [self deliverJavaKeyEventHelper: event]; |
| } |
| |
| fProcessingKeystroke = NO; |
| } |
| |
| - (void) keyUp: (NSEvent *)event { |
| [self deliverJavaKeyEventHelper: event]; |
| } |
| |
| - (void) flagsChanged: (NSEvent *)event { |
| [self deliverJavaKeyEventHelper: event]; |
| } |
| |
| - (BOOL) performKeyEquivalent: (NSEvent *) event { |
| // if IM is active key events should be ignored |
| if (![self hasMarkedText] && !fInPressAndHold) { |
| [self deliverJavaKeyEventHelper: event]; |
| } |
| |
| // Workaround for 8020209: special case for "Cmd =" and "Cmd ." |
| // because Cocoa calls performKeyEquivalent twice for these keystrokes |
| NSUInteger modFlags = [event modifierFlags] & |
| (NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask); |
| if (modFlags == NSCommandKeyMask) { |
| NSString *eventChars = [event charactersIgnoringModifiers]; |
| if ([eventChars length] == 1) { |
| unichar ch = [eventChars characterAtIndex:0]; |
| if (ch == '=' || ch == '.') { |
| [[NSApp mainMenu] performKeyEquivalent: event]; |
| return YES; |
| } |
| } |
| |
| } |
| |
| return NO; |
| } |
| |
| /** |
| * Utility methods and accessors |
| */ |
| |
| -(void) deliverJavaMouseEvent: (NSEvent *) event { |
| BOOL isEnabled = YES; |
| NSWindow* window = [self window]; |
| if ([window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]]) { |
| isEnabled = [(AWTWindow*)[window delegate] isEnabled]; |
| } |
| |
| if (!isEnabled) { |
| return; |
| } |
| |
| NSEventType type = [event type]; |
| |
| // check synthesized mouse entered/exited events |
| if ((type == NSMouseEntered && mouseIsOver) || (type == NSMouseExited && !mouseIsOver)) { |
| return; |
| }else if ((type == NSMouseEntered && !mouseIsOver) || (type == NSMouseExited && mouseIsOver)) { |
| mouseIsOver = !mouseIsOver; |
| } |
| |
| [AWTToolkit eventCountPlusPlus]; |
| |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| NSPoint eventLocation = [event locationInWindow]; |
| NSPoint localPoint = [self convertPoint: eventLocation fromView: nil]; |
| NSPoint absP = [NSEvent mouseLocation]; |
| |
| // Convert global numbers between Cocoa's coordinate system and Java. |
| // TODO: need consitent way for doing that both with global as well as with local coordinates. |
| // The reason to do it here is one more native method for getting screen dimension otherwise. |
| |
| NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; |
| absP.y = screenRect.size.height - absP.y; |
| jint clickCount; |
| |
| if (type == NSMouseEntered || |
| type == NSMouseExited || |
| type == NSScrollWheel || |
| type == NSMouseMoved) { |
| clickCount = 0; |
| } else { |
| clickCount = [event clickCount]; |
| } |
| |
| jdouble deltaX = [event deltaX]; |
| jdouble deltaY = [event deltaY]; |
| if ([AWTToolkit hasPreciseScrollingDeltas: event]) { |
| deltaX = [event scrollingDeltaX] * 0.1; |
| deltaY = [event scrollingDeltaY] * 0.1; |
| } |
| |
| static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); |
| static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V"); |
| jobject jEvent = JNFNewObject(env, jctor_NSEvent, |
| [event type], |
| [event modifierFlags], |
| clickCount, |
| [event buttonNumber], |
| (jint)localPoint.x, (jint)localPoint.y, |
| (jint)absP.x, (jint)absP.y, |
| deltaY, |
| deltaX, |
| [AWTToolkit scrollStateWithEvent: event]); |
| CHECK_NULL(jEvent); |
| |
| static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView"); |
| static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/NSEvent;)V"); |
| jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView); |
| if (!(*env)->IsSameObject(env, jlocal, NULL)) { |
| JNFCallVoidMethod(env, jlocal, jm_deliverMouseEvent, jEvent); |
| (*env)->DeleteLocalRef(env, jlocal); |
| } |
| (*env)->DeleteLocalRef(env, jEvent); |
| } |
| |
| - (void) resetTrackingArea { |
| if (rolloverTrackingArea != nil) { |
| [self removeTrackingArea:rolloverTrackingArea]; |
| [rolloverTrackingArea release]; |
| } |
| |
| int options = (NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited | |
| NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag); |
| |
| rolloverTrackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] |
| options: options |
| owner:self |
| userInfo:nil |
| ]; |
| [self addTrackingArea:rolloverTrackingArea]; |
| } |
| |
| - (void)updateTrackingAreas { |
| [super updateTrackingAreas]; |
| [self resetTrackingArea]; |
| } |
| |
| - (void) resetCursorRects { |
| [super resetCursorRects]; |
| [self resetTrackingArea]; |
| } |
| |
| -(void) deliverJavaKeyEventHelper: (NSEvent *) event { |
| static NSEvent* sLastKeyEvent = nil; |
| if (event == sLastKeyEvent) { |
| // The event is repeatedly delivered by keyDown: after performKeyEquivalent: |
| return; |
| } |
| [sLastKeyEvent release]; |
| sLastKeyEvent = [event retain]; |
| |
| [AWTToolkit eventCountPlusPlus]; |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| jstring characters = NULL; |
| jstring charactersIgnoringModifiers = NULL; |
| if ([event type] != NSFlagsChanged) { |
| characters = JNFNSToJavaString(env, [event characters]); |
| charactersIgnoringModifiers = JNFNSToJavaString(env, [event charactersIgnoringModifiers]); |
| } |
| |
| static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); |
| static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IISLjava/lang/String;Ljava/lang/String;)V"); |
| jobject jEvent = JNFNewObject(env, jctor_NSEvent, |
| [event type], |
| [event modifierFlags], |
| [event keyCode], |
| characters, |
| charactersIgnoringModifiers); |
| CHECK_NULL(jEvent); |
| |
| static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView"); |
| static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_PlatformView, |
| "deliverKeyEvent", "(Lsun/lwawt/macosx/NSEvent;)V"); |
| jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView); |
| if (!(*env)->IsSameObject(env, jlocal, NULL)) { |
| JNFCallVoidMethod(env, jlocal, jm_deliverKeyEvent, jEvent); |
| (*env)->DeleteLocalRef(env, jlocal); |
| } |
| if (characters != NULL) { |
| (*env)->DeleteLocalRef(env, characters); |
| } |
| (*env)->DeleteLocalRef(env, jEvent); |
| } |
| |
| -(void) deliverResize: (NSRect) rect { |
| jint x = (jint) rect.origin.x; |
| jint y = (jint) rect.origin.y; |
| jint w = (jint) rect.size.width; |
| jint h = (jint) rect.size.height; |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView"); |
| static JNF_MEMBER_CACHE(jm_deliverResize, jc_PlatformView, "deliverResize", "(IIII)V"); |
| |
| jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView); |
| if (!(*env)->IsSameObject(env, jlocal, NULL)) { |
| JNFCallVoidMethod(env, jlocal, jm_deliverResize, x,y,w,h); |
| (*env)->DeleteLocalRef(env, jlocal); |
| } |
| } |
| |
| |
| - (void) drawRect:(NSRect)dirtyRect { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| [super drawRect:dirtyRect]; |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| if (env != NULL) { |
| /* |
| if ([self inLiveResize]) { |
| NSRect rs[4]; |
| NSInteger count; |
| [self getRectsExposedDuringLiveResize:rs count:&count]; |
| for (int i = 0; i < count; i++) { |
| JNU_CallMethodByName(env, NULL, [m_awtWindow cPlatformView], |
| "deliverWindowDidExposeEvent", "(FFFF)V", |
| (jfloat)rs[i].origin.x, (jfloat)rs[i].origin.y, |
| (jfloat)rs[i].size.width, (jfloat)rs[i].size.height); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| } |
| } else { |
| */ |
| static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView"); |
| static JNF_MEMBER_CACHE(jm_deliverWindowDidExposeEvent, jc_CPlatformView, "deliverWindowDidExposeEvent", "()V"); |
| jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView); |
| if (!(*env)->IsSameObject(env, jlocal, NULL)) { |
| JNFCallVoidMethod(env, jlocal, jm_deliverWindowDidExposeEvent); |
| (*env)->DeleteLocalRef(env, jlocal); |
| } |
| /* |
| } |
| */ |
| } |
| } |
| |
| -(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint { |
| if (((codePoint >= 0x3000) && (codePoint <= 0x303F)) || |
| ((codePoint >= 0xFF00) && (codePoint <= 0xFFEF))) { |
| // Code point is in 'CJK Symbols and Punctuation' or |
| // 'Halfwidth and Fullwidth Forms' Unicode block. |
| return YES; |
| } |
| return NO; |
| } |
| |
| -(NSMutableString *) parseString : (id) complexString { |
| if ([complexString isKindOfClass:[NSString class]]) { |
| return [complexString mutableCopy]; |
| } |
| else { |
| return [complexString mutableString]; |
| } |
| } |
| |
| // NSAccessibility support |
| - (jobject)awtComponent:(JNIEnv*)env |
| { |
| static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView"); |
| static JNF_MEMBER_CACHE(jf_Peer, jc_CPlatformView, "peer", "Lsun/lwawt/LWWindowPeer;"); |
| if ((env == NULL) || (m_cPlatformView == NULL)) { |
| NSLog(@"Apple AWT : Error AWTView:awtComponent given bad parameters."); |
| if (env != NULL) |
| { |
| JNFDumpJavaStack(env); |
| } |
| return NULL; |
| } |
| |
| jobject peer = NULL; |
| jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView); |
| if (!(*env)->IsSameObject(env, jlocal, NULL)) { |
| peer = JNFGetObjectField(env, jlocal, jf_Peer); |
| (*env)->DeleteLocalRef(env, jlocal); |
| } |
| static JNF_CLASS_CACHE(jc_LWWindowPeer, "sun/lwawt/LWWindowPeer"); |
| static JNF_MEMBER_CACHE(jf_Target, jc_LWWindowPeer, "target", "Ljava/awt/Component;"); |
| if (peer == NULL) { |
| NSLog(@"Apple AWT : Error AWTView:awtComponent got null peer from CPlatformView"); |
| JNFDumpJavaStack(env); |
| return NULL; |
| } |
| jobject comp = JNFGetObjectField(env, peer, jf_Target); |
| (*env)->DeleteLocalRef(env, peer); |
| return comp; |
| } |
| |
| + (AWTView *) awtView:(JNIEnv*)env ofAccessible:(jobject)jaccessible |
| { |
| static JNF_STATIC_MEMBER_CACHE(jm_getAWTView, sjc_CAccessibility, "getAWTView", "(Ljavax/accessibility/Accessible;)J"); |
| |
| jlong jptr = JNFCallStaticLongMethod(env, jm_getAWTView, jaccessible); |
| if (jptr == 0) return nil; |
| |
| return (AWTView *)jlong_to_ptr(jptr); |
| } |
| |
| - (id)getAxData:(JNIEnv*)env |
| { |
| jobject jcomponent = [self awtComponent:env]; |
| id ax = [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease]; |
| (*env)->DeleteLocalRef(env, jcomponent); |
| return ax; |
| } |
| |
| - (NSArray *)accessibilityAttributeNames |
| { |
| return [[super accessibilityAttributeNames] arrayByAddingObject:NSAccessibilityChildrenAttribute]; |
| } |
| |
| // NSAccessibility messages |
| // attribute methods |
| - (id)accessibilityAttributeValue:(NSString *)attribute |
| { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) |
| { |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| (*env)->PushLocalFrame(env, 4); |
| |
| id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]); |
| |
| (*env)->PopLocalFrame(env, NULL); |
| |
| return result; |
| } |
| else |
| { |
| return [super accessibilityAttributeValue:attribute]; |
| } |
| } |
| - (BOOL)accessibilityIsIgnored |
| { |
| return YES; |
| } |
| |
| - (id)accessibilityHitTest:(NSPoint)point |
| { |
| AWT_ASSERT_APPKIT_THREAD; |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| (*env)->PushLocalFrame(env, 4); |
| |
| id result = [[self getAxData:env] accessibilityHitTest:point withEnv:env]; |
| |
| (*env)->PopLocalFrame(env, NULL); |
| |
| return result; |
| } |
| |
| - (id)accessibilityFocusedUIElement |
| { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| (*env)->PushLocalFrame(env, 4); |
| |
| id result = [[self getAxData:env] accessibilityFocusedUIElement]; |
| |
| (*env)->PopLocalFrame(env, NULL); |
| |
| return result; |
| } |
| |
| // --- Services menu support for lightweights --- |
| |
| // finds the focused accessible element, and if it is a text element, obtains the text from it |
| - (NSString *)accessibleSelectedText |
| { |
| id focused = [self accessibilityFocusedUIElement]; |
| if (![focused isKindOfClass:[JavaTextAccessibility class]]) return nil; |
| return [(JavaTextAccessibility *)focused accessibilitySelectedTextAttribute]; |
| } |
| |
| // same as above, but converts to RTFD |
| - (NSData *)accessibleSelectedTextAsRTFD |
| { |
| NSString *selectedText = [self accessibleSelectedText]; |
| NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText]; |
| NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length]) |
| documentAttributes: |
| @{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}]; |
| [styledText release]; |
| return rtfdData; |
| } |
| |
| // finds the focused accessible element, and if it is a text element, sets the text in it |
| - (BOOL)replaceAccessibleTextSelection:(NSString *)text |
| { |
| id focused = [self accessibilityFocusedUIElement]; |
| if (![focused isKindOfClass:[JavaTextAccessibility class]]) return NO; |
| [(JavaTextAccessibility *)focused accessibilitySetSelectedTextAttribute:text]; |
| return YES; |
| } |
| |
| // called for each service in the Services menu - only handle text for now |
| - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType |
| { |
| if ([[self window] firstResponder] != self) return nil; // let AWT components handle themselves |
| |
| if ([sendType isEqual:NSStringPboardType] || [returnType isEqual:NSStringPboardType]) { |
| NSString *selectedText = [self accessibleSelectedText]; |
| if (selectedText) return self; |
| } |
| |
| return nil; |
| } |
| |
| // fetch text from Java and hand off to the service |
| - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types |
| { |
| if ([types containsObject:NSStringPboardType]) |
| { |
| [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; |
| return [pboard setString:[self accessibleSelectedText] forType:NSStringPboardType]; |
| } |
| |
| if ([types containsObject:NSRTFDPboardType]) |
| { |
| [pboard declareTypes:[NSArray arrayWithObject:NSRTFDPboardType] owner:nil]; |
| return [pboard setData:[self accessibleSelectedTextAsRTFD] forType:NSRTFDPboardType]; |
| } |
| |
| return NO; |
| } |
| |
| // write text back to Java from the service |
| - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard |
| { |
| if ([[pboard types] containsObject:NSStringPboardType]) |
| { |
| NSString *text = [pboard stringForType:NSStringPboardType]; |
| return [self replaceAccessibleTextSelection:text]; |
| } |
| |
| if ([[pboard types] containsObject:NSRTFDPboardType]) |
| { |
| NSData *rtfdData = [pboard dataForType:NSRTFDPboardType]; |
| NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:NULL]; |
| NSString *text = [styledText string]; |
| [styledText release]; |
| |
| return [self replaceAccessibleTextSelection:text]; |
| } |
| |
| return NO; |
| } |
| |
| |
| -(void) setDragSource:(CDragSource *)source { |
| self._dragSource = source; |
| } |
| |
| |
| - (void) setDropTarget:(CDropTarget *)target { |
| self._dropTarget = target; |
| [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) on:self._dropTarget withObject:nil waitUntilDone:YES]; |
| } |
| |
| /******************************** BEGIN NSDraggingSource Interface ********************************/ |
| |
| - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| NSDragOperation dragOp = NSDragOperationNone; |
| |
| if (dragSource != nil) { |
| dragOp = [dragSource draggingSourceOperationMaskForLocal:flag]; |
| } |
| return dragOp; |
| } |
| |
| - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| NSArray* array = nil; |
| |
| if (dragSource != nil) { |
| array = [dragSource namesOfPromisedFilesDroppedAtDestination:dropDestination]; |
| } |
| return array; |
| } |
| |
| - (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| |
| if (dragSource != nil) { |
| [dragSource draggedImage:image beganAt:screenPoint]; |
| } |
| } |
| |
| - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| |
| if (dragSource != nil) { |
| [dragSource draggedImage:image endedAt:screenPoint operation:operation]; |
| } |
| } |
| |
| - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| |
| if (dragSource != nil) { |
| [dragSource draggedImage:image movedTo:screenPoint]; |
| } |
| } |
| |
| - (BOOL)ignoreModifierKeysWhileDragging |
| { |
| // If draggingSource is nil route the message to the superclass (if responding to the selector): |
| CDragSource *dragSource = self._dragSource; |
| BOOL result = FALSE; |
| |
| if (dragSource != nil) { |
| result = [dragSource ignoreModifierKeysWhileDragging]; |
| } |
| return result; |
| } |
| |
| /******************************** END NSDraggingSource Interface ********************************/ |
| |
| /******************************** BEGIN NSDraggingDestination Interface ********************************/ |
| |
| - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| NSDragOperation dragOp = NSDragOperationNone; |
| |
| if (dropTarget != nil) { |
| dragOp = [dropTarget draggingEntered:sender]; |
| } |
| return dragOp; |
| } |
| |
| - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| NSDragOperation dragOp = NSDragOperationNone; |
| |
| if (dropTarget != nil) { |
| dragOp = [dropTarget draggingUpdated:sender]; |
| } |
| return dragOp; |
| } |
| |
| - (void)draggingExited:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| |
| if (dropTarget != nil) { |
| [dropTarget draggingExited:sender]; |
| } |
| } |
| |
| - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| BOOL result = FALSE; |
| |
| if (dropTarget != nil) { |
| result = [dropTarget prepareForDragOperation:sender]; |
| } |
| return result; |
| } |
| |
| - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| BOOL result = FALSE; |
| |
| if (dropTarget != nil) { |
| result = [dropTarget performDragOperation:sender]; |
| } |
| return result; |
| } |
| |
| - (void)concludeDragOperation:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| |
| if (dropTarget != nil) { |
| [dropTarget concludeDragOperation:sender]; |
| } |
| } |
| |
| - (void)draggingEnded:(id <NSDraggingInfo>)sender |
| { |
| // If draggingDestination is nil route the message to the superclass: |
| CDropTarget *dropTarget = self._dropTarget; |
| |
| if (dropTarget != nil) { |
| [dropTarget draggingEnded:sender]; |
| } |
| } |
| |
| /******************************** END NSDraggingDestination Interface ********************************/ |
| |
| /******************************** BEGIN NSTextInputClient Protocol ********************************/ |
| |
| |
| JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod"); |
| |
| - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [insertText]: %s\n", [aString UTF8String]); |
| #endif // IM_DEBUG |
| |
| if (fInputMethodLOCKABLE == NULL) { |
| return; |
| } |
| |
| // Insert happens at the end of PAH |
| fInPressAndHold = NO; |
| |
| // insertText gets called when the user commits text generated from an input method. It also gets |
| // called during ordinary input as well. We only need to send an input method event when we have marked |
| // text, or 'text in progress'. We also need to send the event if we get an insert text out of the blue! |
| // (i.e., when the user uses the Character palette or Inkwell), or when the string to insert is a complex |
| // Unicode value. |
| |
| NSMutableString * useString = [self parseString:aString]; |
| NSUInteger utf16Length = [useString lengthOfBytesUsingEncoding:NSUTF16StringEncoding]; |
| NSUInteger utf8Length = [useString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; |
| BOOL aStringIsComplex = NO; |
| if ((utf16Length > 2) || |
| ((utf8Length > 1) && [self isCodePointInUnicodeBlockNeedingIMEvent:[useString characterAtIndex:0]])) { |
| aStringIsComplex = YES; |
| } |
| |
| if ([self hasMarkedText] || !fProcessingKeystroke || aStringIsComplex) { |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V"); |
| // We need to select the previous glyph so that it is overwritten. |
| if (fPAHNeedsToSelect) { |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph); |
| fPAHNeedsToSelect = NO; |
| } |
| |
| static JNF_MEMBER_CACHE(jm_insertText, jc_CInputMethod, "insertText", "(Ljava/lang/String;)V"); |
| jstring insertedText = JNFNSToJavaString(env, useString); |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_insertText, insertedText); // AWT_THREADING Safe (AWTRunLoopMode) |
| (*env)->DeleteLocalRef(env, insertedText); |
| |
| // The input method event will create psuedo-key events for each character in the committed string. |
| // We also don't want to send the character that triggered the insertText, usually a return. [3337563] |
| fKeyEventsNeeded = NO; |
| } |
| else { |
| // Need to set back the fKeyEventsNeeded flag so that the string following the |
| // marked text is not ignored by keyDown |
| if ([useString length] > 0) { |
| fKeyEventsNeeded = YES; |
| } |
| } |
| fPAHNeedsToSelect = NO; |
| } |
| |
| - (void) doCommandBySelector:(SEL)aSelector |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [doCommandBySelector]\n"); |
| NSLog(@"%@", NSStringFromSelector(aSelector)); |
| #endif // IM_DEBUG |
| if (@selector(insertNewline:) == aSelector || @selector(insertTab:) == aSelector || @selector(deleteBackward:) == aSelector) |
| { |
| fKeyEventsNeeded = YES; |
| } |
| } |
| |
| // setMarkedText: cannot take a nil first argument. aString can be NSString or NSAttributedString |
| - (void) setMarkedText:(id)aString selectedRange:(NSRange)selectionRange replacementRange:(NSRange)replacementRange |
| { |
| if (!fInputMethodLOCKABLE) |
| return; |
| |
| BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]]; |
| NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil); |
| NSString *incomingString = (isAttributedString ? [aString string] : aString); |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [setMarkedText] \"%s\", loc=%lu, length=%lu\n", [incomingString UTF8String], (unsigned long)selectionRange.location, (unsigned long)selectionRange.length); |
| #endif // IM_DEBUG |
| static JNF_MEMBER_CACHE(jm_startIMUpdate, jc_CInputMethod, "startIMUpdate", "(Ljava/lang/String;)V"); |
| static JNF_MEMBER_CACHE(jm_addAttribute, jc_CInputMethod, "addAttribute", "(ZZII)V"); |
| static JNF_MEMBER_CACHE(jm_dispatchText, jc_CInputMethod, "dispatchText", "(IIZ)V"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| // NSInputContext already did the analysis of the TSM event and created attributes indicating |
| // the underlining and color that should be done to the string. We need to look at the underline |
| // style and color to determine what kind of Java hilighting needs to be done. |
| jstring inProcessText = JNFNSToJavaString(env, incomingString); |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_startIMUpdate, inProcessText); // AWT_THREADING Safe (AWTRunLoopMode) |
| (*env)->DeleteLocalRef(env, inProcessText); |
| |
| if (isAttributedString) { |
| NSUInteger length; |
| NSRange effectiveRange; |
| NSDictionary *attributes; |
| length = [attrString length]; |
| effectiveRange = NSMakeRange(0, 0); |
| while (NSMaxRange(effectiveRange) < length) { |
| attributes = [attrString attributesAtIndex:NSMaxRange(effectiveRange) |
| effectiveRange:&effectiveRange]; |
| if (attributes) { |
| BOOL isThickUnderline, isGray; |
| NSNumber *underlineSizeObj = |
| (NSNumber *)[attributes objectForKey:NSUnderlineStyleAttributeName]; |
| NSInteger underlineSize = [underlineSizeObj integerValue]; |
| isThickUnderline = (underlineSize > 1); |
| |
| NSColor *underlineColorObj = |
| (NSColor *)[attributes objectForKey:NSUnderlineColorAttributeName]; |
| isGray = !([underlineColorObj isEqual:[NSColor blackColor]]); |
| |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_addAttribute, isThickUnderline, isGray, effectiveRange.location, effectiveRange.length); // AWT_THREADING Safe (AWTRunLoopMode) |
| } |
| } |
| } |
| |
| static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V"); |
| // We need to select the previous glyph so that it is overwritten. |
| if (fPAHNeedsToSelect) { |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph); |
| fPAHNeedsToSelect = NO; |
| } |
| |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_dispatchText, selectionRange.location, selectionRange.length, JNI_FALSE); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| // If the marked text is being cleared (zero-length string) don't handle the key event. |
| if ([incomingString length] == 0) { |
| fKeyEventsNeeded = NO; |
| } |
| } |
| |
| - (void) unmarkText |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [unmarkText]\n"); |
| #endif // IM_DEBUG |
| |
| if (!fInputMethodLOCKABLE) { |
| return; |
| } |
| |
| // unmarkText cancels any input in progress and commits it to the text field. |
| static JNF_MEMBER_CACHE(jm_unmarkText, jc_CInputMethod, "unmarkText", "()V"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| JNFCallVoidMethod(env, fInputMethodLOCKABLE, jm_unmarkText); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| } |
| |
| - (BOOL) hasMarkedText |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [hasMarkedText]\n"); |
| #endif // IM_DEBUG |
| |
| if (!fInputMethodLOCKABLE) { |
| return NO; |
| } |
| |
| static JNF_MEMBER_CACHE(jf_fCurrentText, jc_CInputMethod, "fCurrentText", "Ljava/text/AttributedString;"); |
| static JNF_MEMBER_CACHE(jf_fCurrentTextLength, jc_CInputMethod, "fCurrentTextLength", "I"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| jobject currentText = JNFGetObjectField(env, fInputMethodLOCKABLE, jf_fCurrentText); |
| |
| jint currentTextLength = JNFGetIntField(env, fInputMethodLOCKABLE, jf_fCurrentTextLength); |
| |
| BOOL hasMarkedText = (currentText != NULL && currentTextLength > 0); |
| |
| if (currentText != NULL) { |
| (*env)->DeleteLocalRef(env, currentText); |
| } |
| |
| return hasMarkedText; |
| } |
| |
| - (NSInteger) conversationIdentifier |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [conversationIdentifier]\n"); |
| #endif // IM_DEBUG |
| |
| return (NSInteger) self; |
| } |
| |
| /* Returns attributed string at the range. This allows input mangers to |
| query any range in backing-store (Andy's request) |
| */ |
| - (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [attributedSubstringFromRange] location=%lu, length=%lu\n", (unsigned long)theRange.location, (unsigned long)theRange.length); |
| #endif // IM_DEBUG |
| |
| static JNF_MEMBER_CACHE(jm_substringFromRange, jc_CInputMethod, "attributedSubstringFromRange", "(II)Ljava/lang/String;"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| jobject theString = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_substringFromRange, theRange.location, theRange.length); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| id result = [[[NSAttributedString alloc] initWithString:JNFJavaToNSString(env, theString)] autorelease]; |
| #ifdef IM_DEBUG |
| NSLog(@"attributedSubstringFromRange returning \"%@\"", result); |
| #endif // IM_DEBUG |
| |
| (*env)->DeleteLocalRef(env, theString); |
| return result; |
| } |
| |
| /* This method returns the range for marked region. If hasMarkedText == false, |
| it'll return NSNotFound location & 0 length range. |
| */ |
| - (NSRange) markedRange |
| { |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [markedRange]\n"); |
| #endif // IM_DEBUG |
| |
| if (!fInputMethodLOCKABLE) { |
| return NSMakeRange(NSNotFound, 0); |
| } |
| |
| static JNF_MEMBER_CACHE(jm_markedRange, jc_CInputMethod, "markedRange", "()[I"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| jarray array; |
| jboolean isCopy; |
| jint *_array; |
| NSRange range = NSMakeRange(NSNotFound, 0); |
| |
| array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_markedRange); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| if (array) { |
| _array = (*env)->GetIntArrayElements(env, array, &isCopy); |
| if (_array != NULL) { |
| range.location = _array[0]; |
| range.length = _array[1]; |
| #ifdef IM_DEBUG |
| fprintf(stderr, "markedRange returning (%lu, %lu)\n", |
| (unsigned long)range.location, (unsigned long)range.length); |
| #endif // IM_DEBUG |
| (*env)->ReleaseIntArrayElements(env, array, _array, 0); |
| } |
| (*env)->DeleteLocalRef(env, array); |
| } |
| |
| return range; |
| } |
| |
| /* This method returns the range for selected region. Just like markedRange method, |
| its location field contains char index from the text beginning. |
| */ |
| - (NSRange) selectedRange |
| { |
| if (!fInputMethodLOCKABLE) { |
| return NSMakeRange(NSNotFound, 0); |
| } |
| |
| static JNF_MEMBER_CACHE(jm_selectedRange, jc_CInputMethod, "selectedRange", "()[I"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| jarray array; |
| jboolean isCopy; |
| jint *_array; |
| NSRange range = NSMakeRange(NSNotFound, 0); |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [selectedRange]\n"); |
| #endif // IM_DEBUG |
| |
| array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_selectedRange); // AWT_THREADING Safe (AWTRunLoopMode) |
| if (array) { |
| _array = (*env)->GetIntArrayElements(env, array, &isCopy); |
| if (_array != NULL) { |
| range.location = _array[0]; |
| range.length = _array[1]; |
| (*env)->ReleaseIntArrayElements(env, array, _array, 0); |
| } |
| (*env)->DeleteLocalRef(env, array); |
| } |
| |
| return range; |
| } |
| |
| /* This method returns the first frame of rects for theRange in screen coordindate system. |
| */ |
| - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange |
| { |
| if (!fInputMethodLOCKABLE) { |
| return NSZeroRect; |
| } |
| |
| static JNF_MEMBER_CACHE(jm_firstRectForCharacterRange, jc_CInputMethod, |
| "firstRectForCharacterRange", "(I)[I"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| jarray array; |
| jboolean isCopy; |
| jint *_array; |
| NSRect rect; |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, |
| "AWTView InputMethod Selector Called : [firstRectForCharacterRange:] location=%lu, length=%lu\n", |
| (unsigned long)theRange.location, (unsigned long)theRange.length); |
| #endif // IM_DEBUG |
| |
| array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_firstRectForCharacterRange, |
| theRange.location); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| _array = (*env)->GetIntArrayElements(env, array, &isCopy); |
| if (_array) { |
| rect = ConvertNSScreenRect(env, NSMakeRect(_array[0], _array[1], _array[2], _array[3])); |
| (*env)->ReleaseIntArrayElements(env, array, _array, 0); |
| } else { |
| rect = NSZeroRect; |
| } |
| (*env)->DeleteLocalRef(env, array); |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, |
| "firstRectForCharacterRange returning x=%f, y=%f, width=%f, height=%f\n", |
| rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); |
| #endif // IM_DEBUG |
| return rect; |
| } |
| |
| /* This method returns the index for character that is nearest to thePoint. thPoint is in |
| screen coordinate system. |
| */ |
| - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint |
| { |
| if (!fInputMethodLOCKABLE) { |
| return NSNotFound; |
| } |
| |
| static JNF_MEMBER_CACHE(jm_characterIndexForPoint, jc_CInputMethod, |
| "characterIndexForPoint", "(II)I"); |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| NSPoint flippedLocation = ConvertNSScreenPoint(env, thePoint); |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [characterIndexForPoint:(NSPoint)thePoint] x=%f, y=%f\n", flippedLocation.x, flippedLocation.y); |
| #endif // IM_DEBUG |
| |
| jint index = JNFCallIntMethod(env, fInputMethodLOCKABLE, jm_characterIndexForPoint, (jint)flippedLocation.x, (jint)flippedLocation.y); // AWT_THREADING Safe (AWTRunLoopMode) |
| |
| #ifdef IM_DEBUG |
| fprintf(stderr, "characterIndexForPoint returning %ld\n", index); |
| #endif // IM_DEBUG |
| |
| if (index == -1) { |
| return NSNotFound; |
| } else { |
| return (NSUInteger)index; |
| } |
| } |
| |
| - (NSArray*) validAttributesForMarkedText |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [validAttributesForMarkedText]\n"); |
| #endif // IM_DEBUG |
| |
| return [NSArray array]; |
| } |
| |
| - (void)setInputMethod:(jobject)inputMethod |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [setInputMethod]\n"); |
| #endif // IM_DEBUG |
| |
| JNIEnv *env = [ThreadUtilities getJNIEnv]; |
| |
| // Get rid of the old one |
| if (fInputMethodLOCKABLE) { |
| JNFDeleteGlobalRef(env, fInputMethodLOCKABLE); |
| } |
| |
| // Save a global ref to the new input method. |
| if (inputMethod != NULL) |
| fInputMethodLOCKABLE = JNFNewGlobalRef(env, inputMethod); |
| else |
| fInputMethodLOCKABLE = NULL; |
| } |
| |
| - (void)abandonInput |
| { |
| #ifdef IM_DEBUG |
| fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n"); |
| #endif // IM_DEBUG |
| |
| [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES]; |
| [self unmarkText]; |
| } |
| |
| /******************************** END NSTextInputClient Protocol ********************************/ |
| |
| |
| |
| |
| @end // AWTView |
| |
| /* |
| * Class: sun_lwawt_macosx_CPlatformView |
| * Method: nativeCreateView |
| * Signature: (IIII)J |
| */ |
| JNIEXPORT jlong JNICALL |
| Java_sun_lwawt_macosx_CPlatformView_nativeCreateView |
| (JNIEnv *env, jobject obj, jint originX, jint originY, jint width, jint height, jlong windowLayerPtr) |
| { |
| __block AWTView *newView = nil; |
| |
| JNF_COCOA_ENTER(env); |
| |
| NSRect rect = NSMakeRect(originX, originY, width, height); |
| jobject cPlatformView = (*env)->NewWeakGlobalRef(env, obj); |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| |
| CALayer *windowLayer = jlong_to_ptr(windowLayerPtr); |
| newView = [[AWTView alloc] initWithRect:rect |
| platformView:cPlatformView |
| windowLayer:windowLayer]; |
| }]; |
| |
| JNF_COCOA_EXIT(env); |
| |
| return ptr_to_jlong(newView); |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CPlatformView |
| * Method: nativeSetAutoResizable |
| * Signature: (JZ)V; |
| */ |
| |
| JNIEXPORT void JNICALL |
| Java_sun_lwawt_macosx_CPlatformView_nativeSetAutoResizable |
| (JNIEnv *env, jclass cls, jlong viewPtr, jboolean toResize) |
| { |
| JNF_COCOA_ENTER(env); |
| |
| NSView *view = (NSView *)jlong_to_ptr(viewPtr); |
| |
| [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ |
| |
| if (toResize) { |
| [view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; |
| } else { |
| [view setAutoresizingMask: NSViewMinYMargin | NSViewMaxXMargin]; |
| } |
| |
| if ([view superview] != nil) { |
| [[view superview] setAutoresizesSubviews:(BOOL)toResize]; |
| } |
| |
| }]; |
| JNF_COCOA_EXIT(env); |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CPlatformView |
| * Method: nativeGetNSViewDisplayID |
| * Signature: (J)I; |
| */ |
| |
| JNIEXPORT jint JNICALL |
| Java_sun_lwawt_macosx_CPlatformView_nativeGetNSViewDisplayID |
| (JNIEnv *env, jclass cls, jlong viewPtr) |
| { |
| __block jint ret; //CGDirectDisplayID |
| |
| JNF_COCOA_ENTER(env); |
| |
| NSView *view = (NSView *)jlong_to_ptr(viewPtr); |
| NSWindow *window = [view window]; |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| |
| ret = (jint)[[AWTWindow getNSWindowDisplayID_AppKitThread: window] intValue]; |
| }]; |
| |
| JNF_COCOA_EXIT(env); |
| |
| return ret; |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CPlatformView |
| * Method: nativeGetLocationOnScreen |
| * Signature: (J)Ljava/awt/Rectangle; |
| */ |
| |
| JNIEXPORT jobject JNICALL |
| Java_sun_lwawt_macosx_CPlatformView_nativeGetLocationOnScreen |
| (JNIEnv *env, jclass cls, jlong viewPtr) |
| { |
| jobject jRect = NULL; |
| |
| JNF_COCOA_ENTER(env); |
| |
| __block NSRect rect = NSZeroRect; |
| |
| NSView *view = (NSView *)jlong_to_ptr(viewPtr); |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| |
| NSRect viewBounds = [view bounds]; |
| NSRect frameInWindow = [view convertRect:viewBounds toView:nil]; |
| rect = [[view window] convertRectToScreen:frameInWindow]; |
| NSRect screenRect = [[NSScreen mainScreen] frame]; |
| //Convert coordinates to top-left corner origin |
| rect.origin.y = screenRect.size.height - rect.origin.y - viewBounds.size.height; |
| }]; |
| jRect = NSToJavaRect(env, rect); |
| |
| JNF_COCOA_EXIT(env); |
| |
| return jRect; |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CPlatformView |
| * Method: nativeIsViewUnderMouse |
| * Signature: (J)Z; |
| */ |
| |
| JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPlatformView_nativeIsViewUnderMouse |
| (JNIEnv *env, jclass clazz, jlong viewPtr) |
| { |
| __block jboolean underMouse = JNI_FALSE; |
| |
| JNF_COCOA_ENTER(env); |
| |
| NSView *nsView = OBJC(viewPtr); |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| NSPoint ptWindowCoords = [[nsView window] mouseLocationOutsideOfEventStream]; |
| NSPoint ptViewCoords = [nsView convertPoint:ptWindowCoords fromView:nil]; |
| underMouse = [nsView hitTest:ptViewCoords] != nil; |
| }]; |
| |
| JNF_COCOA_EXIT(env); |
| |
| return underMouse; |
| } |