aboutsummaryrefslogtreecommitdiffstats
path: root/src/newt/native/NewtMacWindow.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/newt/native/NewtMacWindow.m')
-rw-r--r--src/newt/native/NewtMacWindow.m1210
1 files changed, 706 insertions, 504 deletions
diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m
index f914467af..b4133ac7e 100644
--- a/src/newt/native/NewtMacWindow.m
+++ b/src/newt/native/NewtMacWindow.m
@@ -36,42 +36,140 @@
#import "KeyEvent.h"
#import "MouseEvent.h"
-jint GetDeltaY(NSEvent *event, jint javaMods) {
- CGFloat deltaY = 0.0;
+#include <CoreFoundation/CoreFoundation.h>
+#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
+
+#include <math.h>
+
+#define PRINTF(...) NSLog(@ __VA_ARGS__)
+
+static jfloat GetDelta(NSEvent *event, jint javaMods[]) {
CGEventRef cgEvent = [event CGEvent];
+ CGFloat deltaY = 0.0;
+ CGFloat deltaX = 0.0;
+ CGFloat delta = 0.0;
if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) {
// mouse pad case
- deltaY =
- CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
- // fprintf(stderr, "WHEEL/PAD: %lf\n", (double)deltaY);
+ deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2);
+ deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
+ // fprintf(stderr, "WHEEL/PAD: %lf/%lf - 0x%X\n", (double)deltaX, (double)deltaY, javaMods[0]);
+ if( fabsf(deltaX) > fabsf(deltaY) ) {
+ javaMods[0] |= EVENT_SHIFT_MASK;
+ delta = deltaX;
+ } else {
+ delta = deltaY;
+ }
} else {
// traditional mouse wheel case
+ deltaX = [event deltaX];
deltaY = [event deltaY];
- // fprintf(stderr, "WHEEL/TRAD: %lf\n", (double)deltaY);
- if (deltaY == 0.0 && (javaMods & EVENT_SHIFT_MASK) != 0) {
+ // fprintf(stderr, "WHEEL/TRACK: %lf/%lf - 0x%X\n", (double)deltaX, (double)deltaY, javaMods[0]);
+ if (deltaY == 0.0 && (javaMods[0] & EVENT_SHIFT_MASK) != 0) {
// shift+vertical wheel scroll produces horizontal scroll
// we convert it to vertical
- deltaY = [event deltaX];
+ delta = deltaX;
+ } else {
+ delta = deltaY;
}
- if (-1.0 < deltaY && deltaY < 1.0) {
- deltaY *= 10.0;
+ if (-1.0 < delta && delta < 1.0) {
+ delta *= 10.0;
} else {
- if (deltaY < 0.0) {
- deltaY = deltaY - 0.5f;
+ if (delta < 0.0) {
+ delta = delta - 0.5f;
} else {
- deltaY = deltaY + 0.5f;
+ delta = delta + 0.5f;
+ }
+ }
+ }
+ // fprintf(stderr, "WHEEL/RES: %lf - 0x%X\n", (double)delta, javaMods[0]);
+ return (jfloat) delta;
+}
+
+#define kVK_Shift 0x38
+#define kVK_Option 0x3A
+#define kVK_Control 0x3B
+#define kVK_Command 0x37
+
+static jint mods2JavaMods(NSUInteger mods)
+{
+ int javaMods = 0;
+ if (mods & NSShiftKeyMask) {
+ javaMods |= EVENT_SHIFT_MASK;
+ }
+ if (mods & NSControlKeyMask) {
+ javaMods |= EVENT_CTRL_MASK;
+ }
+ if (mods & NSCommandKeyMask) {
+ javaMods |= EVENT_META_MASK;
+ }
+ if (mods & NSAlternateKeyMask) {
+ javaMods |= EVENT_ALT_MASK;
+ }
+ return javaMods;
+}
+
+static CFStringRef CKCH_CreateStringForKey(CGKeyCode keyCode, const UCKeyboardLayout *keyboardLayout) {
+ UInt32 keysDown = 0;
+ UniChar chars[4];
+ UniCharCount realLength;
+
+ UCKeyTranslate(keyboardLayout, keyCode,
+ kUCKeyActionDisplay, 0,
+ LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
+ &keysDown, sizeof(chars) / sizeof(chars[0]), &realLength, chars);
+
+ return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
+}
+
+static CFMutableDictionaryRef CKCH_CreateCodeToCharDict(TISInputSourceRef keyboard) {
+ CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+
+ CFMutableDictionaryRef codeToCharDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128, NULL, NULL);
+ if ( NULL != codeToCharDict ) {
+ intptr_t i;
+ for (i = 0; i < 128; ++i) {
+ CFStringRef string = CKCH_CreateStringForKey((CGKeyCode)i, keyboardLayout);
+ if( NULL != string ) {
+ CFIndex stringLen = CFStringGetLength (string);
+ if ( 0 < stringLen ) {
+ UniChar character = CFStringGetCharacterAtIndex(string, 0);
+ DBG_PRINT("CKCH: MAP 0x%X -> %c\n", (int)i, character);
+ CFDictionaryAddValue(codeToCharDict, (const void *)i, (const void *)(intptr_t)character);
+ }
+ CFRelease(string);
}
}
}
- // fprintf(stderr, "WHEEL/res: %d\n", (int)deltaY);
- return (jint) deltaY;
+ return codeToCharDict;
+}
+
+static CFMutableDictionaryRef CKCH_USCodeToNNChar = NULL;
+
+static void CKCH_CreateDictionaries() {
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+ CKCH_USCodeToNNChar = CKCH_CreateCodeToCharDict(currentKeyboard);
+ CFRelease(currentKeyboard);
+}
+
+static UniChar CKCH_CharForKeyCode(jshort keyCode) {
+ UniChar rChar = 0;
+
+ if ( NULL != CKCH_USCodeToNNChar ) {
+ intptr_t code = (intptr_t) keyCode;
+ intptr_t character = 0;
+
+ if ( CFDictionaryGetValueIfPresent(CKCH_USCodeToNNChar, (void *)code, (const void **)&character) ) {
+ rChar = (UniChar) character;
+ DBG_PRINT("CKCH: OK 0x%X -> 0x%X\n", (int)keyCode, (int)rChar);
+ }
+ }
+ return rChar;
}
static jmethodID enqueueMouseEventID = NULL;
-static jmethodID sendMouseEventID = NULL;
static jmethodID enqueueKeyEventID = NULL;
-static jmethodID sendKeyEventID = NULL;
static jmethodID requestFocusID = NULL;
static jmethodID insetsChangedID = NULL;
@@ -82,24 +180,21 @@ static jmethodID focusChangedID = NULL;
static jmethodID windowDestroyNotifyID = NULL;
static jmethodID windowRepaintID = NULL;
-// Can't use USE_SENDIO_DIRECT, ie w/o enqueueing to EDT,
+// Need to enqueue all events to EDT,
// since we may operate on AWT-AppKit (Main Thread)
// and direct issuing 'requestFocus()' would deadlock:
// AWT-AppKit
// AWT-EventQueue-0
-//
-// #define USE_SENDIO_DIRECT 1
@implementation NewtView
- (id)initWithFrame:(NSRect)frameRect
{
+ id res = [super initWithFrame:frameRect];
javaWindowObject = NULL;
- jvmHandle = NULL;
- jvmVersion = 0;
destroyNotifySent = NO;
- softLocked = NO;
+ softLockCount = 0;
pthread_mutexattr_t softLockSyncAttr;
pthread_mutexattr_init(&softLockSyncAttr);
@@ -107,59 +202,46 @@ static jmethodID windowRepaintID = NULL;
pthread_mutex_init(&softLockSync, &softLockSyncAttr); // recursive
ptrTrackingTag = 0;
-
- /**
- NSCursor crs = [NSCursor arrowCursor];
- NSImage crsImg = [crs image];
- NSPoint crsHot = [crs hotSpot];
- myCursor = [[NSCursor alloc] initWithImage: crsImg hotSpot:crsHot];
- */
myCursor = NULL;
- return [super initWithFrame:frameRect];
+ modsDown[0] = NO; // shift
+ modsDown[1] = NO; // ctrl
+ modsDown[2] = NO; // alt
+ modsDown[3] = NO; // win
+ mouseConfined = NO;
+ mouseVisible = YES;
+ mouseInside = NO;
+ cursorIsHidden = NO;
+
+ DBG_PRINT("NewtView::create: %p (refcnt %d)\n", res, (int)[res retainCount]);
+ return res;
}
+#ifdef DBG_LIFECYCLE
- (void) release
{
-#ifdef VERBOSE_ON
- NSLog(@"NewtView::release\n");
- NSLog(@"%@",[NSThread callStackSymbols]);
-#endif
+ DBG_PRINT("NewtView::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
[super release];
}
+#endif
- (void) dealloc
{
- if(softLocked) {
+ DBG_PRINT("NewtView::dealloc.0: %p (refcnt %d), ptrTrackingTag %d\n", self, (int)[self retainCount], (int)ptrTrackingTag);
+#ifdef DBG_LIFECYCLE
+ NSLog(@"%@",[NSThread callStackSymbols]);
+#endif
+ if( 0 < softLockCount ) {
NSLog(@"NewtView::dealloc: softLock still hold @ dealloc!\n");
}
+ [self removeCursorRects];
+ [self removeMyCursor];
+
pthread_mutex_destroy(&softLockSync);
-#ifdef VERBOSE_ON
- NSLog(@"NewtView::dealloc\n");
- NSLog(@"%@",[NSThread callStackSymbols]);
-#endif
+ DBG_PRINT("NewtView::dealloc.X: %p\n", self);
[super dealloc];
}
-- (void) setJVMHandle: (JavaVM*) vm
-{
- jvmHandle = vm;
-}
-- (JavaVM*) getJVMHandle
-{
- return jvmHandle;
-}
-
-- (void) setJVMVersion: (int) ver
-{
- jvmVersion = ver;
-}
-
-- (int) getJVMVersion
-{
- return jvmVersion;
-}
-
- (void) setJavaWindowObject: (jobject) javaWindowObj
{
javaWindowObject = javaWindowObj;
@@ -170,32 +252,6 @@ static jmethodID windowRepaintID = NULL;
return javaWindowObject;
}
-- (void) rightMouseDown: (NSEvent*) theEvent
-{
- NSResponder* next = [self nextResponder];
- if (next != nil) {
- [next rightMouseDown: theEvent];
- }
-}
-
-- (void) resetCursorRects
-{
- [super resetCursorRects];
-
- if(0 != ptrTrackingTag) {
- // [self removeCursorRect: ptrRect cursor: myCursor];
- [self removeTrackingRect: ptrTrackingTag];
- }
- ptrRect = [self bounds];
- // [self addCursorRect: ptrRect cursor: myCursor];
- ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO];
-}
-
-- (NSCursor *) cursor
-{
- return myCursor;
-}
-
- (void) setDestroyNotifySent: (BOOL) v
{
destroyNotifySent = v;
@@ -209,18 +265,27 @@ static jmethodID windowRepaintID = NULL;
- (BOOL) softLock
{
// DBG_PRINT("*************** softLock.0: %p\n", (void*)pthread_self());
- // NSLog(@"NewtView::softLock: %@",[NSThread callStackSymbols]);
- pthread_mutex_lock(&softLockSync);
- softLocked = YES;
+ int err;
+ if( 0 != ( err = pthread_mutex_lock(&softLockSync) ) ) {
+ NSLog(@"NewtView::softLock failed: errCode %d - %@", err, [NSThread callStackSymbols]);
+ return NO;
+ }
+ softLockCount++;
// DBG_PRINT("*************** softLock.X: %p\n", (void*)pthread_self());
- return softLocked;
+ return 0 < softLockCount;
}
-- (void) softUnlock
+- (BOOL) softUnlock
{
// DBG_PRINT("*************** softUnlock: %p\n", (void*)pthread_self());
- softLocked = NO;
- pthread_mutex_unlock(&softLockSync);
+ softLockCount--;
+ int err;
+ if( 0 != ( err = pthread_mutex_unlock(&softLockSync) ) ) {
+ softLockCount++;
+ NSLog(@"NewtView::softUnlock failed: Not locked by current thread - errCode %d - %@", err, [NSThread callStackSymbols]);
+ return NO;
+ }
+ return YES;
}
- (BOOL) needsDisplay
@@ -256,7 +321,7 @@ static jmethodID windowRepaintID = NULL;
return;
}
int shallBeDetached = 0;
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("drawRect: null JNIEnv\n");
return;
@@ -268,9 +333,8 @@ static jmethodID windowRepaintID = NULL;
dirtyRect.origin.x, viewFrame.size.height - dirtyRect.origin.y,
dirtyRect.size.width, dirtyRect.size.height);
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
- (void) viewDidHide
@@ -280,7 +344,7 @@ static jmethodID windowRepaintID = NULL;
return;
}
int shallBeDetached = 0;
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("viewDidHide: null JNIEnv\n");
return;
@@ -288,9 +352,8 @@ static jmethodID windowRepaintID = NULL;
(*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_FALSE);
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
[super viewDidHide];
}
@@ -302,7 +365,7 @@ static jmethodID windowRepaintID = NULL;
return;
}
int shallBeDetached = 0;
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("viewDidUnhide: null JNIEnv\n");
return;
@@ -310,9 +373,8 @@ static jmethodID windowRepaintID = NULL;
(*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_TRUE);
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
[super viewDidUnhide];
}
@@ -322,232 +384,140 @@ static jmethodID windowRepaintID = NULL;
return YES;
}
-@end
-
-@implementation NewtMacWindow
-
-+ (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz
+- (BOOL) becomeFirstResponder
{
- enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZIIIIII)V");
- sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V");
- enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V");
- sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V");
- sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V");
- visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V");
- insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V");
- positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V");
- focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V");
- windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z");
- windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V");
- requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V");
- if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID &&
- positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID)
- {
- return YES;
- }
- return NO;
+ DBG_PRINT( "*************** View.becomeFirstResponder\n");
+ return [super becomeFirstResponder];
}
-- (id) initWithContentRect: (NSRect) contentRect
- styleMask: (NSUInteger) windowStyle
- backing: (NSBackingStoreType) bufferingType
- defer: (BOOL) deferCreation
- screen:(NSScreen *)screen
- isFullscreenWindow:(BOOL)isfs
+- (BOOL) resignFirstResponder
{
- id res = [super initWithContentRect: contentRect
- styleMask: windowStyle
- backing: bufferingType
- defer: deferCreation
- screen: screen];
- isFullscreenWindow = isfs;
- // Why is this necessary? Without it we don't get any of the
- // delegate methods like resizing and window movement.
- [self setDelegate: self];
- cachedInsets[0] = 0; // l
- cachedInsets[1] = 0; // r
- cachedInsets[2] = 0; // t
- cachedInsets[3] = 0; // b
- mouseConfined = NO;
- mouseVisible = YES;
- mouseInside = NO;
- cursorIsHidden = NO;
- realized = YES;
- return res;
+ DBG_PRINT( "*************** View.resignFirstResponder\n");
+ return [super resignFirstResponder];
}
-- (void) release
+- (void) removeCursorRects
{
-#ifdef VERBOSE_ON
- NSLog(@"NewtWindow::release\n");
- NSLog(@"%@",[NSThread callStackSymbols]);
-#endif
- [super release];
+ if(0 != ptrTrackingTag) {
+ if(NULL != myCursor) {
+ [self removeCursorRect: ptrRect cursor: myCursor];
+ }
+ [self removeTrackingRect: ptrTrackingTag];
+ ptrTrackingTag = 0;
+ }
}
-- (void) dealloc
+- (void) addCursorRects
{
-#ifdef VERBOSE_ON
- NSLog(@"NewtWindow::dealloc\n");
- NSLog(@"%@",[NSThread callStackSymbols]);
-#endif
- [super dealloc];
+ ptrRect = [self bounds];
+ if(NULL != myCursor) {
+ [self addCursorRect: ptrRect cursor: myCursor];
+ }
+ ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO];
}
-- (void) setUnrealized
+- (void) removeMyCursor
{
- realized = NO;
+ if(NULL != myCursor) {
+ [myCursor release];
+ myCursor = NULL;
+ }
}
-- (BOOL) isRealized
+- (void) resetCursorRects
{
- return realized;
+ [super resetCursorRects];
+
+ [self removeCursorRects];
+ [self addCursorRects];
}
-- (void) updateInsets: (JNIEnv*) env
+- (void) setPointerIcon: (NSCursor*)c
{
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
+ DBG_PRINT( "setPointerIcon: %p -> %p, top %p, mouseInside %d\n", myCursor, c, [NSCursor currentCursor], (int)mouseInside);
+ if( c != myCursor ) {
+ [self removeCursorRects];
+ [self removeMyCursor];
+ myCursor = c;
+ if( NULL != myCursor ) {
+ [myCursor retain];
+ }
}
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
- if (env==NULL || javaWindowObject == NULL) {
- return;
+ NSWindow* nsWin = [self window];
+ if( NULL != nsWin ) {
+ [nsWin invalidateCursorRectsForView: self];
}
-
- NSRect frameRect = [self frame];
- NSRect contentRect = [self contentRectForFrameRect: frameRect];
-
- // note: this is a simplistic implementation which doesn't take
- // into account DPI and scaling factor
- CGFloat l = contentRect.origin.x - frameRect.origin.x;
- cachedInsets[0] = (int)l; // l
- cachedInsets[1] = (int)(frameRect.size.width - (contentRect.size.width + l)); // r
- cachedInsets[2] = (jint)(frameRect.size.height - contentRect.size.height); // t
- cachedInsets[3] = (jint)(contentRect.origin.y - frameRect.origin.y); // b
-
- DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]);
-
- (*env)->CallVoidMethod(env, javaWindowObject, insetsChangedID, JNI_FALSE, cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]);
}
-- (void) attachToParent: (NSWindow*) parent
-{
- DBG_PRINT( "attachToParent.1\n");
- [parent addChildWindow: self ordered: NSWindowAbove];
- DBG_PRINT( "attachToParent.2\n");
- [self setParentWindow: parent];
- DBG_PRINT( "attachToParent.X\n");
-}
-
-- (void) detachFromParent: (NSWindow*) parent
+- (void) mouseEntered: (NSEvent*) theEvent
{
- DBG_PRINT( "detachFromParent.1\n");
- [self setParentWindow: nil];
- if(NULL != parent) {
- DBG_PRINT( "detachFromParent.2\n");
- [parent removeChildWindow: self];
+ DBG_PRINT( "mouseEntered: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]);
+ mouseInside = YES;
+ [self cursorHide: !mouseVisible enter: 1];
+ if(NO == mouseConfined) {
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED];
+ }
+ NSWindow* nsWin = [self window];
+ if( NULL != nsWin ) {
+ [nsWin makeFirstResponder: self];
}
- DBG_PRINT( "detachFromParent.X\n");
-}
-
-/**
- * p abs screen position w/ top-left origin
- * returns: abs screen position w/ bottom-left origin
- */
-- (NSPoint) newtScreenWinPos2OSXScreenPos: (NSPoint) p
-{
- NSView* mView = [self contentView];
- NSRect mViewFrame = [mView frame];
- int totalHeight = mViewFrame.size.height + cachedInsets[2] + cachedInsets[3]; // height + insets[top+bottom]
-
- NSScreen* screen = [self screen];
- NSRect screenFrame = [screen frame];
-
- return NSMakePoint(screenFrame.origin.x + p.x + cachedInsets[0],
- screenFrame.origin.y + screenFrame.size.height - p.y - totalHeight);
-}
-
-/**
- * p rel client window position w/ top-left origin
- * returns: abs screen position w/ bottom-left origin
- */
-- (NSPoint) newtClientWinPos2OSXScreenPos: (NSPoint) p
-{
- NSRect winFrame = [self frame];
-
- NSView* mView = [self contentView];
- NSRect mViewFrame = [mView frame];
-
- return NSMakePoint(winFrame.origin.x + p.x,
- winFrame.origin.y + ( mViewFrame.size.height - p.y ) ); // y-flip in view
}
-/**
- * y-flips input / output
- * p rel client window position w/ top-left origin
- * returns: location in 0/0 top-left space.
- */
-- (NSPoint) getLocationOnScreen: (NSPoint) p
+- (void) mouseExited: (NSEvent*) theEvent
{
- NSScreen* screen = [self screen];
- NSRect screenRect = [screen frame];
-
- NSView* view = [self contentView];
- NSRect viewFrame = [view frame];
-
- NSRect r;
- r.origin.x = p.x;
- r.origin.y = viewFrame.size.height - p.y; // y-flip
- r.size.width = 0;
- r.size.height = 0;
- // NSRect rS = [win convertRectToScreen: r]; // 10.7
- NSPoint oS = [self convertBaseToScreen: r.origin];
- oS.y = screenRect.origin.y + screenRect.size.height - oS.y;
- return oS;
+ DBG_PRINT( "mouseExited: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]);
+ if(NO == mouseConfined) {
+ mouseInside = NO;
+ [self cursorHide: NO enter: -1];
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED];
+ [self resignFirstResponder];
+ } else {
+ [self setMousePosition: lastInsideMousePosition];
+ }
}
-- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p
+- (void) setMousePosition:(NSPoint)p
{
- NSView* view = [self contentView];
- NSRect viewFrame = [view frame];
+ NSWindow* nsWin = [self window];
+ if( NULL != nsWin ) {
+ NSScreen* screen = [nsWin screen];
+ NSRect screenRect = [screen frame];
- NSRect r;
- r.origin.x = p.x;
- r.origin.y = p.y;
- r.size.width = 0;
- r.size.height = 0;
- // NSRect rS = [win convertRectFromScreen: r]; // 10.7
- NSPoint oS = [self convertScreenToBase: r.origin];
- oS.y = viewFrame.size.height - oS.y; // y-flip
- return oS;
+ CGPoint pt = { p.x, screenRect.size.height - p.y }; // y-flip (CG is top-left origin)
+ CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft);
+ CGEventPost (kCGHIDEventTap, ev);
+ }
}
-- (BOOL) isMouseInside
+- (BOOL) updateMouseInside
{
- NSView* view = [self contentView];
- NSRect viewFrame = [view frame];
+ NSRect viewFrame = [self frame];
NSPoint l1 = [NSEvent mouseLocation];
NSPoint l0 = [self screenPos2NewtClientWinPos: l1];
- return viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) &&
- viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ;
+ mouseInside = viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) &&
+ viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ;
+ return mouseInside;
}
- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus
{
mouseVisible = v;
- mouseInside = [self isMouseInside];
+ [self updateMouseInside];
DBG_PRINT( "setMouseVisible: confined %d, visible %d (current: %d), mouseInside %d, hasFocus %d\n",
mouseConfined, mouseVisible, !cursorIsHidden, mouseInside, focus);
if(YES == focus && YES == mouseInside) {
- [self cursorHide: !mouseVisible];
+ [self cursorHide: !mouseVisible enter: 0];
}
}
+- (BOOL) isMouseVisible
+{
+ return mouseVisible;
+}
-- (void) cursorHide:(BOOL)v
+- (void) cursorHide:(BOOL)v enter:(int)enterState
{
- DBG_PRINT( "cursorHide: %d -> %d\n", cursorIsHidden, v);
+ DBG_PRINT( "cursorHide: %d -> %d, enter %d; PointerIcon: %p, top %p\n",
+ cursorIsHidden, v, enterState, myCursor, [NSCursor currentCursor]);
if(v) {
if(!cursorIsHidden) {
[NSCursor hide];
@@ -567,108 +537,105 @@ static jmethodID windowRepaintID = NULL;
DBG_PRINT( "setMouseConfined: confined %d, visible %d\n", mouseConfined, mouseVisible);
}
-- (void) setMousePosition:(NSPoint)p
+- (void) mouseMoved: (NSEvent*) theEvent
{
- NSScreen* screen = [self screen];
- NSRect screenRect = [screen frame];
+ if( mouseInside ) {
+ NSCursor * currentCursor = [NSCursor currentCursor];
+ BOOL setCursor = NULL != myCursor && NO == cursorIsHidden && currentCursor != myCursor;
+ DBG_PRINT( "mouseMoved.set: %d; mouseInside %d, CursorHidden %d, PointerIcon: %p, top %p\n",
+ setCursor, mouseInside, cursorIsHidden, myCursor, currentCursor);
+ if( setCursor ) {
+ // FIXME: Workaround missing NSCursor update for 'fast moving' pointer
+ [myCursor set];
+ }
+ lastInsideMousePosition = [NSEvent mouseLocation];
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+ }
+}
- CGPoint pt = { p.x, screenRect.size.height - p.y }; // y-flip (CG is top-left origin)
- CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft);
- CGEventPost (kCGHIDEventTap, ev);
+- (void) scrollWheel: (NSEvent*) theEvent
+{
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED];
}
-static jint mods2JavaMods(NSUInteger mods)
+- (void) mouseDown: (NSEvent*) theEvent
{
- int javaMods = 0;
- if (mods & NSShiftKeyMask) {
- javaMods |= EVENT_SHIFT_MASK;
- }
- if (mods & NSControlKeyMask) {
- javaMods |= EVENT_CTRL_MASK;
- }
- if (mods & NSCommandKeyMask) {
- javaMods |= EVENT_META_MASK;
- }
- if (mods & NSAlternateKeyMask) {
- javaMods |= EVENT_ALT_MASK;
- }
- return javaMods;
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
}
-- (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType
+- (void) mouseDragged: (NSEvent*) theEvent
{
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
- }
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
- if (javaWindowObject == NULL) {
- DBG_PRINT("sendKeyEvent: null javaWindowObject\n");
- return;
- }
- int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
- if(NULL==env) {
- DBG_PRINT("sendKeyEvent: null JNIEnv\n");
- return;
+ lastInsideMousePosition = [NSEvent mouseLocation];
+ // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+}
+
+- (void) mouseUp: (NSEvent*) theEvent
+{
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
+}
+
+- (void) rightMouseDown: (NSEvent*) theEvent
+{
+ NSResponder* next = [self nextResponder];
+ if (next != nil) {
+ [next rightMouseDown: theEvent];
}
+ // FIXME: ^^ OR [super rightMouseDown: theEvent] ?
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
+}
- int i;
- jint keyCode = (jint) [event keyCode];
- NSString* chars = [event charactersIgnoringModifiers];
- int len = [chars length];
- jint javaMods = mods2JavaMods([event modifierFlags]);
+- (void) rightMouseDragged: (NSEvent*) theEvent
+{
+ lastInsideMousePosition = [NSEvent mouseLocation];
+ // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+}
- for (i = 0; i < len; i++) {
- // Note: the key code in the NSEvent does not map to anything we can use
- jchar keyChar = (jchar) [chars characterAtIndex: i];
+- (void) rightMouseUp: (NSEvent*) theEvent
+{
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
+}
- DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode);
+- (void) otherMouseDown: (NSEvent*) theEvent
+{
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
+}
- #ifdef USE_SENDIO_DIRECT
- (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID,
- evType, javaMods, keyCode, keyChar);
- #else
- (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE,
- evType, javaMods, keyCode, keyChar);
- #endif
- }
+- (void) otherMouseDragged: (NSEvent*) theEvent
+{
+ lastInsideMousePosition = [NSEvent mouseLocation];
+ // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+}
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+- (void) otherMouseUp: (NSEvent*) theEvent
+{
+ [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
}
-- (void) sendMouseEvent: (NSEvent*) event eventType: (jint) evType
+- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType
{
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
- }
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
if (javaWindowObject == NULL) {
DBG_PRINT("sendMouseEvent: null javaWindowObject\n");
return;
}
int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("sendMouseEvent: null JNIEnv\n");
return;
}
- jint javaMods = mods2JavaMods([event modifierFlags]);
+ jint javaMods[] = { 0 } ;
+ javaMods[0] = mods2JavaMods([event modifierFlags]);
// convert to 1-based button number (or use zero if no button is involved)
// TODO: detect mouse button when mouse wheel scrolled
- jint javaButtonNum = 0;
- jint scrollDeltaY = 0;
+ jshort javaButtonNum = 0;
+ jfloat scrollDeltaY = 0.0f;
switch ([event type]) {
case NSScrollWheel: {
- scrollDeltaY = GetDeltaY(event, javaMods);
+ scrollDeltaY = GetDelta(event, javaMods);
javaButtonNum = 1;
break;
}
@@ -699,246 +666,484 @@ static jint mods2JavaMods(NSUInteger mods)
NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]];
- #ifdef USE_SENDIO_DIRECT
- (*env)->CallVoidMethod(env, javaWindowObject, sendMouseEventID,
- evType, javaMods,
- (jint) location.x, (jint) location.y,
- javaButtonNum, scrollDeltaY);
- #else
(*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, JNI_FALSE,
- evType, javaMods,
+ evType, javaMods[0],
(jint) location.x, (jint) location.y,
javaButtonNum, scrollDeltaY);
- #endif
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
-- (void) focusChanged: (BOOL) gained
+- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p
{
- DBG_PRINT( "focusChanged: gained %d\n", gained);
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
+ NSRect viewFrame = [self frame];
+
+ NSRect r;
+ r.origin.x = p.x;
+ r.origin.y = p.y;
+ r.size.width = 0;
+ r.size.height = 0;
+ // NSRect rS = [[self window] convertRectFromScreen: r]; // 10.7
+ NSPoint oS = [[self window] convertScreenToBase: r.origin];
+ oS.y = viewFrame.size.height - oS.y; // y-flip
+ return oS;
+}
+
+- (void) handleFlagsChanged:(NSUInteger) mods
+{
+ [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods];
+ [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods];
+ [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods];
+ [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods];
+}
+
+- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods
+{
+ if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) ) {
+ modsDown[keyIdx] = YES;
+ [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_PRESSED];
+ } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) ) {
+ modsDown[keyIdx] = NO;
+ [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_RELEASED];
}
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
+}
+
+- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType
+{
+ jshort keyCode = (jshort) [event keyCode];
+ NSString* chars = [event charactersIgnoringModifiers];
+ NSUInteger mods = [event modifierFlags];
+ [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType];
+}
+
+- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType
+{
if (javaWindowObject == NULL) {
- DBG_PRINT("focusChanged: null javaWindowObject\n");
+ DBG_PRINT("sendKeyEvent: null javaWindowObject\n");
return;
}
int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
- DBG_PRINT("focusChanged: null JNIEnv\n");
+ DBG_PRINT("sendKeyEvent: null JNIEnv\n");
return;
}
- (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE);
+ int i;
+ int len = NULL != chars ? [chars length] : 0;
+ jint javaMods = mods2JavaMods(mods);
+
+ if(len > 0) {
+ // printable chars
+ for (i = 0; i < len; i++) {
+ // Note: the key code in the NSEvent does not map to anything we can use
+ UniChar keyChar = (UniChar) [chars characterAtIndex: i];
+ UniChar keySymChar = CKCH_CharForKeyCode(keyCode);
+
+ DBG_PRINT("sendKeyEvent: %d/%d code 0x%X, char 0x%X, mods 0x%X/0x%X -> keySymChar 0x%X\n", i, len, (int)keyCode, (int)keyChar,
+ (int)mods, (int)javaMods, (int)keySymChar);
+
+ (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE,
+ evType, javaMods, keyCode, (jchar)keyChar, (jchar)keySymChar);
+ }
+ } else {
+ // non-printable chars
+ jchar keyChar = (jchar) 0;
+
+ DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode);
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
+ (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE,
+ evType, javaMods, keyCode, keyChar, keyChar);
}
+
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
-- (BOOL) becomeFirstResponder
+@end
+
+@implementation NewtMacWindow
+
++ (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz
{
- DBG_PRINT( "*************** becomeFirstResponder\n");
- return [super becomeFirstResponder];
+ enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZSIIISF)V");
+ enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZSISCC)V");
+ sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V");
+ visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V");
+ insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V");
+ positionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V");
+ focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V");
+ windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z");
+ windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V");
+ requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V");
+ if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID &&
+ positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID)
+ {
+ CKCH_CreateDictionaries();
+ return YES;
+ }
+ return NO;
}
-- (BOOL) resignFirstResponder
+- (id) initWithContentRect: (NSRect) contentRect
+ styleMask: (NSUInteger) windowStyle
+ backing: (NSBackingStoreType) bufferingType
+ defer: (BOOL) deferCreation
+ isFullscreenWindow:(BOOL)isfs
{
- DBG_PRINT( "*************** resignFirstResponder\n");
- return [super resignFirstResponder];
+ id res = [super initWithContentRect: contentRect
+ styleMask: windowStyle
+ backing: bufferingType
+ defer: deferCreation];
+ // OSX 10.6
+ if ( [NSApp respondsToSelector:@selector(currentSystemPresentationOptions)] &&
+ [NSApp respondsToSelector:@selector(setPresentationOptions:)] ) {
+ hasPresentationSwitch = YES;
+ defaultPresentationOptions = [NSApp currentSystemPresentationOptions];
+ fullscreenPresentationOptions =
+ // NSApplicationPresentationDefault|
+ // NSApplicationPresentationAutoHideDock|
+ NSApplicationPresentationHideDock|
+ // NSApplicationPresentationAutoHideMenuBar|
+ NSApplicationPresentationHideMenuBar|
+ NSApplicationPresentationDisableAppleMenu|
+ // NSApplicationPresentationDisableProcessSwitching|
+ // NSApplicationPresentationDisableSessionTermination|
+ NSApplicationPresentationDisableHideApplication|
+ // NSApplicationPresentationDisableMenuBarTransparency|
+ // NSApplicationPresentationFullScreen| // OSX 10.7
+ 0 ;
+ } else {
+ hasPresentationSwitch = NO;
+ defaultPresentationOptions = 0;
+ fullscreenPresentationOptions = 0;
+ }
+
+ isFullscreenWindow = isfs;
+ // Why is this necessary? Without it we don't get any of the
+ // delegate methods like resizing and window movement.
+ [self setDelegate: self];
+ cachedInsets[0] = 0; // l
+ cachedInsets[1] = 0; // r
+ cachedInsets[2] = 0; // t
+ cachedInsets[3] = 0; // b
+ realized = YES;
+ DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n",
+ res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]);
+ return res;
}
-- (BOOL) canBecomeKeyWindow
+#ifdef DBG_LIFECYCLE
+- (void) release
{
- // Even if the window is borderless, we still want it to be able
- // to become the key window to receive keyboard events
- return YES;
+ DBG_PRINT("NewtWindow::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
+ // NSLog(@"%@",[NSThread callStackSymbols]);
+ [super release];
}
+#endif
-- (void) becomeKeyWindow
+- (void) dealloc
{
- DBG_PRINT( "*************** becomeKeyWindow\n");
- [super becomeKeyWindow];
+ DBG_PRINT("NewtWindow::dealloc.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
+#ifdef DBG_LIFECYCLE
+ NSLog(@"%@",[NSThread callStackSymbols]);
+#endif
+
+ NewtView* mView = (NewtView *)[self contentView];
+ if( NULL != mView ) {
+ [mView release];
+ }
+ [super dealloc];
+ DBG_PRINT("NewtWindow::dealloc.X: %p\n", self);
}
-- (void) resignKeyWindow
+- (void) setRealized: (BOOL)v
{
- DBG_PRINT( "*************** resignKeyWindow: isFullscreen %d\n", (int)isFullscreenWindow);
- if(!isFullscreenWindow) {
- [super resignKeyWindow];
+ realized = v;
+}
+
+- (BOOL) isRealized
+{
+ return realized;
+}
+
+- (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin
+{
+ NSRect frameRect = [self frame];
+ NSRect contentRect = [self contentRectForFrameRect: frameRect];
+
+ // note: this is a simplistic implementation which doesn't take
+ // into account DPI and scaling factor
+ CGFloat l = contentRect.origin.x - frameRect.origin.x;
+ cachedInsets[0] = (int)l; // l
+ cachedInsets[1] = (int)(frameRect.size.width - (contentRect.size.width + l)); // r
+ cachedInsets[2] = (jint)(frameRect.size.height - contentRect.size.height); // t
+ cachedInsets[3] = (jint)(contentRect.origin.y - frameRect.origin.y); // b
+
+ DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]);
+
+ if( NULL != env && NULL != javaWin ) {
+ (*env)->CallVoidMethod(env, javaWin, insetsChangedID, JNI_FALSE, cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]);
}
}
-- (void) windowDidBecomeKey: (NSNotification *) notification
+- (void) attachToParent: (NSWindow*) parent
{
- DBG_PRINT( "*************** windowDidBecomeKey\n");
- mouseInside = [self isMouseInside];
- if(YES == mouseInside) {
- [self cursorHide: !mouseVisible];
+ DBG_PRINT( "attachToParent.1\n");
+ [parent addChildWindow: self ordered: NSWindowAbove];
+ DBG_PRINT( "attachToParent.2\n");
+ [self setParentWindow: parent];
+ DBG_PRINT( "attachToParent.X\n");
+}
+
+- (void) detachFromParent: (NSWindow*) parent
+{
+ DBG_PRINT( "detachFromParent.1\n");
+ [self setParentWindow: nil];
+ if(NULL != parent) {
+ DBG_PRINT( "detachFromParent.2\n");
+ [parent removeChildWindow: self];
}
- [self focusChanged: YES];
+ DBG_PRINT( "detachFromParent.X\n");
}
-- (void) windowDidResignKey: (NSNotification *) notification
+/**
+ * p abs screen position of client-area pos w/ top-left origin, using contentView's client NSSize
+ * returns: abs screen position w/ bottom-left origin
+ */
+- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p
{
- DBG_PRINT( "*************** windowDidResignKey\n");
- // Implicit mouse exit by OS X
- [self focusChanged: NO];
+ NSView* mView = [self contentView];
+ NSRect mViewFrame = [mView frame];
+ return [self newtAbsClientTLWinPos2AbsBLScreenPos: p size: mViewFrame.size];
}
-- (void) keyDown: (NSEvent*) theEvent
+/**
+ * p abs screen position of client-area pos w/ top-left origin, using given client NSSize
+ * returns: abs screen position w/ bottom-left origin
+ */
+- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p size: (NSSize) nsz
{
- [self sendKeyEvent: theEvent eventType: EVENT_KEY_PRESSED];
+ int totalHeight = nsz.height + cachedInsets[3]; // height + insets.bottom
+
+ DBG_PRINT( "newtAbsClientTLWinPos2AbsBLScreenPos: given %d/%d %dx%d, insets bottom %d -> totalHeight %d\n",
+ (int)p.x, (int)p.y, (int)nsz.width, (int)nsz.height, cachedInsets[3], totalHeight);
+
+ NSScreen* screen = [self screen];
+ NSRect screenFrame = [screen frame];
+
+ DBG_PRINT( "newtAbsClientTLWinPos2AbsBLScreenPos: screen %d/%d %dx%d\n",
+ (int)screenFrame.origin.x, (int)screenFrame.origin.y, (int)screenFrame.size.width, (int)screenFrame.size.height);
+
+ NSPoint r = NSMakePoint(screenFrame.origin.x + p.x,
+ screenFrame.origin.y + screenFrame.size.height - p.y - totalHeight);
+
+ DBG_PRINT( "newtAbsClientTLWinPos2AbsBLScreenPos: result %d/%d\n", (int)r.x, (int)r.y);
+
+ return r;
}
-- (void) keyUp: (NSEvent*) theEvent
+/**
+ * p rel client window position w/ top-left origin
+ * returns: abs screen position w/ bottom-left origin
+ */
+- (NSPoint) newtRelClientTLWinPos2AbsBLScreenPos: (NSPoint) p
{
- [self sendKeyEvent: theEvent eventType: EVENT_KEY_RELEASED];
- [self sendKeyEvent: theEvent eventType: EVENT_KEY_TYPED];
+ NSRect winFrame = [self frame];
+
+ NSView* mView = [self contentView];
+ NSRect mViewFrame = [mView frame];
+
+ return NSMakePoint(winFrame.origin.x + p.x,
+ winFrame.origin.y + ( mViewFrame.size.height - p.y ) ); // y-flip in view
}
-- (void) mouseEntered: (NSEvent*) theEvent
+- (NSSize) newtClientSize2TLSize: (NSSize) nsz
{
- DBG_PRINT( "mouseEntered: confined %d, visible %d\n", mouseConfined, mouseVisible);
- mouseInside = YES;
- [self cursorHide: !mouseVisible];
- if(NO == mouseConfined) {
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED];
+ NSSize topSZ = { nsz.width, nsz.height + cachedInsets[2] + cachedInsets[3] }; // height + insets.top + insets.bottom
+ return topSZ;
+}
+
+/**
+ * y-flips input / output
+ * p rel client window position w/ top-left origin
+ * returns: location in 0/0 top-left space.
+ */
+- (NSPoint) getLocationOnScreen: (NSPoint) p
+{
+ NSScreen* screen = [self screen];
+ NSRect screenRect = [screen frame];
+
+ NSView* view = [self contentView];
+ NSRect viewFrame = [view frame];
+
+ NSRect r;
+ r.origin.x = p.x;
+ r.origin.y = viewFrame.size.height - p.y; // y-flip
+ r.size.width = 0;
+ r.size.height = 0;
+ // NSRect rS = [win convertRectToScreen: r]; // 10.7
+ NSPoint oS = [self convertBaseToScreen: r.origin];
+ oS.y = screenRect.origin.y + screenRect.size.height - oS.y;
+ return oS;
+}
+
+- (void) focusChanged: (BOOL) gained
+{
+ DBG_PRINT( "focusChanged: gained %d\n", gained);
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( ! [newtView isKindOfClass:[NewtView class]] ) {
+ return;
+ }
+ jobject javaWindowObject = [newtView getJavaWindowObject];
+ if (javaWindowObject == NULL) {
+ DBG_PRINT("focusChanged: null javaWindowObject\n");
+ return;
+ }
+ int shallBeDetached = 0;
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
+ if(NULL==env) {
+ DBG_PRINT("focusChanged: null JNIEnv\n");
+ return;
}
+
+ (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE);
+
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
-- (void) mouseExited: (NSEvent*) theEvent
+- (void) keyDown: (NSEvent*) theEvent
{
- DBG_PRINT( "mouseExited: confined %d, visible %d\n", mouseConfined, mouseVisible);
- if(NO == mouseConfined) {
- mouseInside = NO;
- [self cursorHide: NO];
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED];
- } else {
- [self setMousePosition: lastInsideMousePosition];
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( [newtView isKindOfClass:[NewtView class]] ) {
+ [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_PRESSED];
}
}
-- (void) mouseMoved: (NSEvent*) theEvent
+- (void) keyUp: (NSEvent*) theEvent
{
- lastInsideMousePosition = [NSEvent mouseLocation];
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( [newtView isKindOfClass:[NewtView class]] ) {
+ [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_RELEASED];
+ }
}
-- (void) scrollWheel: (NSEvent*) theEvent
+- (void) flagsChanged:(NSEvent *) theEvent
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED];
+ NSUInteger mods = [theEvent modifierFlags];
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( [newtView isKindOfClass:[NewtView class]] ) {
+ [newtView handleFlagsChanged: mods];
+ }
}
-- (void) mouseDown: (NSEvent*) theEvent
+- (BOOL) acceptsMouseMovedEvents
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
+ return YES;
}
-- (void) mouseDragged: (NSEvent*) theEvent
+- (BOOL) acceptsFirstResponder
{
- lastInsideMousePosition = [NSEvent mouseLocation];
- // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+ return YES;
}
-- (void) mouseUp: (NSEvent*) theEvent
+- (BOOL) becomeFirstResponder
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
+ DBG_PRINT( "*************** Win.becomeFirstResponder\n");
+ return [super becomeFirstResponder];
}
-- (void) rightMouseDown: (NSEvent*) theEvent
+- (BOOL) resignFirstResponder
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
+ DBG_PRINT( "*************** Win.resignFirstResponder\n");
+ return [super resignFirstResponder];
}
-- (void) rightMouseDragged: (NSEvent*) theEvent
+- (BOOL) canBecomeKeyWindow
{
- lastInsideMousePosition = [NSEvent mouseLocation];
- // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+ // Even if the window is borderless, we still want it to be able
+ // to become the key window to receive keyboard events
+ return YES;
}
-- (void) rightMouseUp: (NSEvent*) theEvent
+- (void) becomeKeyWindow
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
+ DBG_PRINT( "*************** becomeKeyWindow\n");
+ [super becomeKeyWindow];
}
-- (void) otherMouseDown: (NSEvent*) theEvent
+- (void) resignKeyWindow
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED];
+ DBG_PRINT( "*************** resignKeyWindow: isFullscreen %d\n", (int)isFullscreenWindow);
+ if(!isFullscreenWindow) {
+ [super resignKeyWindow];
+ }
}
-- (void) otherMouseDragged: (NSEvent*) theEvent
+- (void) windowDidBecomeKey: (NSNotification *) notification
{
- lastInsideMousePosition = [NSEvent mouseLocation];
- // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED];
+ DBG_PRINT( "*************** windowDidBecomeKey\n");
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( [newtView isKindOfClass:[NewtView class]] ) {
+ BOOL mouseInside = [newtView updateMouseInside];
+ if(YES == mouseInside) {
+ [newtView cursorHide: ![newtView isMouseVisible] enter: 1];
+ }
+ }
+ [self focusChanged: YES];
}
-- (void) otherMouseUp: (NSEvent*) theEvent
+- (void) windowDidResignKey: (NSNotification *) notification
{
- [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED];
+ DBG_PRINT( "*************** windowDidResignKey\n");
+ // Implicit mouse exit by OS X
+ [self focusChanged: NO];
}
- (void)windowDidResize: (NSNotification*) notification
{
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
- }
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
- if (javaWindowObject == NULL) {
- DBG_PRINT("windowDidResize: null javaWindowObject\n");
- return;
- }
+ jobject javaWindowObject = NULL;
int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
- if(NULL==env) {
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
+
+ if( NULL == env ) {
DBG_PRINT("windowDidResize: null JNIEnv\n");
return;
}
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( [newtView isKindOfClass:[NewtView class]] ) {
+ javaWindowObject = [newtView getJavaWindowObject];
+ }
+ if( NULL != javaWindowObject ) {
+ // update insets on every window resize for lack of better hook place
+ [self updateInsets: env jwin:javaWindowObject];
- // update insets on every window resize for lack of better hook place
- [self updateInsets: env];
-
- NSRect frameRect = [self frame];
- NSRect contentRect = [self contentRectForFrameRect: frameRect];
-
- (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_FALSE,
- (jint) contentRect.size.width,
- (jint) contentRect.size.height, JNI_FALSE);
+ NSRect frameRect = [self frame];
+ NSRect contentRect = [self contentRectForFrameRect: frameRect];
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
+ (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_FALSE,
+ (jint) contentRect.size.width,
+ (jint) contentRect.size.height, JNI_FALSE);
}
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
- (void)windowDidMove: (NSNotification*) notification
{
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( ! [newtView isKindOfClass:[NewtView class]] ) {
return;
}
- NewtView* view = (NewtView *) nsview;
- jobject javaWindowObject = [view getJavaWindowObject];
+ jobject javaWindowObject = [newtView getJavaWindowObject];
if (javaWindowObject == NULL) {
DBG_PRINT("windowDidMove: null javaWindowObject\n");
return;
}
int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("windowDidMove: null JNIEnv\n");
return;
@@ -948,9 +1153,8 @@ static jint mods2JavaMods(NSUInteger mods)
p0 = [self getLocationOnScreen: p0];
(*env)->CallVoidMethod(env, javaWindowObject, positionChangedID, JNI_FALSE, (jint) p0.x, (jint) p0.y);
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
}
- (BOOL)windowShouldClose: (id) sender
@@ -966,41 +1170,38 @@ static jint mods2JavaMods(NSUInteger mods)
- (BOOL) windowClosingImpl: (BOOL) force
{
jboolean closed = JNI_FALSE;
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-
- [self cursorHide: NO];
- NSView* nsview = [self contentView];
- if( ! [nsview isMemberOfClass:[NewtView class]] ) {
- return;
+ NewtView* newtView = (NewtView *) [self contentView];
+ if( ! [newtView isKindOfClass:[NewtView class]] ) {
+ return NO;
}
- NewtView* view = (NewtView *) nsview;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [newtView cursorHide: NO enter: -1];
- if( false == [view getDestroyNotifySent] ) {
- jobject javaWindowObject = [view getJavaWindowObject];
+ if( false == [newtView getDestroyNotifySent] ) {
+ jobject javaWindowObject = [newtView getJavaWindowObject];
DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject);
if (javaWindowObject == NULL) {
DBG_PRINT("windowWillClose: null javaWindowObject\n");
- return;
+ [pool release];
+ return NO;
}
int shallBeDetached = 0;
- JavaVM *jvmHandle = [view getJVMHandle];
- JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached);
+ JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
if(NULL==env) {
DBG_PRINT("windowWillClose: null JNIEnv\n");
- return;
+ [pool release];
+ return NO;
}
-
- [view setDestroyNotifySent: true]; // earmark assumption of being closed
+ [newtView setDestroyNotifySent: true]; // earmark assumption of being closed
closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE);
if(!force && !closed) {
// not closed on java side, not force -> clear flag
- [view setDestroyNotifySent: false];
+ [newtView setDestroyNotifySent: false];
}
- if (shallBeDetached) {
- (*jvmHandle)->DetachCurrentThread(jvmHandle);
- }
+ // detaching thread not required - daemon
+ // NewtCommon_ReleaseJNIEnv(shallBeDetached);
DBG_PRINT( "*************** windowWillClose.X: %p, closed %d\n", (void *)(intptr_t)javaWindowObject, (int)closed);
} else {
DBG_PRINT( "*************** windowWillClose (skip)\n");
@@ -1010,3 +1211,4 @@ static jint mods2JavaMods(NSUInteger mods)
}
@end
+