--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/macosx/native/sun/awt/AWTView.m Tue Mar 06 20:34:38 2012 +0000
@@ -0,0 +1,1206 @@
+/*
+ * Copyright (c) 2011, 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 "CGLGraphicsConfig.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
+
+#import "ThreadUtilities.h"
+#import "AWTView.h"
+#import "AWTEvent.h"
+#import "AWTWindow.h"
+#import "LWCToolkit.h"
+#import "JavaComponentAccessibility.h"
+#import "JavaTextAccessibility.h"
+#import "GeomUtilities.h"
+#import "OSVersion.h"
+#import "CGLLayer.h"
+
+@interface AWTView()
+@property (retain) CDropTarget *_dropTarget;
+@property (retain) CDragSource *_dragSource;
+@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;
+
+// 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;
+
+ if (windowLayer != nil) {
+ self.cglLayer = windowLayer;
+ [self setWantsLayer: YES];
+ [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];
+ CFRetain(remoteLayer); // REMIND
+ remoteLayer.frame = CGRectMake(0, 0, 720, 500); // REMIND
+ CFRetain(remoteLayer.jrsRemoteLayer); // 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 getJNIEnv];
+ (*env)->DeleteGlobalRef(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 resetTrackingRect];
+ }
+}
+
+- (BOOL) acceptsFirstMouse: (NSEvent *)event {
+ return YES;
+}
+
+- (BOOL) acceptsFirstResponder {
+ return YES;
+}
+
+- (BOOL) becomeFirstResponder {
+ return YES;
+}
+
+- (BOOL) preservesContentDuringLiveResize {
+ return YES;
+}
+
+/*
+ * Automatically triggered functions.
+ */
+
+/*
+ * 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 {
+ NSLog(@"-> IM does not want to handle event");
+ [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]) {
+ fProcessingKeystroke = NO;
+ if (!fInPressAndHold) {
+ fInPressAndHold = YES;
+ fPAHNeedsToSelect = YES;
+ }
+ return;
+ }
+
+ if (![self hasMarkedText] && fKeyEventsNeeded) {
+ [self deliverJavaKeyEventHelper: event];
+ }
+
+ fProcessingKeystroke = NO;
+}
+
+- (void) keyUp: (NSEvent *)event {
+ [self deliverJavaKeyEventHelper: event];
+}
+
+- (void) flagsChanged: (NSEvent *)event {
+ [self deliverJavaKeyEventHelper: event];
+}
+
+- (BOOL) performKeyEquivalent: (NSEvent *) event {
+ [self deliverJavaKeyEventHelper: event];
+ return NO;
+}
+
+/**
+ * Utility methods and accessors
+ */
+
+-(void) deliverJavaMouseEvent: (NSEvent *) event {
+ [AWTToolkit eventCountPlusPlus];
+
+ JNIEnv *env = [ThreadUtilities getJNIEnv];
+
+ NSPoint eventLocation = [event locationInWindow];
+ NSPoint localPoint = [self convertPoint: eventLocation fromView: nil];
+ NSPoint absP = [NSEvent mouseLocation];
+ NSEventType type = [event type];
+
+ // 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 mainScreen] 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];
+ }
+
+ static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/event/NSEvent");
+ static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)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,
+ [event deltaY],
+ [event deltaX]);
+ if (jEvent == nil) {
+ // Unable to create event by some reason.
+ return;
+ }
+
+ static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
+ static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/event/NSEvent;)V");
+ JNFCallVoidMethod(env, m_cPlatformView, jm_deliverMouseEvent, jEvent);
+}
+
+
+- (void) clearTrackingRect {
+ if (rolloverTrackingRectTag > 0) {
+ [self removeTrackingRect:rolloverTrackingRectTag];
+ rolloverTrackingRectTag = 0;
+ }
+}
+
+- (void) resetTrackingRect {
+ [self clearTrackingRect];
+ rolloverTrackingRectTag = [self addTrackingRect:[self visibleRect]
+ owner:self
+ userData:NULL
+ assumeInside:NO];
+}
+
+- (void)updateTrackingAreas {
+ [super updateTrackingAreas];
+ [self resetTrackingRect];
+}
+
+- (void) resetCursorRects {
+ [super resetCursorRects];
+ [self resetTrackingRect];
+}
+
+-(void) deliverJavaKeyEventHelper: (NSEvent *) event {
+ [AWTToolkit eventCountPlusPlus];
+ JNIEnv *env = [ThreadUtilities getJNIEnv];
+
+ jstring characters = NULL;
+ if ([event type] != NSFlagsChanged) {
+ characters = JNFNSToJavaString(env, [event characters]);
+ }
+
+ static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/event/NSEvent");
+ static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IISLjava/lang/String;)V");
+ jobject jevent = JNFNewObject(env, jctor_NSEvent,
+ [event type],
+ [event modifierFlags],
+ [event keyCode],
+ characters);
+
+ static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
+ static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_PlatformView,
+ "deliverKeyEvent", "(Lsun/lwawt/macosx/event/NSEvent;)V");
+ JNFCallVoidMethod(env, m_cPlatformView, jm_deliverKeyEvent, jevent);
+
+ if (characters != NULL) {
+ (*env)->DeleteLocalRef(env, characters);
+ }
+}
+
+- (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");
+ JNFCallVoidMethod(env, m_cPlatformView, jm_deliverWindowDidExposeEvent);
+/*
+ }
+*/
+ }
+}
+
+// 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 = JNFGetObjectField(env, m_cPlatformView, jf_Peer);
+ 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;
+ }
+ return JNFGetObjectField(env, peer, jf_Target);
+}
+
+- (id)getAxData:(JNIEnv*)env
+{
+ return [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:[self awtComponent:env] withIndex:-1 withView:self withJavaRole:nil] autorelease];
+}
+
+- (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 accessable element, and if it's 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:nil];
+ [styledText release];
+ return rtfdData;
+}
+
+// finds the focused accessable element, and if it's 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:nil];
+ 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) onObject:self._dropTarget withObject:nil waitUntilDone:YES awtMode: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];
+ else if ([super respondsToSelector:@selector(draggingSourceOperationMaskForLocal:)])
+ dragOp = [super 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];
+ else if ([super respondsToSelector:@selector(namesOfPromisedFilesDroppedAtDestination:)])
+ array = [super 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];
+ else if ([super respondsToSelector:@selector(draggedImage::)])
+ [super 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];
+ else if ([super respondsToSelector:@selector(draggedImage:::)])
+ [super 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];
+ else if ([super respondsToSelector:@selector(draggedImage::)])
+ [super 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];
+ else if ([super respondsToSelector:@selector(ignoreModifierKeysWhileDragging)])
+ result = [super 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];
+ else if ([super respondsToSelector:@selector(draggingEntered:)])
+ dragOp = [super 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];
+ else if ([super respondsToSelector:@selector(draggingUpdated:)])
+ dragOp = [super 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];
+ else if ([super respondsToSelector:@selector(draggingExited:)])
+ [super 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];
+ else if ([super respondsToSelector:@selector(prepareForDragOperation:)])
+ result = [super 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];
+ else if ([super respondsToSelector:@selector(performDragOperation:)])
+ result = [super 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];
+ else if ([super respondsToSelector:@selector(concludeDragOperation:)])
+ [super 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];
+ else if ([super respondsToSelector:@selector(draggingEnded:)])
+ [super 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.
+ NSUInteger utf8Length = [aString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ if ([self hasMarkedText] || !fProcessingKeystroke || (utf8Length > 2)) {
+ 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, aString);
+ 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;
+ }
+
+ 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;
+
+ array = JNFCallObjectMethod(env, fInputMethodLOCKABLE, jm_markedRange); // AWT_THREADING Safe (AWTRunLoopMode)
+
+ if (array) {
+ _array = (*env)->GetIntArrayElements(env, array, &isCopy);
+ range = NSMakeRange(_array[0], _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);
+ } else {
+ range = NSMakeRange(NSNotFound, 0);
+ }
+
+ 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;
+
+#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);
+ range = NSMakeRange(_array[0], _array[1]);
+ (*env)->ReleaseIntArrayElements(env, array, _array, 0);
+ (*env)->DeleteLocalRef(env, array);
+ } else {
+ range = NSMakeRange(NSNotFound, 0);
+ }
+
+ 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 NSMakeRect(0, 0, 0, 0);
+ }
+
+ 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);
+ rect = ConvertNSScreenRect(env, NSMakeRect(_array[0], _array[1], _array[2], _array[3]));
+ (*env)->ReleaseIntArrayElements(env, array, _array, 0);
+ (*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:) onObject:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES awtMode: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);
+AWT_ASSERT_NOT_APPKIT_THREAD;
+
+ NSRect rect = NSMakeRect(originX, originY, width, height);
+ jobject cPlatformView = (*env)->NewGlobalRef(env, obj);
+
+ [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
+ AWT_ASSERT_APPKIT_THREAD;
+
+ CALayer *windowLayer = jlong_to_ptr(windowLayerPtr);
+ AWTView *view = [[AWTView alloc] initWithRect:rect
+ platformView:cPlatformView
+ windowLayer:windowLayer];
+ CFRetain(view);
+ [view release]; // GC
+
+ newView = view;
+ }];
+
+JNF_COCOA_EXIT(env);
+
+ return ptr_to_jlong(newView);
+}