From d186f6e945fd157b219231fb3861b3b0ce10ee75 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Thu, 13 Oct 2011 17:04:17 +0200
Subject: OSX/SWT: Adding OSXUtil: RunOnMainThread(), IsMainThread() /
 Utilizing those for SWT access/calls

Adding OSXUtil: RunOnMainThread(), IsMainThread()
- Issuing a native call where the user Runnable is to be performed on the main thread
- Enable query if we are on the main thread.

Utilizing those for SWT access/calls
- Using the above to call all SWT functions on the main thread if required (incomplete)

TODO/Issues:
- JOGL OSX CGL Context fails, ie expecting NS, but having CGL
---
 .../jogamp/nativewindow/macosx/OSXUtil.java        |  10 +
 .../jogamp/nativewindow/swt/SWTAccessor.java       |  65 ++++--
 src/nativewindow/native/NativewindowCommon.c       |  27 +++
 src/nativewindow/native/NativewindowCommon.h       |   2 +
 src/nativewindow/native/macosx/OSXmisc.c           | 116 -----------
 src/nativewindow/native/macosx/OSXmisc.m           | 217 +++++++++++++++++++++
 6 files changed, 300 insertions(+), 137 deletions(-)
 delete mode 100644 src/nativewindow/native/macosx/OSXmisc.c
 create mode 100644 src/nativewindow/native/macosx/OSXmisc.m

(limited to 'src/nativewindow')

diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index ffd23fef7..ca303e6bc 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -34,6 +34,16 @@ public class OSXUtil {
       return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y);
     }
     
+    public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) {
+        RunOnMainThread0(waitUntilDone, runnable);
+    }
+    
+    public static boolean IsMainThread() {
+        return IsMainThread0();
+    }
+    
     private static native boolean initIDs0();
     private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y);
+    private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable);
+    private static native boolean IsMainThread0();
 }
diff --git a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java
index d1f5efc88..1ad909897 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java
@@ -42,6 +42,8 @@ import javax.media.nativewindow.x11.X11GraphicsDevice;
 import com.jogamp.common.util.ReflectionUtil;
 import javax.media.nativewindow.macosx.MacOSXGraphicsDevice;
 
+import jogamp.nativewindow.macosx.OSXUtil;
+
 public class SWTAccessor {
     static final Field swt_control_handle;
     static final boolean swt_uses_long_handles;
@@ -60,7 +62,7 @@ public class SWTAccessor {
     static final String str_internal_dispose_GC = "internal_dispose_GC";
 
     static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS";
-    static final Class OS_gtk_class;
+    static final Class<?> OS_gtk_class;
     static final Method OS_gtk_widget_realize;
     static final Method OS_gtk_widget_unrealize;
     static final Method OS_GTK_WIDGET_WINDOW;
@@ -113,9 +115,9 @@ public class SWTAccessor {
         }
         swt_control_internal_dispose_GC = m;
 
-        Class c=null;                
+        Class<?> c=null;                
         Method m1=null, m2=null, m3=null, m4=null, m5=null;
-        Class handleType = swt_uses_long_handles  ? long.class : int.class ;
+        Class<?> handleType = swt_uses_long_handles  ? long.class : int.class ;
         if( NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false) ) {
             try {
                 c = ReflectionUtil.getClass(str_OS_gtk_class, false, SWTAccessor.class.getClassLoader());
@@ -179,15 +181,19 @@ public class SWTAccessor {
         return h;
     }
 
-    public static void setRealized(Control swtControl, boolean realize) {
-        long handle = getHandle(swtControl);
+    public static void setRealized(final Control swtControl, final boolean realize) {
+        final long handle = getHandle(swtControl);
         
         if(null != OS_gtk_class) {
-            if(realize) {
-                callStaticMethodL2V(OS_gtk_widget_realize, handle);
-            } else {
-                callStaticMethodL2V(OS_gtk_widget_unrealize, handle);
-            }
+            invoke(true, new Runnable() {
+                public void run() {
+                    if(realize) {
+                        callStaticMethodL2V(OS_gtk_widget_realize, handle);
+                    } else {
+                        callStaticMethodL2V(OS_gtk_widget_unrealize, handle);
+                    }                    
+                }
+            });
         }
     }
     
@@ -220,21 +226,38 @@ public class SWTAccessor {
         throw new UnsupportedOperationException("n/a for this windowing system: "+NativeWindowFactory.getNativeWindowType(false));
     }
     
-    public static long newGC(Control swtControl, GCData gcData) {
-        Object o = ReflectionUtil.callMethod(swtControl, swt_control_internal_new_GC, new Object[] { gcData });
-        if(o instanceof Number) {
-            return ((Number)o).longValue();
+    public static long newGC(final Control swtControl, final GCData gcData) {
+        final Object[] o = new Object[1];
+        invoke(true, new Runnable() {
+            public void run() {
+                o[0] = ReflectionUtil.callMethod(swtControl, swt_control_internal_new_GC, new Object[] { gcData });
+            }
+        });
+        if(o[0] instanceof Number) {
+            return ((Number)o[0]).longValue();
         } else {
-            throw new InternalError("SWT internal_new_GC did not return int or long but "+o.getClass());
+            throw new InternalError("SWT internal_new_GC did not return int or long but "+o[0].getClass());
         }
     }
 
-    public static void disposeGC(Control swtControl, long gc, GCData gcData) {
-        if(swt_uses_long_handles) {
-            ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Long(gc), gcData });
-        }  else {
-            ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Integer((int)gc), gcData });
-        }
+    public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) {
+        invoke(true, new Runnable() {
+            public void run() {
+                if(swt_uses_long_handles) {
+                    ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Long(gc), gcData });
+                }  else {
+                    ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Integer((int)gc), gcData });
+                }
+            }
+        });
+    }
+    
+    public static void invoke(boolean wait, Runnable runnable) {
+        if(Platform.OS_TYPE == Platform.OSType.MACOS) {
+            OSXUtil.RunOnMainThread(wait, runnable);
+        } else {
+            runnable.run();
+        }        
     }
     
 }
diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c
index e357045d6..b866646a6 100644
--- a/src/nativewindow/native/NativewindowCommon.c
+++ b/src/nativewindow/native/NativewindowCommon.c
@@ -55,3 +55,30 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str)
     return strChars;
 }
 
+JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) {
+    JNIEnv* curEnv = NULL;
+    JNIEnv* newEnv = NULL;
+    int envRes;
+
+    // retrieve this thread's JNIEnv curEnv - or detect it's detached
+    envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ;
+    if( JNI_EDETACHED == envRes ) {
+        // detached thread - attach to JVM
+        if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) {
+            fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes);
+            return NULL;
+        }
+        curEnv = newEnv;
+    } else if( JNI_OK != envRes ) {
+        // oops ..
+        fprintf(stderr, "can't GetEnv: %d\n", envRes);
+        return NULL;
+    }
+    if (curEnv==NULL) {
+        fprintf(stderr, "env is NULL\n");
+        return NULL;
+    }
+    *shallBeDetached = NULL != newEnv;
+    return curEnv;
+}
+
diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h
index 5dc5debef..41c4bd0eb 100644
--- a/src/nativewindow/native/NativewindowCommon.h
+++ b/src/nativewindow/native/NativewindowCommon.h
@@ -12,4 +12,6 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str)
 void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...);
 void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...);
 
+JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached);
+
 #endif
diff --git a/src/nativewindow/native/macosx/OSXmisc.c b/src/nativewindow/native/macosx/OSXmisc.c
deleted file mode 100644
index fe0d59bd7..000000000
--- a/src/nativewindow/native/macosx/OSXmisc.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Copyright 2011 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- * 
- *    1. Redistributions of source code must retain the above copyright notice, this list of
- *       conditions and the following disclaimer.
- * 
- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
- *       of conditions and the following disclaimer in the documentation and/or other materials
- *       provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
- 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <AppKit/AppKit.h>
-
-#include "NativewindowCommon.h"
-#include "jogamp_nativewindow_macosx_OSXUtil.h"
-
-static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point";
-static const char * const ClazzAnyCstrName = "<init>";
-static const char * const ClazzNamePointCstrSignature = "(II)V";
-static jclass pointClz = NULL;
-static jmethodID pointCstr = NULL;
-
-static int _initialized=0;
-
-JNIEXPORT jboolean JNICALL 
-Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) {
-    if(0==_initialized) {
-        jclass c;
-        c = (*env)->FindClass(env, ClazzNamePoint);
-        if(NULL==c) {
-            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNamePoint);
-        }
-        pointClz = (jclass)(*env)->NewGlobalRef(env, c);
-        (*env)->DeleteLocalRef(env, c);
-        if(NULL==pointClz) {
-            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNamePoint);
-        }
-        pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature);
-        if(NULL==pointCstr) {
-            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s",
-                ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature);
-        }
-
-        _initialized=1;
-    }
-    return JNI_TRUE;
-}
-
-/*
- * Class:     Java_jogamp_nativewindow_macosx_OSXUtil
- * Method:    getLocationOnScreenImpl0
- * Signature: (JII)Ljavax/media/nativewindow/util/Point;
- */
-JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnScreen0
-  (JNIEnv *env, jclass unused, jlong winOrView, jint src_x, jint src_y)
-{
-    /**
-     * return location in 0/0 top-left space,
-     * OSX is 0/0 bottom-left space naturally
-     */
-    NSRect r;
-    int dest_x=-1;
-    int dest_y=-1;
-
-    NSObject *nsObj = (NSObject*) ((intptr_t) winOrView);
-    NSWindow* win = NULL;
-    NSView* view = NULL;
-
-    if( [nsObj isKindOfClass:[NSWindow class]] ) {
-        win = (NSWindow*) nsObj;
-        view = [win contentView];
-    } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) {
-        view = (NSView*) nsObj;
-        win = [view window];
-    } else {
-        NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj);
-    }
-    NSScreen* screen = [win screen];
-    NSRect screenRect = [screen frame];
-
-    NSRect viewFrame = [view frame];
-
-    r.origin.x = src_x;
-    r.origin.y = viewFrame.size.height - src_y; // y-flip for 0/0 top-left
-    r.size.width = 0;
-    r.size.height = 0;
-    // NSRect rS = [win convertRectToScreen: r]; // 10.7
-    NSPoint oS = [win convertBaseToScreen: r.origin];
-    dest_x = (int) oS.x;
-    dest_y = (int) screenRect.origin.y + screenRect.size.height - oS.y;
-
-    return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y);
-}
-
diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m
new file mode 100644
index 000000000..af71b4a0a
--- /dev/null
+++ b/src/nativewindow/native/macosx/OSXmisc.m
@@ -0,0 +1,217 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+ 
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <AppKit/AppKit.h>
+
+#include "NativewindowCommon.h"
+#include "jogamp_nativewindow_macosx_OSXUtil.h"
+
+static const char * const ClazzNameRunnable = "java/lang/Runnable";
+static jmethodID runnableRunID = NULL;
+
+static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point";
+static const char * const ClazzAnyCstrName = "<init>";
+static const char * const ClazzNamePointCstrSignature = "(II)V";
+static jclass pointClz = NULL;
+static jmethodID pointCstr = NULL;
+
+static int _initialized=0;
+
+JNIEXPORT jboolean JNICALL 
+Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) {
+    if(0==_initialized) {
+        jclass c;
+        c = (*env)->FindClass(env, ClazzNamePoint);
+        if(NULL==c) {
+            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNamePoint);
+        }
+        pointClz = (jclass)(*env)->NewGlobalRef(env, c);
+        (*env)->DeleteLocalRef(env, c);
+        if(NULL==pointClz) {
+            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNamePoint);
+        }
+        pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature);
+        if(NULL==pointCstr) {
+            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s",
+                ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature);
+        }
+
+        c = (*env)->FindClass(env, ClazzNameRunnable);
+        if(NULL==c) {
+            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameRunnable);
+        }
+        runnableRunID = (*env)->GetMethodID(env, c, "run", "()V");
+        if(NULL==runnableRunID) {
+            NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable);
+        }
+        _initialized=1;
+    }
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method:    getLocationOnScreenImpl0
+ * Signature: (JII)Ljavax/media/nativewindow/util/Point;
+ */
+JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnScreen0
+  (JNIEnv *env, jclass unused, jlong winOrView, jint src_x, jint src_y)
+{
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    /**
+     * return location in 0/0 top-left space,
+     * OSX is 0/0 bottom-left space naturally
+     */
+    NSRect r;
+    int dest_x=-1;
+    int dest_y=-1;
+
+    NSObject *nsObj = (NSObject*) ((intptr_t) winOrView);
+    NSWindow* win = NULL;
+    NSView* view = NULL;
+
+    if( [nsObj isKindOfClass:[NSWindow class]] ) {
+        win = (NSWindow*) nsObj;
+        view = [win contentView];
+    } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) {
+        view = (NSView*) nsObj;
+        win = [view window];
+    } else {
+        NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj);
+    }
+    NSScreen* screen = [win screen];
+    NSRect screenRect = [screen frame];
+
+    NSRect viewFrame = [view frame];
+
+    r.origin.x = src_x;
+    r.origin.y = viewFrame.size.height - src_y; // y-flip for 0/0 top-left
+    r.size.width = 0;
+    r.size.height = 0;
+    // NSRect rS = [win convertRectToScreen: r]; // 10.7
+    NSPoint oS = [win convertBaseToScreen: r.origin];
+    dest_x = (int) oS.x;
+    dest_y = (int) screenRect.origin.y + screenRect.size.height - oS.y;
+
+    jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y);
+
+    [pool release];
+
+    return res;
+}
+
+@interface MainRunnable : NSObject
+
+{
+    JavaVM *jvmHandle;
+    int jvmVersion;
+    jobject runnableObj;
+}
+
+- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers;
+- (void) jRun;
+
+@end
+
+@implementation MainRunnable
+
+- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers
+{
+    jvmHandle = jvm;
+    jvmVersion = jvmVers;
+    runnableObj = runnable;
+    return [super init];
+}
+
+- (void) jRun
+{
+    int shallBeDetached = 0;
+    JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached);
+    if(NULL!=env) {
+        (*env)->CallVoidMethod(env, runnableObj, runnableRunID);
+
+        if (shallBeDetached) {
+            (*jvmHandle)->DetachCurrentThread(jvmHandle);
+        }
+    }
+}
+
+@end
+
+
+/*
+ * Class:     Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method:    RunOnMainThread0
+ * Signature: (ZLjava/lang/Runnable;)V
+ */
+JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0
+  (JNIEnv *env, jclass unused, jboolean jwait, jobject runnable)
+{
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    if ( NO == [NSThread isMainThread] ) {
+        jobject runnableGlob = (*env)->NewGlobalRef(env, runnable);
+
+        BOOL wait = (JNI_TRUE == jwait) ? YES : NO;
+        JavaVM *jvmHandle = NULL;
+        int jvmVersion = 0;
+
+        if(0 != (*env)->GetJavaVM(env, &jvmHandle)) {
+            jvmHandle = NULL;
+        } else {
+            jvmVersion = (*env)->GetVersion(env);
+        }
+
+        MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableGlob jvmHandle: jvmHandle jvmVersion: jvmVersion];
+        [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:wait];
+        [mr release];
+
+        (*env)->DeleteGlobalRef(env, runnableGlob);
+    } else {
+        (*env)->CallVoidMethod(env, runnable, runnableRunID);
+    }
+
+    [pool release];
+}
+
+/*
+ * Class:     Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method:    RunOnMainThread0
+ * Signature: (ZLjava/lang/Runnable;)V
+ */
+JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0
+  (JNIEnv *env, jclass unused)
+{
+    return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ;
+}
-- 
cgit v1.2.3