summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java2
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java39
-rw-r--r--src/nativewindow/native/macosx/OSXmisc.m21
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java112
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/event/TestNewtEventModifiersNewtCanvasSWT.java103
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java19
6 files changed, 205 insertions, 91 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
index eba26c7d3..d3e339586 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
@@ -480,7 +480,7 @@ public class SWTAccessor {
* <li>Mac OSX
* <ul>
* <!--li>AWT EDT: In case AWT is available, the AWT EDT is the OSX UI main thread</li-->
- * <li><i>Main Thread</i>: Run on OSX UI main thread.</li>
+ * <li><i>Main Thread</i>: Run on OSX UI main thread. 'wait' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.</li>
* </ul></li>
* <li>Linux, Windows, ..
* <ul>
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index a195f137e..f06f97064 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -32,6 +32,8 @@ import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.util.RunnableTask;
+
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
import jogamp.nativewindow.ToolkitProperties;
@@ -154,11 +156,42 @@ public class OSXUtil implements ToolkitProperties {
DestroyCALayer0(caLayer);
}
+ /**
+ * Run on OSX UI main thread.
+ * <p>
+ * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.
+ * </p>
+ *
+ * @param waitUntilDone
+ * @param runnable
+ */
public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) {
- if(IsMainThread0()) {
+ if( IsMainThread0() ) {
runnable.run(); // don't leave the JVM
} else {
- RunOnMainThread0(waitUntilDone, runnable);
+ if( waitUntilDone ) {
+ // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread,
+ // otherwise we may freeze the OSX main thread.
+ Throwable throwable = null;
+ final Object sync = new Object();
+ final RunnableTask rt = new RunnableTask( runnable, sync, true );
+ synchronized(sync) {
+ RunOnMainThread0(rt);
+ try {
+ sync.wait();
+ } catch (InterruptedException ie) {
+ throwable = ie;
+ }
+ if(null==throwable) {
+ throwable = rt.getThrowable();
+ }
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+ } else {
+ RunOnMainThread0(runnable);
+ }
}
}
@@ -205,7 +238,7 @@ public class OSXUtil implements ToolkitProperties {
private static native void AddCASublayer0(long rootCALayer, long subCALayer);
private static native void RemoveCASublayer0(long rootCALayer, long subCALayer);
private static native void DestroyCALayer0(long caLayer);
- private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable);
+ private static native void RunOnMainThread0(Runnable runnable);
private static native boolean IsMainThread0();
private static native int GetScreenRefreshRate0(int scrn_idx);
}
diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m
index 1cf41fc9d..72bb2338c 100644
--- a/src/nativewindow/native/macosx/OSXmisc.m
+++ b/src/nativewindow/native/macosx/OSXmisc.m
@@ -519,13 +519,18 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
{
int shallBeDetached = 0;
JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached);
+ DBG_PRINT("MainRunnable.0 env: %d\n", (int)(NULL!=env));
if(NULL!=env) {
+ DBG_PRINT("MainRunnable.1.0\n");
(*env)->CallVoidMethod(env, runnableObj, runnableRunID);
+ DBG_PRINT("MainRunnable.1.1\n");
if (shallBeDetached) {
+ DBG_PRINT("MainRunnable.1.2\n");
(*jvmHandle)->DetachCurrentThread(jvmHandle);
}
}
+ DBG_PRINT("MainRunnable.X\n");
}
@end
@@ -537,14 +542,16 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
* Signature: (ZLjava/lang/Runnable;)V
*/
JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0
- (JNIEnv *env, jclass unused, jboolean jwait, jobject runnable)
+ (JNIEnv *env, jclass unused, jobject runnable)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ DBG_PRINT( "RunOnMainThread0: isMainThread %d, NSApp %d, NSApp-isRunning %d\n",
+ (int)([NSThread isMainThread]), (int)(NULL!=NSApp), (int)([NSApp isRunning]));
+
if ( NO == [NSThread isMainThread] ) {
jobject runnableGlob = (*env)->NewGlobalRef(env, runnable);
- BOOL wait = (JNI_TRUE == jwait) ? YES : NO;
JavaVM *jvmHandle = NULL;
int jvmVersion = 0;
@@ -554,14 +561,18 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0
jvmVersion = (*env)->GetVersion(env);
}
+ DBG_PRINT( "RunOnMainThread0.1.0\n");
MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableGlob jvmHandle: jvmHandle jvmVersion: jvmVersion];
- [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:wait];
+ [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO];
[mr release];
+ DBG_PRINT( "RunOnMainThread0.1.1\n");
(*env)->DeleteGlobalRef(env, runnableGlob);
} else {
+ DBG_PRINT( "RunOnMainThread0.2\n");
(*env)->CallVoidMethod(env, runnable, runnableRunID);
}
+ DBG_PRINT( "RunOnMainThread0.X\n");
[pool release];
}
@@ -620,7 +631,7 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR
DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen);
if(NULL != screen) {
CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
- DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)display);
+ DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)(intptr_t)display);
if(0 != display) {
CFDictionaryRef mode = CGDisplayCurrentMode(display);
DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode);
@@ -633,7 +644,7 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR
if(0 == res) {
res = 60; // default .. (experienced on OSX 10.6.8)
}
- DBG_PRINT(stderr, "GetScreenRefreshRate.X: %d\n", res);
+ DBG_PRINT(stderr, "GetScreenRefreshRate.X: %d\n", (int)res);
// [pool release];
JNF_COCOA_EXIT(env);
return res;
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java b/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java
index 85a5f24cb..6cbbc675f 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java
@@ -34,12 +34,12 @@ import java.util.ArrayList ;
import javax.media.opengl.GLProfile ;
import org.junit.After ;
-import org.junit.AfterClass ;
import org.junit.Assert ;
import org.junit.Before ;
import org.junit.BeforeClass ;
import org.junit.Test ;
+import com.jogamp.common.util.RunnableTask;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.opengl.test.junit.util.UITestCase ;
@@ -59,18 +59,18 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
protected static final int TEST_FRAME_WIDTH = 400 ;
protected static final int TEST_FRAME_HEIGHT = 400 ;
- private static final int INITIAL_MOUSE_X = TEST_FRAME_X + ( TEST_FRAME_WIDTH / 2 ) ;
- private static final int INITIAL_MOUSE_Y = TEST_FRAME_Y + ( TEST_FRAME_HEIGHT / 2 ) ;
+ protected static final int INITIAL_MOUSE_X = TEST_FRAME_X + ( TEST_FRAME_WIDTH / 2 ) ;
+ protected static final int INITIAL_MOUSE_Y = TEST_FRAME_Y + ( TEST_FRAME_HEIGHT / 2 ) ;
- private static final int MS_ROBOT_KEY_PRESS_DELAY = 50 ;
- private static final int MS_ROBOT_KEY_RELEASE_DELAY = 50 ;
- private static final int MS_ROBOT_MOUSE_MOVE_DELAY = 100 ;
+ protected static final int MS_ROBOT_KEY_PRESS_DELAY = 50 ;
+ protected static final int MS_ROBOT_KEY_RELEASE_DELAY = 50 ;
+ protected static final int MS_ROBOT_MOUSE_MOVE_DELAY = 100 ;
- private static final int MS_ROBOT_AUTO_DELAY = 50 ;
- private static final int MS_ROBOT_POST_TEST_DELAY = 100;
+ protected static final int MS_ROBOT_AUTO_DELAY = 50 ;
+ protected static final int MS_ROBOT_POST_TEST_DELAY = 100;
- private static final boolean _debug = true ;
- private static PrintStream _debugPrintStream = System.err ;
+ protected static final boolean _debug = true ;
+ protected static PrintStream _debugPrintStream = System.err ;
////////////////////////////////////////////////////////////////////////////
@@ -336,6 +336,35 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
}
////////////////////////////////////////////////////////////////////////////
+ // Following both methods are mandatory to deal with SWT's requirement
+ // to run the SWT event dispatch on the TK thread - which must be the main thread on OSX.
+ // We spawn off the actual test-action into another thread,
+ // while dispatching the events until the test-action is completed.
+ // YES: This is sort of ideal - NOT :)
+
+ protected void eventDispatch() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) { }
+ }
+
+ private void execOffThreadWithOnThreadEventDispatch(Runnable testAction) {
+ Throwable throwable = null;
+ final Object sync = new Object();
+ final RunnableTask rt = new RunnableTask( testAction, sync, true );
+ new Thread(rt, "Test-Thread").start();
+ while( !rt.isExecuted() && null == throwable ) {
+ eventDispatch();
+ }
+ if(null==throwable) {
+ throwable = rt.getThrowable();
+ }
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
// The approach on all these tests is to tell the test mouse listener what
// modifiers we think it should receive. Then when the events are delivered
@@ -357,17 +386,32 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
@Test
public void testSingleButtonPressAndRelease() throws Exception {
- _doSingleButtonPressAndRelease( 0, 0 ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( 0, 0 );
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
@Test
public void testSingleButtonPressAndReleaseWithShift() throws Exception {
- _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_SHIFT, java.awt.event.InputEvent.SHIFT_DOWN_MASK ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_SHIFT, java.awt.event.InputEvent.SHIFT_DOWN_MASK ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
@Test
public void testSingleButtonPressAndReleaseWithCtrl() throws Exception {
- _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_CONTROL, java.awt.event.InputEvent.CTRL_DOWN_MASK ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_CONTROL, java.awt.event.InputEvent.CTRL_DOWN_MASK ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
/**
@@ -375,12 +419,22 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
* so it's probably best to leave them commented out.
@Test
public void testSingleButtonPressAndReleaseWithMeta() throws Exception {
- _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_META, java.awt.event.InputEvent.META_DOWN_MASK ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_META, java.awt.event.InputEvent.META_DOWN_MASK ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
@Test
public void testSingleButtonPressAndReleaseWithAlt() throws Exception {
- _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_ALT, java.awt.event.InputEvent.ALT_DOWN_MASK ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_ALT, java.awt.event.InputEvent.ALT_DOWN_MASK ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
*/
@@ -392,7 +446,12 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
* enough to not let this modifier slip through (?).
@Test
public void testSingleButtonPressAndReleaseWithAltGraph() throws Exception {
- _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_ALT_GRAPH, java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonPressAndRelease( java.awt.event.KeyEvent.VK_ALT_GRAPH, java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
*/
@@ -400,17 +459,32 @@ public abstract class BaseNewtEventModifiers extends UITestCase {
@Test
public void testHoldOneButtonAndPressAnother() throws Exception {
- _doHoldOneButtonAndPressAnother( 0, 0 ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doHoldOneButtonAndPressAnother( 0, 0 ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
@Test
public void testPressAllButtonsInSequence() throws Exception {
- _doPressAllButtonsInSequence( 0, 0 ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doPressAllButtonsInSequence( 0, 0 ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
@Test
public void testSingleButtonClickAndDrag() throws Exception {
- _doSingleButtonClickAndDrag( 0, 0 ) ;
+ execOffThreadWithOnThreadEventDispatch(new Runnable() {
+ public void run() {
+ try {
+ _doSingleButtonClickAndDrag( 0, 0 ) ;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ } } );
}
////////////////////////////////////////////////////////////////////////////
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/event/TestNewtEventModifiersNewtCanvasSWT.java b/src/test/com/jogamp/opengl/test/junit/newt/event/TestNewtEventModifiersNewtCanvasSWT.java
index 83b7ded7a..cafc3dd46 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/event/TestNewtEventModifiersNewtCanvasSWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/event/TestNewtEventModifiersNewtCanvasSWT.java
@@ -59,69 +59,42 @@ public class TestNewtEventModifiersNewtCanvasSWT extends BaseNewtEventModifiers
private static Shell _shell = null;
private static Composite _composite = null;
private static GLWindow _glWindow ;
- private static DisplayThread _displayThread ;
////////////////////////////////////////////////////////////////////////////
-
- private static class DisplayThread extends Thread
- {
- public volatile boolean shallStop = false;
- public volatile boolean isInit = false;
-
- public DisplayThread()
- {
- super( "SWT Display Thread" ) ;
- }
-
- public void run() {
-
- synchronized(this) {
- SWTAccessor.invoke(true, new Runnable() {
- public void run() {
- _display = new Display();
- Assert.assertNotNull( _display );
- }});
-
- isInit = true;
- this.notifyAll();
- }
-
- while( !_display.isDisposed() && !shallStop && isInterrupted() == false ) {
- if( !_display.readAndDispatch() ) {
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) { }
- }
- }
-
- synchronized(this) {
+
+ protected static void eventDispatch2xImpl() {
+ eventDispatchImpl();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) { }
+ eventDispatchImpl();
+ }
+
+ protected static void eventDispatchImpl() {
+ if( !_display.isDisposed() ) {
+ if( !_display.readAndDispatch() ) {
try {
- if(!_display.isDisposed()) {
- SWTAccessor.invoke(true, new Runnable() {
- public void run() {
- _display.dispose();
- }});
- }
- } finally {
- isInit = false;
- this.notifyAll();
- }
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
}
- }
+ }
}
-
+
+ @Override
+ protected void eventDispatch() {
+ eventDispatchImpl();
+ }
+
////////////////////////////////////////////////////////////////////////////
@BeforeClass
public static void beforeClass() throws Exception {
- _displayThread = new DisplayThread() ;
- synchronized(_displayThread) {
- _displayThread.start() ;
- while(!_displayThread.isInit) {
- _displayThread.wait();
- }
- }
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ _display = new Display();
+ }});
+ Assert.assertNotNull( _display );
_display.syncExec(new Runnable() {
public void run() {
@@ -149,10 +122,16 @@ public class TestNewtEventModifiersNewtCanvasSWT extends BaseNewtEventModifiers
}
});
- AWTRobotUtil.assertRequestFocusAndWait(null, _glWindow, _glWindow, null, null); // programmatic
+ // no AWT idling, may deadlock on OSX!
Assert.assertNotNull(_robot);
- AWTRobotUtil.requestFocus(_robot, _glWindow, false); // within unit framework, prev. tests (TestFocus02SwingAWTRobot) 'confuses' Windows keyboard input
-
+ _robot.setAutoWaitForIdle( false ) ;
+
+ // no waiting for results ..
+ AWTRobotUtil.requestFocus(null, _glWindow, false); // programmatic
+ eventDispatch2xImpl();
+ AWTRobotUtil.requestFocus(_robot, _glWindow, INITIAL_MOUSE_X, INITIAL_MOUSE_Y);
+ eventDispatch2xImpl();
+
_glWindow.addMouseListener( _testMouseListener ) ;
}
@@ -171,12 +150,12 @@ public class TestNewtEventModifiersNewtCanvasSWT extends BaseNewtEventModifiers
_shell.dispose();
}});
- synchronized(_displayThread) {
- _displayThread.shallStop = true;
- while( _displayThread.isInit && _displayThread.isAlive() ) {
- _displayThread.wait();
- }
- }
+ if(!_display.isDisposed()) {
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ _display.dispose();
+ }});
+ }
}
catch( Throwable throwable ) {
throwable.printStackTrace();
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
index b5c96d10f..45648bedf 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
@@ -287,7 +287,24 @@ public class AWTRobotUtil {
System.err.println("requestFocus: click, d: "+d+" ms");
}
}
-
+
+ public static void requestFocus(Robot robot, Object obj, int x, int y)
+ throws AWTException, InterruptedException, InvocationTargetException {
+
+ final boolean idling = robot.isAutoWaitForIdle();
+ final int mouseButton = java.awt.event.InputEvent.BUTTON1_MASK;
+ robot.mouseMove( x, y );
+ if( idling ) {
+ robot.waitForIdle();
+ } else {
+ try { Thread.sleep(50); } catch (InterruptedException e) { }
+ }
+ robot.mousePress(mouseButton);
+ robot.mouseRelease(mouseButton);
+ final int d = getClickTimeout(obj) + 1;
+ robot.delay( d );
+ }
+
public static boolean hasFocus(Object obj) {
if(obj instanceof Component) {
final Component comp = (Component) obj;