aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-09-15 07:50:50 +0200
committerSven Gothel <[email protected]>2015-09-15 07:50:50 +0200
commit68c8e39fa8d6e700f0a99241c1a01a435b7f6284 (patch)
treed02cf789a06514da205f6da8a45f55538b019a0b /src
parentcf9b31c30de3768447b20d6aa31ec1df00595871 (diff)
Bug 1211: Hardening Condition-Wait from Spurious-Wakeups and unintended InterruptedException(s)
Below is an updated list of Condition-Wait classifications as described in Bug 1211. This list includes recent changes on GlueGen regarding this Bug 1211. A followup commit will address the unit tests. - Noncancelable + Persistent-Wait - GLMediaPlayerImpl.StreamWorker thread (changed) - pauses thread in case of intr - Cancelable + Persistent-Wait: - LFRingbuffer.getImpl(..) - LFRingbuffer.waitForFreeSlots(int) - SyncedRingbuffer.getImpl(..) - SyncedRingbuffer.waitForFreeSlots(int) - FunctionTask.invokeOnNewThread(..) (changed) - RunnableTask.invokeOnNewThread(..) (changed) - SharedResourceRunner.run() - SharedResourceRunner.doAndWait() (changed) - SharedResourceRunner.start() (changed) - SharedResourceRunner.stop() (changed) - GLMediaPlayerImpl.StreamWorker ctor (changed) - GLMediaPlayerImpl caller thread actions do*() (changed) - AndroidGLMediaPlayerAPI14.getNextTextureImpl(..) (changed) - DisplayImpl.enqueueEvent(..) (changed) -> Persistent-Wait -> Cancels wait and NEWTEvent -> dispatchMessage(NEWTEventTask): always notifyCaller! - GLDrawableHelper.invoke(..) (changed) - DefaultEDTUtil.waitUntilIdle() (changed) - DefaultEDTUtil.waitUntilStopped() (changed) - DefaultEDTUtil.invokeImpl(..) (changed) - DefaultEDTUtil.NEDT.run(..) (changed) - AWTEDTUtil.waitUntilStopped(..) (changed) - AWTEDTUtil.invokeImpl(..) (changed) - AWTEDTUtil.NEDT.run(..) (changed) - SWTEDTUtil.invokeImpl(..) (changed) - SWTEDTUtil.waitUntilStopped(..) (changed) - SWTEDTUtil.NEDT.run(..) (changed) - GLWorkerThread.invokeAndWait(..) - GLWorkerThread.start() (changed) - GLWorkerThread.WorkerRunnable.run() (changed) - Animator.run() (changed) - AnimatorBase.finishLifecycleAction() (changed) - OSXUtil.RunOnMainThread(..) (changed) - SingletonInstanceServerSocket.Server.shutdown() (changed) - SingletonInstanceServerSocket.Server.start() (changed) - com.jogamp.audio.windows.waveout.Mixer.shutdown() (changed) - Extending/Using InterruptSource.Thread (changed) - DefaultEDTUtil.NEDT - AWTEDTUtil.NEDT - SWTEDTUtil.NEDT - GLWorkerThread.thread - Mixer.FillerThread - Mixer.MixerThread - Using InterruptSource.Thread (changed) - TempFileCache - LauncherTempFileCache - Animator.thread - SingletonInstanceServerSocket.Server.serverThread Deprecated: - FunctionTask.invoke(..) (changed) -> on current thread, no wait -> deprecated - RunnableTask.invoke(..) (changed) -> on current thread, no wait -> deprecated
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java239
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java3
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java3
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Animator.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java5
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java3
-rw-r--r--src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java39
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDrawableHelper.java42
-rw-r--r--src/jogl/classes/jogamp/opengl/GLRunnableTask.java5
-rw-r--r--src/jogl/classes/jogamp/opengl/GLWorkerThread.java26
-rw-r--r--src/jogl/classes/jogamp/opengl/SharedResourceRunner.java105
-rw-r--r--src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java11
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java177
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java3
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java43
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java499
-rw-r--r--src/newt/classes/com/jogamp/newt/util/MainThread.java20
-rw-r--r--src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java93
-rw-r--r--src/newt/classes/jogamp/newt/DefaultEDTUtil.java45
-rw-r--r--src/newt/classes/jogamp/newt/DisplayImpl.java14
-rw-r--r--src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java35
-rw-r--r--src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java5
-rw-r--r--src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java3
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java3
-rw-r--r--src/newt/classes/jogamp/newt/event/NEWTEventTask.java8
-rw-r--r--src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java33
26 files changed, 1029 insertions, 456 deletions
diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java
index bbfe72b08..30b3fd278 100644
--- a/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java
+++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java
@@ -36,6 +36,9 @@ import java.io.*;
import java.nio.*;
import java.util.*;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
+
// Needed only for NIO workarounds on CVM
import java.lang.reflect.*;
@@ -43,9 +46,10 @@ public class Mixer {
// This class is a singleton
private static Mixer mixer;
- private volatile boolean shutdown;
- private volatile Object shutdownLock = new Object();
- private volatile boolean shutdownDone;
+ volatile boolean fillerAlive;
+ volatile boolean mixerAlive;
+ volatile boolean shutdown;
+ volatile Object shutdownLock = new Object();
// Windows Event object
private final long event;
@@ -63,6 +67,9 @@ public class Mixer {
private Mixer() {
event = CreateEvent();
+ fillerAlive = false;
+ mixerAlive = false;
+ shutdown = false;
new FillerThread().start();
final MixerThread m = new MixerThread();
m.setPriority(Thread.MAX_PRIORITY - 1);
@@ -118,50 +125,57 @@ public class Mixer {
shutdown = true;
SetEvent(event);
try {
- shutdownLock.wait();
+ while(fillerAlive || mixerAlive) {
+ shutdownLock.wait();
+ }
} catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
}
}
- class FillerThread extends Thread {
+ class FillerThread extends InterruptSource.Thread {
FillerThread() {
- super("Mixer Thread");
+ super(null, null, "Mixer Thread");
}
@Override
public void run() {
- while (!shutdown) {
- final List<Track> curTracks = tracks;
+ fillerAlive = true;
+ try {
+ while (!shutdown) {
+ final List<Track> curTracks = tracks;
- for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
- final Track track = iter.next();
+ for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
+ final Track track = iter.next();
+ try {
+ track.fill();
+ } catch (final IOException e) {
+ e.printStackTrace();
+ remove(track);
+ }
+ }
try {
- track.fill();
- } catch (final IOException e) {
- e.printStackTrace();
- remove(track);
+ // Run ten times per second
+ java.lang.Thread.sleep(100);
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
}
-
- try {
- // Run ten times per second
- Thread.sleep(100);
- } catch (final InterruptedException e) {
- e.printStackTrace();
- }
+ } finally {
+ fillerAlive = false;
}
}
}
- class MixerThread extends Thread {
+ class MixerThread extends InterruptSource.Thread {
// Temporary mixing buffer
// Interleaved left and right channels
float[] mixingBuffer;
private final Vec3f temp = new Vec3f();
MixerThread() {
- super("Mixer Thread");
+ super(null, null, "Mixer Thread");
if (!initializeWaveOut(event)) {
throw new InternalError("Error initializing waveout device");
}
@@ -169,108 +183,113 @@ public class Mixer {
@Override
public void run() {
- while (!shutdown) {
- // Get the next buffer
- final long mixerBuffer = getNextMixerBuffer();
- if (mixerBuffer != 0) {
- ByteBuffer buf = getMixerBufferData(mixerBuffer);
-
- if (buf == null) {
- // This is happening on CVM because
- // JNI_NewDirectByteBuffer isn't implemented
- // by default and isn't compatible with the
- // JSR-239 NIO implementation (apparently)
- buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer),
- getMixerBufferDataCapacity(mixerBuffer));
- }
+ mixerAlive = true;
+ try {
+ while (!shutdown) {
+ // Get the next buffer
+ final long mixerBuffer = getNextMixerBuffer();
+ if (mixerBuffer != 0) {
+ ByteBuffer buf = getMixerBufferData(mixerBuffer);
+
+ if (buf == null) {
+ // This is happening on CVM because
+ // JNI_NewDirectByteBuffer isn't implemented
+ // by default and isn't compatible with the
+ // JSR-239 NIO implementation (apparently)
+ buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer),
+ getMixerBufferDataCapacity(mixerBuffer));
+ }
- if (buf == null) {
- throw new InternalError("Couldn't wrap the native address with a direct byte buffer");
- }
+ if (buf == null) {
+ throw new InternalError("Couldn't wrap the native address with a direct byte buffer");
+ }
- // System.out.println("Mixing buffer");
+ // System.out.println("Mixing buffer");
- // If we don't have enough samples in our mixing buffer, expand it
- // FIXME: knowledge of native output rendering format
- if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) {
- mixingBuffer = new float[buf.capacity() / 2];
- } else {
- // Zap it
- for (int i = 0; i < mixingBuffer.length; i++) {
- mixingBuffer[i] = 0.0f;
+ // If we don't have enough samples in our mixing buffer, expand it
+ // FIXME: knowledge of native output rendering format
+ if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) {
+ mixingBuffer = new float[buf.capacity() / 2];
+ } else {
+ // Zap it
+ for (int i = 0; i < mixingBuffer.length; i++) {
+ mixingBuffer[i] = 0.0f;
+ }
}
- }
-
- // This assertion should be in place if we have stereo
- if ((mixingBuffer.length % 2) != 0) {
- final String msg = "FATAL ERROR: odd number of samples in the mixing buffer";
- System.out.println(msg);
- throw new InternalError(msg);
- }
- // Run down all of the registered tracks mixing them in
- final List<Track> curTracks = tracks;
+ // This assertion should be in place if we have stereo
+ if ((mixingBuffer.length % 2) != 0) {
+ final String msg = "FATAL ERROR: odd number of samples in the mixing buffer";
+ System.out.println(msg);
+ throw new InternalError(msg);
+ }
- for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
- final Track track = iter.next();
- // Consider only playing tracks
- if (track.isPlaying()) {
- // First recompute its gain
- final Vec3f pos = track.getPosition();
- final float leftGain = gain(pos, leftSpeakerPosition);
- final float rightGain = gain(pos, rightSpeakerPosition);
- // Now mix it in
- int i = 0;
- while (i < mixingBuffer.length) {
- if (track.hasNextSample()) {
- final float sample = track.nextSample();
- mixingBuffer[i++] = sample * leftGain;
- mixingBuffer[i++] = sample * rightGain;
- } else {
- // This allows tracks to stall without being abruptly cancelled
- if (track.done()) {
- remove(track);
+ // Run down all of the registered tracks mixing them in
+ final List<Track> curTracks = tracks;
+
+ for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
+ final Track track = iter.next();
+ // Consider only playing tracks
+ if (track.isPlaying()) {
+ // First recompute its gain
+ final Vec3f pos = track.getPosition();
+ final float leftGain = gain(pos, leftSpeakerPosition);
+ final float rightGain = gain(pos, rightSpeakerPosition);
+ // Now mix it in
+ int i = 0;
+ while (i < mixingBuffer.length) {
+ if (track.hasNextSample()) {
+ final float sample = track.nextSample();
+ mixingBuffer[i++] = sample * leftGain;
+ mixingBuffer[i++] = sample * rightGain;
+ } else {
+ // This allows tracks to stall without being abruptly cancelled
+ if (track.done()) {
+ remove(track);
+ }
+ break;
}
- break;
}
}
}
- }
- // Now that we have our data, send it down to the card
- int outPos = 0;
- for (int i = 0; i < mixingBuffer.length; i++) {
- final short val = (short) mixingBuffer[i];
- buf.put(outPos++, (byte) val);
- buf.put(outPos++, (byte) (val >> 8));
- }
- if (!prepareMixerBuffer(mixerBuffer)) {
- throw new RuntimeException("Error preparing mixer buffer");
- }
- if (!writeMixerBuffer(mixerBuffer)) {
- throw new RuntimeException("Error writing mixer buffer to device");
- }
- } else {
- // System.out.println("No mixer buffer available");
+ // Now that we have our data, send it down to the card
+ int outPos = 0;
+ for (int i = 0; i < mixingBuffer.length; i++) {
+ final short val = (short) mixingBuffer[i];
+ buf.put(outPos++, (byte) val);
+ buf.put(outPos++, (byte) (val >> 8));
+ }
+ if (!prepareMixerBuffer(mixerBuffer)) {
+ throw new RuntimeException("Error preparing mixer buffer");
+ }
+ if (!writeMixerBuffer(mixerBuffer)) {
+ throw new RuntimeException("Error writing mixer buffer to device");
+ }
+ } else {
+ // System.out.println("No mixer buffer available");
- // Wait for a buffer to become available
- if (!WaitForSingleObject(event)) {
- throw new RuntimeException("Error while waiting for event object");
- }
+ // Wait for a buffer to become available
+ if (!WaitForSingleObject(event)) {
+ throw new RuntimeException("Error while waiting for event object");
+ }
- /*
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
+ /*
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
+ }
+ */
}
- */
}
- }
-
- // Need to shut down
- shutdownWaveOut();
- synchronized(shutdownLock) {
- shutdownLock.notifyAll();
+ } finally {
+ mixerAlive = false;
+ // Need to shut down
+ shutdownWaveOut();
+ synchronized(shutdownLock) {
+ shutdownLock.notifyAll();
+ }
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java
index 549efd569..38b8f770b 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java
@@ -58,7 +58,8 @@ public interface GLAnimatorControl extends FPSCounter {
* Any exception thrown by this method will be ignored.
* </p>
* @param animator the {@link GLAnimatorControl}
- * @param drawable the causing {@link GLAutoDrawable}
+ * @param drawable the causing {@link GLAutoDrawable},
+ * may be {@code null} in case {@link Throwable} caused unrelated to any {@link GLAutoDrawable}.
* @param cause the uncaught exception
* @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler)
* @since 2.2
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
index 5bf4c106c..20dc71958 100644
--- a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
@@ -98,6 +98,7 @@ import jogamp.opengl.awt.AWTTilePainter;
import jogamp.opengl.awt.Java2D;
import jogamp.opengl.util.glsl.GLSLTextureRaster;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.awt.AWTEDTExecutor;
import com.jogamp.common.util.locks.LockFactory;
@@ -395,7 +396,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
*/
public final boolean initializeBackend(final boolean offthread) {
if( offthread ) {
- new Thread(getThreadName()+"-GLJPanel_Init") {
+ new InterruptSource.Thread(null, null, getThreadName()+"-GLJPanel_Init") {
public void run() {
if( !isInitialized ) {
initializeBackendImpl();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 066709316..10b0b6b5a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -40,6 +40,9 @@
package com.jogamp.opengl.util;
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLException;
@@ -174,6 +177,9 @@ public class Animator extends AnimatorBase {
try {
Animator.this.wait();
} catch (final InterruptedException e) {
+ caughtException = new UncaughtAnimatorException(null, SourcedInterruptedException.wrap(e));
+ stopIssued = true;
+ break; // end pause loop
}
if (wasPaused) {
// resume from pause -> reset counter
@@ -209,8 +215,7 @@ public class Animator extends AnimatorBase {
}
} catch(final ThreadDeath td) {
if(DEBUG) {
- System.err.println("Animator caught: "+td.getClass().getName()+": "+td.getMessage());
- td.printStackTrace();
+ ExceptionUtils.dumpThrowable("", td);
}
caughtThreadDeath = td;
}
@@ -222,8 +227,7 @@ public class Animator extends AnimatorBase {
if( null == caughtException ) {
caughtException = dre;
} else {
- System.err.println("Animator.setExclusiveContextThread: caught: "+dre.getMessage());
- dre.printStackTrace();
+ ExceptionUtils.dumpThrowable("(setExclusiveContextThread)", dre);
}
}
}
@@ -233,8 +237,7 @@ public class Animator extends AnimatorBase {
if(DEBUG) {
System.err.println("Animator stop on " + animThread.getName() + ": " + toString());
if( null != caughtException ) {
- System.err.println("Animator caught: "+caughtException.getMessage());
- caughtException.printStackTrace();
+ ExceptionUtils.dumpThrowable("", caughtException);
}
}
stopIssued = false;
@@ -291,13 +294,7 @@ public class Animator extends AnimatorBase {
runnable = new MainLoop();
}
fpsCounter.resetFPSCounter();
- final String threadName = getThreadName()+"-"+baseName;
- Thread thread;
- if(null==threadGroup) {
- thread = new Thread(runnable, threadName);
- } else {
- thread = new Thread(threadGroup, runnable, threadName);
- }
+ final Thread thread = new InterruptSource.Thread(threadGroup, runnable, getThreadName()+"-"+baseName);
thread.setDaemon(false); // force to be non daemon, regardless of parent thread
if(DEBUG) {
final Thread ct = Thread.currentThread();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index aafdf63f8..41b969551 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -40,6 +40,7 @@ import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLProfile;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptedRuntimeException;
/**
* Base implementation of GLAnimatorControl<br>
@@ -596,7 +597,9 @@ public abstract class AnimatorBase implements GLAnimatorControl {
notifyAll();
try {
wait(pollPeriod);
- } catch (final InterruptedException ie) { }
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
remaining -= System.currentTimeMillis() - t1 ;
nok = waitCondition.eval();
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java
index e6f5aaa2e..38bac06cc 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java
@@ -40,6 +40,7 @@
package com.jogamp.opengl.util.awt;
import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.opengl.GLExtensions;
import com.jogamp.opengl.util.*;
@@ -915,7 +916,7 @@ public class TextRenderer {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
- new Thread(new Runnable() {
+ new InterruptSource.Thread(null, new Runnable() {
@Override
public void run() {
anim.stop();
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 19fd6c7e1..9d1490300 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -51,6 +51,7 @@ import com.jogamp.opengl.GLRunnable;
import com.jogamp.opengl.GLSharedContextSetter;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.RunnableTask;
import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.opengl.GLAutoDrawableDelegate;
import com.jogamp.opengl.GLEventListenerState;
@@ -598,6 +599,44 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe
return helper.getExclusiveContextThread();
}
+ /**
+ * Invokes given {@code runnable} on current thread outside of a probable claimed exclusive thread,
+ * i.e. releases the exclusive thread, executes the runnable and reclaims it.
+ * FIXME: Promote to GLAutoDrawable!
+ *
+ * @param runnable the {@link Runnable} to execute on the new thread.
+ * The runnable <b>must exit</b>, i.e. not loop forever.
+ *
+ * @see #setExclusiveContextThread(Thread, GLContext)
+ *
+ * @since 2.3.2
+ */
+ public final void invokeOnCurrentThread(final Runnable runnable) {
+ helper.runOutsideOfExclusiveContextThread(context, runnable);
+ }
+ /**
+ * Invokes given {@code runnable} on current thread outside of a probable claimed exclusive thread,
+ * i.e. releases the exclusive thread, executes the runnable and reclaims it.
+ * FIXME: Promote to GLAutoDrawable!
+ *
+ * @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code>
+ * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately.
+ * @param runnable the {@link Runnable} to execute on the new thread.
+ * The runnable <b>must exit</b>, i.e. not loop forever.
+ * @return {@link RunnableTask} instance with execution details
+ *
+ * @see #setExclusiveContextThread(Thread, GLContext)
+ *
+ * @since 2.3.2
+ */
+ public final RunnableTask invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable) {
+ return RunnableTask.invokeOnNewThread(tg, null, waitUntilDone,
+ new Runnable() {
+ public final void run() {
+ helper.runOutsideOfExclusiveContextThread(context, runnable);
+ } });
+ }
+
@Override
public final boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException {
return helper.invoke(this, wait, glRunnable);
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index e9ee46a51..6bc93bf36 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -61,6 +61,7 @@ import com.jogamp.opengl.GLFBODrawable;
import com.jogamp.opengl.GLRunnable;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.PropertyAccess;
/** Encapsulates the implementation of most of the GLAutoDrawable's
@@ -874,9 +875,8 @@ public class GLDrawableHelper {
return false;
}
- GLRunnableTask rTask = null;
+ final GLRunnableTask rTask;
final Object rTaskLock = new Object();
- Throwable throwable = null;
synchronized(rTaskLock) {
boolean deferredHere;
synchronized(glRunnablesLock) {
@@ -910,13 +910,13 @@ public class GLDrawableHelper {
drawable.display();
} else if( wait ) {
try {
- rTaskLock.wait(); // free lock, allow execution of rTask
+ while( rTask.isInQueue() ) {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ }
} catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rTask.getThrowable();
+ throw new InterruptedRuntimeException(ie);
}
+ final Throwable throwable = rTask.getThrowable();
if(null!=throwable) {
throw new RuntimeException(throwable);
}
@@ -941,9 +941,8 @@ public class GLDrawableHelper {
}
final int count = newGLRunnables.size();
- GLRunnableTask rTask = null;
+ final GLRunnableTask rTask;
final Object rTaskLock = new Object();
- Throwable throwable = null;
synchronized(rTaskLock) {
boolean deferredHere;
synchronized(glRunnablesLock) {
@@ -981,13 +980,13 @@ public class GLDrawableHelper {
drawable.display();
} else if( wait ) {
try {
- rTaskLock.wait(); // free lock, allow execution of rTask
+ while( rTask.isInQueue() ) {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ }
} catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rTask.getThrowable();
+ throw new InterruptedRuntimeException(ie);
}
+ final Throwable throwable = rTask.getThrowable();
if(null!=throwable) {
throw new RuntimeException(throwable);
}
@@ -1082,6 +1081,21 @@ public class GLDrawableHelper {
return exclusiveContextThread;
}
+ /**
+ * Runs given {@code runnable} outside of a probable claimed exclusive thread,
+ * i.e. releases the exclusive thread, executes the runnable and reclaims it.
+ * @see #setExclusiveContextThread(Thread, GLContext)
+ * @since 2.3.2
+ */
+ public final void runOutsideOfExclusiveContextThread(final GLContext context, final Runnable runnable) {
+ final Thread t = setExclusiveContextThread(null, context);
+ try {
+ runnable.run();
+ } finally {
+ setExclusiveContextThread(t, context);
+ }
+ }
+
private static final ThreadLocal<WeakReference<Runnable>> perThreadInitAction = new ThreadLocal<WeakReference<Runnable>>();
private static final Runnable getLastInitAction() {
final WeakReference<Runnable> lastInitActionWR = perThreadInitAction.get();
diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
index 1a6024bfa..cfe3df95d 100644
--- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
+++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
@@ -29,6 +29,7 @@
package jogamp.opengl;
import com.jogamp.opengl.GLRunnable;
+import com.jogamp.common.ExceptionUtils;
import com.jogamp.opengl.GLAutoDrawable;
/**
@@ -61,7 +62,7 @@ public class GLRunnableTask implements GLRunnable {
} catch (final Throwable t) {
runnableException = t;
if(catchExceptions) {
- runnableException.printStackTrace();
+ ExceptionUtils.dumpThrowable("", runnableException);
} else {
throw new RuntimeException(runnableException);
}
@@ -75,7 +76,7 @@ public class GLRunnableTask implements GLRunnable {
} catch (final Throwable t) {
runnableException = t;
if(catchExceptions) {
- runnableException.printStackTrace();
+ ExceptionUtils.dumpThrowable("", runnableException);
} else {
throw new RuntimeException(runnableException);
}
diff --git a/src/jogl/classes/jogamp/opengl/GLWorkerThread.java b/src/jogl/classes/jogamp/opengl/GLWorkerThread.java
index c03cdea02..3d0adfc9c 100644
--- a/src/jogl/classes/jogamp/opengl/GLWorkerThread.java
+++ b/src/jogl/classes/jogamp/opengl/GLWorkerThread.java
@@ -43,6 +43,9 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.opengl.GLContext;
/** Singleton thread upon which all OpenGL work is performed by
@@ -78,15 +81,18 @@ public class GLWorkerThread {
synchronized (GLWorkerThread.class) {
if (!started) {
lock = new Object();
- thread = new Thread(new WorkerRunnable(),
- "JOGL-GLWorkerThread-");
+ final WorkerRunnable worker = new WorkerRunnable();
+ thread = new InterruptSource.Thread(null, worker, "JOGL-GLWorkerThread-");
thread.setDaemon(true);
started = true;
synchronized (lock) {
thread.start();
try {
- lock.wait();
+ while(!worker.isRunning) {
+ lock.wait();
+ }
} catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
}
@@ -119,7 +125,7 @@ public class GLWorkerThread {
// less cooperatively
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
public void run() {
Object lockTemp = lock;
if (lockTemp == null) {
@@ -177,7 +183,9 @@ public class GLWorkerThread {
work = runnable;
lockTemp.notifyAll();
- lockTemp.wait();
+ while( null != work ) {
+ lockTemp.wait();
+ }
if (exception != null) {
final Throwable localException = exception;
exception = null;
@@ -222,10 +230,13 @@ public class GLWorkerThread {
protected static String getThreadName() { return Thread.currentThread().getName(); }
static class WorkerRunnable implements Runnable {
+ volatile boolean isRunning = false;
+
@Override
public void run() {
// Notify starting thread that we're ready
synchronized (lock) {
+ isRunning = true;
lock.notifyAll();
}
@@ -238,6 +249,7 @@ public class GLWorkerThread {
// Avoid race conditions with wanting to release contexts on this thread
lock.wait(1000);
} catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
if (GLContext.getCurrent() != null) {
@@ -269,8 +281,7 @@ public class GLWorkerThread {
final Runnable curAsync = queue.remove(0);
curAsync.run();
} catch (final Throwable t) {
- System.err.println(getThreadName()+": Exception occurred on JOGL OpenGL worker thread:");
- t.printStackTrace();
+ ExceptionUtils.dumpThrowable("suppressed", t); // Noncancelable
}
}
@@ -285,6 +296,7 @@ public class GLWorkerThread {
}
}
}
+ isRunning = false;
}
}
}
diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java
index de4a35a9b..0f6c1f875 100644
--- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java
+++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java
@@ -38,6 +38,9 @@ import com.jogamp.nativewindow.AbstractGraphicsScreen;
import com.jogamp.opengl.GLProfile;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.opengl.GLRendererQuirks;
public class SharedResourceRunner implements Runnable {
@@ -166,13 +169,18 @@ public class SharedResourceRunner implements Runnable {
System.err.println("SharedResourceRunner.start() - start new Thread - "+getThreadName());
}
resetState();
- thread = new Thread(this, getThreadName()+"-SharedResourceRunner");
+ thread = new InterruptSource.Thread(null, this, getThreadName()+"-SharedResourceRunner");
thread.setDaemon(true); // Allow JVM to exit, even if this one is running
thread.start();
- while (!running) {
- try {
+ try {
+ while (!running) {
this.wait();
- } catch (final InterruptedException ex) { }
+ }
+ } catch (final InterruptedException ex) {
+ // Cleanup
+ shouldRelease = true;
+ this.notifyAll();
+ throw new InterruptedRuntimeException(ex);
}
}
}
@@ -188,11 +196,12 @@ public class SharedResourceRunner implements Runnable {
synchronized (this) {
shouldRelease = true;
this.notifyAll();
-
- while (running) {
- try {
+ try {
+ while (running) {
this.wait();
- } catch (final InterruptedException ex) { }
+ }
+ } catch (final InterruptedException ex) {
+ throw new InterruptedRuntimeException(ex);
}
}
}
@@ -213,7 +222,11 @@ public class SharedResourceRunner implements Runnable {
ExceptionUtils.dumpStack(System.err);
}
if ( impl.isDeviceSupported(device) ) {
- doAndWait(device, null);
+ try {
+ doAndWait(device, null);
+ } catch (final InterruptedException ex) {
+ throw new InterruptedRuntimeException(ex);
+ }
sr = impl.mapGet(device);
}
if (DEBUG) {
@@ -236,7 +249,11 @@ public class SharedResourceRunner implements Runnable {
if (DEBUG) {
System.err.println("SharedResourceRunner.releaseShared() " + device + ": trying - "+getThreadName());
}
- doAndWait(null, device);
+ try {
+ doAndWait(null, device);
+ } catch (final InterruptedException ex) {
+ throw new InterruptedRuntimeException(ex);
+ }
if (DEBUG) {
System.err.println("SharedResourceRunner.releaseShared() " + device + ": done - "+getThreadName());
}
@@ -246,7 +263,7 @@ public class SharedResourceRunner implements Runnable {
return sr;
}
- private final void doAndWait(final AbstractGraphicsDevice initDevice, final AbstractGraphicsDevice releaseDevice) {
+ private final void doAndWait(final AbstractGraphicsDevice initDevice, final AbstractGraphicsDevice releaseDevice) throws InterruptedException {
synchronized (this) {
// wait until thread becomes ready to init new device,
// pass the device and release the sync
@@ -254,26 +271,41 @@ public class SharedResourceRunner implements Runnable {
if (DEBUG) {
System.err.println("SharedResourceRunner.doAndWait() START init: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
}
- while (!ready && running) {
- try {
+ try {
+ while (!ready && running) {
this.wait();
- } catch (final InterruptedException ex) { }
- }
- if (DEBUG) {
- System.err.println("SharedResourceRunner.doAndWait() set command: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
- }
- this.initDevice = initDevice;
- this.releaseDevice = releaseDevice;
- this.notifyAll();
+ }
+ if (DEBUG) {
+ System.err.println("SharedResourceRunner.doAndWait() set command: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
+ }
+ this.initDevice = initDevice;
+ this.releaseDevice = releaseDevice;
+ this.notifyAll();
- // wait until thread has init/released the device
- while ( running && ( !ready || null != this.initDevice || null != this.releaseDevice ) ) {
- try {
+ // wait until thread has init/released the device
+ while ( running && ( !ready || null != this.initDevice || null != this.releaseDevice ) ) {
this.wait();
- } catch (final InterruptedException ex) { }
+ }
+ } catch (final InterruptedException ex) {
+ final InterruptedException ex2 = SourcedInterruptedException.wrap(ex);
+ if (DEBUG) {
+ System.err.println("SharedResourceRunner.doAndWait() INTERRUPT init: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
+ ExceptionUtils.dumpThrowable("", ex2);
+ }
+ // Cleanup initDevice due to exception!
+ final AbstractGraphicsDevice _initDevice = this.initDevice;
+ if( null != _initDevice ) {
+ if (DEBUG) {
+ System.err.println("SharedResourceRunner.doAndWait() Cleanup init: " + _initDevice + " -> release: "+this.releaseDevice+" - "+threadName);
+ }
+ this.releaseDevice = _initDevice;
+ this.initDevice = null;
+ this.notifyAll();
+ }
+ throw ex2;
}
if (DEBUG) {
- System.err.println("SharedResourceRunner.initializeAndWait END init: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
+ System.err.println("SharedResourceRunner.doAndWait() END init: " + initDevice + ", release: "+releaseDevice+" - "+threadName);
}
}
// done
@@ -292,19 +324,18 @@ public class SharedResourceRunner implements Runnable {
while (!shouldRelease) {
try {
- // wait for stop or init
+ // wait until call-thread issues stop or init/released a device
ready = true;
if (DEBUG) {
System.err.println("SharedResourceRunner.run(): READY - " + threadName);
}
notifyAll();
- this.wait();
+ while ( !shouldRelease && null == initDevice && null == releaseDevice ) {
+ this.wait();
+ }
} catch (final InterruptedException ex) {
shouldRelease = true;
- if(DEBUG) {
- System.err.println("SharedResourceRunner.run(): INTERRUPTED - "+threadName);
- ex.printStackTrace();
- }
+ ExceptionUtils.dumpThrowable("handled", SourcedInterruptedException.wrap(ex)); // cancelable
}
ready = false;
@@ -321,7 +352,7 @@ public class SharedResourceRunner implements Runnable {
try {
sr = impl.createSharedResource(initDevice);
} catch (final Exception e) {
- e.printStackTrace();
+ ExceptionUtils.dumpThrowable("handled", e);
}
if (null != sr) {
impl.mapPut(initDevice, sr);
@@ -335,9 +366,10 @@ public class SharedResourceRunner implements Runnable {
if (null != sr) {
try {
impl.releaseSharedResource(sr);
- impl.mapPut(releaseDevice, null);
} catch (final Exception e) {
- e.printStackTrace();
+ ExceptionUtils.dumpThrowable("handled", e);
+ } finally {
+ impl.mapPut(releaseDevice, null);
}
}
}
@@ -370,8 +402,7 @@ public class SharedResourceRunner implements Runnable {
try {
impl.releaseSharedResource(iter.next());
} catch (final Throwable t) {
- System.err.println("Caught exception on thread "+getThreadName());
- t.printStackTrace();
+ ExceptionUtils.dumpThrowable("", t);
}
}
impl.clear();
diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
index da81922a4..09d2dfda0 100644
--- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
+++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
@@ -33,7 +33,6 @@ import java.util.List;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GLES2;
import com.jogamp.opengl.GLException;
-
import com.jogamp.common.os.AndroidVersion;
import com.jogamp.common.os.Platform;
import com.jogamp.opengl.util.TimeFrameI;
@@ -364,7 +363,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
}
@Override
- protected final int getNextTextureImpl(final GL gl, final TextureFrame nextFrame) {
+ protected final int getNextTextureImpl(final GL gl, final TextureFrame nextFrame) throws InterruptedException {
int pts = TimeFrameI.INVALID_PTS;
if(null != mp || null != cam) {
final SurfaceTextureFrame sTexFrame = null != nextFrame ? (SurfaceTextureFrame) nextFrame : singleSTexFrame;
@@ -398,12 +397,8 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
boolean update = updateSurface;
if( !update ) {
synchronized(updateSurfaceLock) {
- if(!updateSurface) { // volatile OK.
- try {
- updateSurfaceLock.wait();
- } catch (final InterruptedException e) {
- e.printStackTrace();
- }
+ while(!updateSurface) { // volatile OK.
+ updateSurfaceLock.wait(); // propagates InterruptedException
}
update = updateSurface;
updateSurface = false;
diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
index cfecbfd8d..1b19eced7 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
@@ -46,10 +46,14 @@ import com.jogamp.opengl.GLProfile;
import jogamp.opengl.Debug;
import com.jogamp.common.net.UriQueryProps;
+import com.jogamp.common.ExceptionUtils;
import com.jogamp.common.net.Uri;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.LFRingbuffer;
import com.jogamp.common.util.Ringbuffer;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.opengl.GLExtensions;
import com.jogamp.opengl.util.TimeFrameI;
import com.jogamp.opengl.util.av.AudioSink;
@@ -365,7 +369,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
event_mask = addStateEventMask(event_mask, GLMediaPlayer.State.Paused);
setState( State.Paused );
if( null != streamWorker ) {
- streamWorker.doPause();
+ streamWorker.doPause(true);
}
if( flush ) {
resetAVPTSAndFlush();
@@ -414,7 +418,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
final State _state = state;
setState( State.Paused );
if( null != streamWorker ) {
- streamWorker.doPause();
+ streamWorker.doPause(true);
}
// Adjust target ..
if( msec >= duration ) {
@@ -571,7 +575,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
this.vid = vid;
this.aid = aid;
- new Thread() {
+ new InterruptSource.Thread() {
public void run() {
try {
// StreamWorker may be used, see API-doc of StreamWorker
@@ -968,8 +972,9 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
* shall be <code>null</code> for audio only.
* @return the last processed video PTS value, maybe {@link TimeFrameI#INVALID_PTS} if video frame is invalid or n/a.
* Will be {@link TimeFrameI#END_OF_STREAM_PTS} if end of stream reached.
+ * @throws InterruptedException if waiting for next frame fails
*/
- protected abstract int getNextTextureImpl(GL gl, TextureFrame nextFrame);
+ protected abstract int getNextTextureImpl(GL gl, TextureFrame nextFrame) throws InterruptedException;
protected final int getNextSingleThreaded(final GL gl, final TextureFrame nextFrame, final boolean[] gotVFrame) throws InterruptedException {
final int pts;
@@ -1064,7 +1069,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
* {@link GLMediaPlayerImpl#updateAttributes(int, int, int, int, int, int, int, float, int, int, int, String, String) updateAttributes(..)},
* the latter decides whether StreamWorker is being used.
*/
- class StreamWorker extends Thread {
+ class StreamWorker extends InterruptSource.Thread {
private volatile boolean isRunning = false;
private volatile boolean isActive = false;
private volatile boolean isBlocked = false;
@@ -1086,13 +1091,13 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
setDaemon(true);
synchronized(this) {
start();
- while( !isRunning ) {
+ try {
this.notifyAll(); // wake-up startup-block
- try {
+ while( !isRunning && !shallStop ) {
this.wait(); // wait until started
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
}
}
@@ -1140,18 +1145,20 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
sharedGLCtx.release();
}
}
- public final synchronized void doPause() {
+ public final synchronized void doPause(final boolean waitUntilDone) {
if( isActive ) {
shallPause = true;
- if( Thread.currentThread() != this ) {
+ if( java.lang.Thread.currentThread() != this ) {
if( isBlocked && isActive ) {
this.interrupt();
}
- while( isActive && isRunning ) {
+ if( waitUntilDone ) {
try {
- this.wait(); // wait until paused
+ while( isActive && isRunning ) {
+ this.wait(); // wait until paused
+ }
} catch (final InterruptedException e) {
- e.printStackTrace();
+ throw new InterruptedRuntimeException(e);
}
}
}
@@ -1160,14 +1167,16 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
public final synchronized void doResume() {
if( isRunning && !isActive ) {
shallPause = false;
- if( Thread.currentThread() != this ) {
- while( !isActive && !shallPause && isRunning ) {
+ if( java.lang.Thread.currentThread() != this ) {
+ try {
this.notifyAll(); // wake-up pause-block
- try {
+ while( !isActive && !shallPause && isRunning ) {
this.wait(); // wait until resumed
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ final InterruptedException e2 = SourcedInterruptedException.wrap(e);
+ doPause(false);
+ throw new InterruptedRuntimeException(e2);
}
}
}
@@ -1175,17 +1184,17 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
public final synchronized void doStop() {
if( isRunning ) {
shallStop = true;
- if( Thread.currentThread() != this ) {
+ if( java.lang.Thread.currentThread() != this ) {
if( isBlocked && isRunning ) {
this.interrupt();
}
- while( isRunning ) {
+ try {
this.notifyAll(); // wake-up pause-block (opt)
- try {
+ while( isRunning ) {
this.wait(); // wait until stopped
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
}
}
@@ -1203,48 +1212,48 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
this.notifyAll(); // wake-up ctor()
}
- while( !shallStop ){
- if( shallPause ) {
- synchronized ( this ) {
- if( sharedGLCtxCurrent ) {
- postNextTextureImpl(sharedGLCtx.getGL());
- sharedGLCtx.release();
- }
- while( shallPause && !shallStop ) {
- isActive = false;
- this.notifyAll(); // wake-up doPause()
- try {
- this.wait(); // wait until resumed
- } catch (final InterruptedException e) {
- if( !shallPause ) {
- e.printStackTrace();
+ while( !shallStop ) {
+ TextureFrame nextFrame = null;
+ try {
+ if( shallPause ) {
+ synchronized ( this ) {
+ if( sharedGLCtxCurrent ) {
+ postNextTextureImpl(sharedGLCtx.getGL());
+ sharedGLCtx.release();
+ }
+ while( shallPause && !shallStop ) {
+ isActive = false;
+ this.notifyAll(); // wake-up doPause()
+ try {
+ this.wait(); // wait until resumed
+ } catch (final InterruptedException e) {
+ if( !shallPause ) {
+ throw SourcedInterruptedException.wrap(e);
+ }
}
}
+ if( sharedGLCtxCurrent ) {
+ makeCurrent(sharedGLCtx);
+ preNextTextureImpl(sharedGLCtx.getGL());
+ }
+ isActive = true;
+ this.notifyAll(); // wake-up doResume()
}
- if( sharedGLCtxCurrent ) {
- makeCurrent(sharedGLCtx);
- preNextTextureImpl(sharedGLCtx.getGL());
- }
- isActive = true;
- this.notifyAll(); // wake-up doResume()
}
- }
- if( !sharedGLCtxCurrent && null != sharedGLCtx ) {
- synchronized ( this ) {
- if( null != sharedGLCtx ) {
- makeCurrent( sharedGLCtx );
- preNextTextureImpl(sharedGLCtx.getGL());
- sharedGLCtxCurrent = true;
- }
- if( null == videoFramesFree ) {
- throw new InternalError("XXX videoFramesFree is null");
+ if( !sharedGLCtxCurrent && null != sharedGLCtx ) {
+ synchronized ( this ) {
+ if( null != sharedGLCtx ) {
+ makeCurrent( sharedGLCtx );
+ preNextTextureImpl(sharedGLCtx.getGL());
+ sharedGLCtxCurrent = true;
+ }
+ if( null == videoFramesFree ) {
+ throw new InternalError("XXX videoFramesFree is null");
+ }
}
}
- }
- if( !shallStop ) {
- TextureFrame nextFrame = null;
- try {
+ if( !shallStop ) {
isBlocked = true;
final GL gl;
if( STREAM_ID_NONE != vid ) {
@@ -1260,7 +1269,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( TimeFrameI.INVALID_PTS != vPTS ) {
if( null != nextFrame ) {
if( STREAM_WORKER_DELAY > 0 ) {
- Thread.sleep(STREAM_WORKER_DELAY);
+ java.lang.Thread.sleep(STREAM_WORKER_DELAY);
}
if( !videoFramesDecoded.put(nextFrame) ) {
throw new InternalError("XXX: free "+videoFramesFree+", decoded "+videoFramesDecoded+", "+GLMediaPlayerImpl.this);
@@ -1294,31 +1303,30 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_EOS);
}
- } catch (final InterruptedException e) {
- isBlocked = false;
- if( !shallStop && !shallPause ) {
- streamErr = new StreamException("InterruptedException while decoding: "+GLMediaPlayerImpl.this.toString(), e);
- }
- } catch (final Throwable t) {
- streamErr = new StreamException(t.getClass().getSimpleName()+" while decoding: "+GLMediaPlayerImpl.this.toString(), t);
- } finally {
- if( null != nextFrame ) { // put back
- videoFramesFree.put(nextFrame);
+ }
+ } catch (final InterruptedException e) {
+ if( !isBlocked ) { // !shallStop && !shallPause
+ streamErr = new StreamException("InterruptedException while decoding: "+GLMediaPlayerImpl.this.toString(),
+ SourcedInterruptedException.wrap(e));
+ }
+ isBlocked = false;
+ } catch (final Throwable t) {
+ streamErr = new StreamException(t.getClass().getSimpleName()+" while decoding: "+GLMediaPlayerImpl.this.toString(), t);
+ } finally {
+ if( null != nextFrame ) { // put back
+ videoFramesFree.put(nextFrame);
+ }
+ if( null != streamErr ) {
+ if( DEBUG ) {
+ ExceptionUtils.dumpThrowable("handled", streamErr);
}
- if( null != streamErr ) {
- if( DEBUG ) {
- final Throwable t = null != streamErr.getCause() ? streamErr.getCause() : streamErr;
- System.err.println("Caught StreamException: "+t.getMessage());
- t.printStackTrace();
- }
- // state transition incl. notification
- synchronized ( this ) {
- shallPause = true;
- isActive = false;
- this.notifyAll(); // wake-up potential do*()
- }
- pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_ERR);
+ // state transition incl. notification
+ synchronized ( this ) {
+ shallPause = true;
+ isActive = false;
+ this.notifyAll(); // wake-up potential do*()
}
+ pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_ERR);
}
}
}
@@ -1387,7 +1395,6 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( wasUninitialized ) {
event_mask |= GLMediaEventListener.EVENT_CHANGE_INIT;
- setState( State.Initialized );
}
if( STREAM_ID_AUTO == vid ) {
vid = STREAM_ID_NONE;
@@ -1444,10 +1451,12 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
if( wasUninitialized ) {
if( null != streamWorker ) {
+ changeState(GLMediaEventListener.EVENT_CHANGE_ERR, GLMediaPlayer.State.Uninitialized);
throw new InternalError("XXX: StreamWorker not null - "+this);
}
if( TEXTURE_COUNT_MIN < textureCount || STREAM_ID_NONE == vid ) { // Enable StreamWorker for 'audio only' as well (Bug 918).
streamWorker = new StreamWorker();
+ setState( State.Initialized );
}
if( DEBUG ) {
System.err.println("XXX Initialize @ updateAttributes: "+this);
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
index d2db09adf..5da7974b0 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
@@ -57,6 +57,7 @@ import jogamp.nativewindow.x11.X11Lib;
import jogamp.nativewindow.x11.X11Util;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos;
@@ -183,7 +184,7 @@ public abstract class NativeWindowFactory {
_DEBUG[0] = Debug.debug("NativeWindow");
_tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true);
Runtime.getRuntime().addShutdownHook(
- new Thread(new Runnable() {
+ new InterruptSource.Thread(null, new Runnable() {
@Override
public void run() {
NativeWindowFactory.shutdown(true);
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index 8ad089a56..f71dff1cb 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -34,6 +34,7 @@ import com.jogamp.nativewindow.util.Point;
import com.jogamp.common.util.Function;
import com.jogamp.common.util.FunctionTask;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.RunnableTask;
import jogamp.nativewindow.Debug;
@@ -267,22 +268,21 @@ public class OSXUtil implements ToolkitProperties {
} else {
// 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, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
synchronized(sync) {
RunOnMainThread0(kickNSApp, rt);
if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
}
}
}
@@ -341,23 +341,22 @@ public class OSXUtil implements ToolkitProperties {
} else {
// 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 FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
synchronized(sync) {
rt.setArgs(args);
RunOnMainThread0(kickNSApp, rt);
if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
}
}
}
diff --git a/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
new file mode 100644
index 000000000..ca4b51192
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
@@ -0,0 +1,499 @@
+/**
+ * Copyright 2015 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.
+ */
+package com.jogamp.newt.opengl.util;
+
+import java.net.URLConnection;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+import com.jogamp.nativewindow.ScalableSurface;
+import com.jogamp.newt.Display;
+import com.jogamp.newt.Display.PointerIcon;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.MouseListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.FPSCounter;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GLAnimatorControl;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLRunnable;
+import com.jogamp.opengl.util.Gamma;
+import com.jogamp.opengl.util.PNGPixelRect;
+
+import jogamp.newt.driver.PNGIcon;
+
+public class NEWTDemoListener extends WindowAdapter implements KeyListener, MouseListener {
+ protected final GLWindow glWindow;
+ final PointerIcon[] pointerIcons;
+ int pointerIconIdx = 0;
+ float gamma = 1f;
+ float brightness = 0f;
+ float contrast = 1f;
+ boolean confinedFixedCenter = false;
+
+ public NEWTDemoListener(final GLWindow glWin, final PointerIcon[] pointerIcons) {
+ this.glWindow = glWin;
+ if( null != pointerIcons ) {
+ this.pointerIcons = pointerIcons;
+ } else {
+ this.pointerIcons = createPointerIcons(glWindow);
+ }
+ }
+ public NEWTDemoListener(final GLWindow glWin) {
+ this(glWin, null);
+ }
+
+ protected void printlnState(final String prelude) {
+ System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString());
+ }
+ protected void printlnState(final String prelude, final String post) {
+ System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString()+", "+post);
+ }
+
+ @Override
+ public void keyPressed(final KeyEvent e) {
+ if( e.isAutoRepeat() || e.isConsumed() ) {
+ return;
+ }
+ final int keySymbol = e.getKeySymbol();
+ switch(keySymbol) {
+ case KeyEvent.VK_SPACE:
+ e.setConsumed(true);
+ glWindow.invokeOnCurrentThread(new Runnable() {
+ public void run() {
+ if(glWindow.getAnimator().isPaused()) {
+ glWindow.getAnimator().resume();
+ } else {
+ glWindow.getAnimator().pause();
+ }
+ } } );
+ break;
+ case KeyEvent.VK_A:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set alwaysontop pre]");
+ glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
+ printlnState("[set alwaysontop post]");
+ } } );
+ break;
+ case KeyEvent.VK_B:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set alwaysonbottom pre]");
+ glWindow.setAlwaysOnBottom(!glWindow.isAlwaysOnBottom());
+ printlnState("[set alwaysonbottom post]");
+ } } );
+ break;
+ case KeyEvent.VK_C:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ if( null != pointerIcons ) {
+ printlnState("[set pointer-icon pre]");
+ final PointerIcon currentPI = glWindow.getPointerIcon();
+ final PointerIcon newPI;
+ if( pointerIconIdx >= pointerIcons.length ) {
+ newPI=null;
+ pointerIconIdx=0;
+ } else {
+ newPI=pointerIcons[pointerIconIdx++];
+ }
+ glWindow.setPointerIcon( newPI );
+ printlnState("[set pointer-icon post]", currentPI+" -> "+glWindow.getPointerIcon());
+ }
+ } } );
+ break;
+ case KeyEvent.VK_D:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set undecorated pre]");
+ glWindow.setUndecorated(!glWindow.isUndecorated());
+ printlnState("[set undecorated post]");
+ } } );
+ break;
+ case KeyEvent.VK_F:
+ e.setConsumed(true);
+ quitAdapterOff();
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set fullscreen pre]");
+ if( glWindow.isFullscreen() ) {
+ glWindow.setFullscreen( false );
+ } else {
+ if( e.isAltDown() ) {
+ glWindow.setFullscreen( null );
+ } else {
+ glWindow.setFullscreen( true );
+ }
+ }
+ printlnState("[set fullscreen post]");
+ quitAdapterOn();
+ } } );
+ break;
+ case KeyEvent.VK_G:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ final float newGamma = gamma + ( e.isShiftDown() ? -0.1f : 0.1f );
+ System.err.println("[set gamma]: "+gamma+" -> "+newGamma);
+ if( Gamma.setDisplayGamma(glWindow, newGamma, brightness, contrast) ) {
+ gamma = newGamma;
+ }
+ } } );
+ break;
+ case KeyEvent.VK_I:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set pointer-visible pre]");
+ glWindow.setPointerVisible(!glWindow.isPointerVisible());
+ printlnState("[set pointer-visible post]");
+ } } );
+ break;
+ case KeyEvent.VK_J:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set pointer-confined pre]", "warp-center: "+e.isShiftDown());
+ final boolean confine = !glWindow.isPointerConfined();
+ glWindow.confinePointer(confine);
+ printlnState("[set pointer-confined post]", "warp-center: "+e.isShiftDown());
+ if( e.isShiftDown() ) {
+ setConfinedFixedCenter(confine);
+ } else if( !confine ) {
+ setConfinedFixedCenter(false);
+ }
+ } } );
+ break;
+ case KeyEvent.VK_M:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ // none: max-v
+ // alt: max-h
+ // shift: max-hv
+ // ctrl: max-off
+ final boolean horz, vert;
+ if( e.isControlDown() ) {
+ horz = false;
+ vert = false;
+ } else if( e.isShiftDown() ) {
+ final boolean bothMax = glWindow.isMaximizedHorz() && glWindow.isMaximizedVert();
+ horz = !bothMax;
+ vert = !bothMax;
+ } else if( !e.isAltDown() ) {
+ horz = glWindow.isMaximizedHorz();
+ vert = !glWindow.isMaximizedVert();
+ } else if( e.isAltDown() ) {
+ horz = !glWindow.isMaximizedHorz();
+ vert = glWindow.isMaximizedVert();
+ } else {
+ vert = glWindow.isMaximizedVert();
+ horz = glWindow.isMaximizedHorz();
+ }
+ printlnState("[set maximize pre]", "max[vert "+vert+", horz "+horz+"]");
+ glWindow.setMaximized(horz, vert);
+ printlnState("[set maximize post]", "max[vert "+vert+", horz "+horz+"]");
+ } } );
+ break;
+ case KeyEvent.VK_Q:
+ if( quitAdapterEnabled && 0 == e.getModifiers() ) {
+ System.err.println("QUIT Key "+Thread.currentThread());
+ quitAdapterShouldQuit = true;
+ }
+ break;
+ case KeyEvent.VK_P:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set position pre]");
+ glWindow.setPosition(100, 100);
+ printlnState("[set position post]");
+ } } );
+ break;
+ case KeyEvent.VK_R:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set resizable pre]");
+ glWindow.setResizable(!glWindow.isResizable());
+ printlnState("[set resizable post]");
+ } } );
+ break;
+ case KeyEvent.VK_S:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set sticky pre]");
+ glWindow.setSticky(!glWindow.isSticky());
+ printlnState("[set sticky post]");
+ } } );
+ break;
+ case KeyEvent.VK_V:
+ e.setConsumed(true);
+ if( e.isControlDown() ) {
+ glWindow.invoke(false, new GLRunnable() {
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
+ final int _i = gl.getSwapInterval();
+ final int i;
+ switch(_i) {
+ case 0: i = -1; break;
+ case -1: i = 1; break;
+ case 1: i = 0; break;
+ default: i = 1; break;
+ }
+ gl.setSwapInterval(i);
+
+ final GLAnimatorControl a = drawable.getAnimator();
+ if( null != a ) {
+ a.resetFPSCounter();
+ }
+ if(drawable instanceof FPSCounter) {
+ ((FPSCounter)drawable).resetFPSCounter();
+ }
+ System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval());
+ return true;
+ }
+ });
+ } else {
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ final boolean wasVisible = glWindow.isVisible();
+ {
+ printlnState("[set visible pre]");
+ glWindow.setVisible(!wasVisible);
+ printlnState("[set visible post]");
+ }
+ if( wasVisible && !e.isControlDown() ) {
+ try {
+ java.lang.Thread.sleep(5000);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ printlnState("[reset visible pre]");
+ glWindow.setVisible(true);
+ printlnState("[reset visible post]");
+ }
+ } } );
+ }
+ break;
+ case KeyEvent.VK_W:
+ e.setConsumed(true);
+ glWindow.invokeOnNewThread(null, false, new Runnable() {
+ public void run() {
+ printlnState("[set pointer-pos pre]");
+ glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2);
+ printlnState("[set pointer-pos post]");
+ } } );
+ break;
+ case KeyEvent.VK_X:
+ e.setConsumed(true);
+ final float[] hadSurfacePixelScale = glWindow.getCurrentSurfaceScale(new float[2]);
+ final float[] reqSurfacePixelScale;
+ if( hadSurfacePixelScale[0] == ScalableSurface.IDENTITY_PIXELSCALE ) {
+ reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+ } else {
+ reqSurfacePixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ }
+ System.err.println("[set PixelScale pre]: had "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" -> req "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]);
+ glWindow.setSurfaceScale(reqSurfacePixelScale);
+ final float[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new float[2]);
+ final float[] hasSurfacePixelScale1 = glWindow.getCurrentSurfaceScale(new float[2]);
+ System.err.println("[set PixelScale post]: "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" (had) -> "+
+ reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+
+ valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+
+ hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)");
+ setTitle();
+ }
+ }
+ @Override
+ public void keyReleased(final KeyEvent e) { }
+
+ public void setConfinedFixedCenter(final boolean v) {
+ confinedFixedCenter = v;
+ }
+ @Override
+ public void mouseMoved(final MouseEvent e) {
+ if( e.isConfined() ) {
+ mouseCenterWarp(e);
+ }
+ }
+ @Override
+ public void mouseDragged(final MouseEvent e) {
+ if( e.isConfined() ) {
+ mouseCenterWarp(e);
+ }
+ }
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ if(e.getClickCount() == 2 && e.getPointerCount() == 1) {
+ glWindow.setFullscreen(!glWindow.isFullscreen());
+ System.err.println("setFullscreen: "+glWindow.isFullscreen());
+ }
+ }
+ private void mouseCenterWarp(final MouseEvent e) {
+ if(e.isConfined() && confinedFixedCenter ) {
+ final int x=glWindow.getSurfaceWidth()/2;
+ final int y=glWindow.getSurfaceHeight()/2;
+ glWindow.warpPointer(x, y);
+ }
+ }
+ @Override
+ public void mouseEntered(final MouseEvent e) {}
+ @Override
+ public void mouseExited(final MouseEvent e) {}
+ @Override
+ public void mousePressed(final MouseEvent e) {}
+ @Override
+ public void mouseReleased(final MouseEvent e) {}
+ @Override
+ public void mouseWheelMoved(final MouseEvent e) {}
+
+ /////////////////////////////////////////////////////////////
+
+ private boolean quitAdapterShouldQuit = false;
+ private boolean quitAdapterEnabled = false;
+ private boolean quitAdapterEnabled2 = true;
+
+ protected void quitAdapterOff() {
+ quitAdapterEnabled2 = false;
+ }
+ protected void quitAdapterOn() {
+ clearQuitAdapter();
+ quitAdapterEnabled2 = true;
+ }
+ public void quitAdapterEnable(final boolean v) { quitAdapterEnabled = v; }
+ public void clearQuitAdapter() { quitAdapterShouldQuit = false; }
+ public boolean shouldQuit() { return quitAdapterShouldQuit; }
+ public void doQuit() { quitAdapterShouldQuit=true; }
+
+ public void windowDestroyNotify(final WindowEvent e) {
+ if( quitAdapterEnabled && quitAdapterEnabled2 ) {
+ System.err.println("QUIT Window "+Thread.currentThread());
+ quitAdapterShouldQuit = true;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////
+
+ public void setTitle() {
+ setTitle(glWindow);
+ }
+ public static void setTitle(final GLWindow win) {
+ final CapabilitiesImmutable chosenCaps = win.getChosenCapabilities();
+ final CapabilitiesImmutable reqCaps = win.getRequestedCapabilities();
+ final CapabilitiesImmutable caps = null != chosenCaps ? chosenCaps : reqCaps;
+ final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl";
+ final float[] sDPI = win.getPixelsPerMM(new float[2]);
+ sDPI[0] *= 25.4f;
+ sDPI[1] *= 25.4f;
+ win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]);
+ }
+
+ public static PointerIcon[] createPointerIcons(final GLWindow glWindow) {
+ final PointerIcon[] pointerIcons = { null, null, null, null, null };
+ {
+ final Display disp = glWindow.getScreen().getDisplay();
+ disp.createNative();
+ int idx = 0;
+ {
+ PointerIcon _pointerIcon = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } );
+ try {
+ _pointerIcon = disp.createPointerIcon(res, 8, 8);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ pointerIcons[idx] = _pointerIcon;
+ }
+ idx++;
+ {
+ PointerIcon _pointerIcon = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } );
+ try {
+ _pointerIcon = disp.createPointerIcon(res, 0, 0);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ pointerIcons[idx] = _pointerIcon;
+ }
+ idx++;
+ {
+ PointerIcon _pointerIcon = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-red-alpha-64x64.png" } );
+ try {
+ _pointerIcon = disp.createPointerIcon(res, 0, 0);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ pointerIcons[idx] = _pointerIcon;
+ }
+ idx++;
+ {
+ PointerIcon _pointerIcon = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-blue-alpha-64x64.png" } );
+ try {
+ _pointerIcon = disp.createPointerIcon(res, 0, 0);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ pointerIcons[idx] = _pointerIcon;
+ }
+ idx++;
+ if( PNGIcon.isAvailable() ) {
+ PointerIcon _pointerIcon = null;
+ final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } );
+ try {
+ final URLConnection urlConn = res.resolve(0);
+ final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, image.toString());
+ _pointerIcon = disp.createPointerIcon(image, 32, 0);
+ System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ pointerIcons[idx] = _pointerIcon;
+ }
+ idx++;
+ }
+ return pointerIcons;
+ }
+} \ No newline at end of file
diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java
index 8bf4bc20f..05df63794 100644
--- a/src/newt/classes/com/jogamp/newt/util/MainThread.java
+++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java
@@ -45,6 +45,7 @@ import java.util.List;
import com.jogamp.nativewindow.NativeWindowFactory;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.ReflectionUtil;
@@ -171,15 +172,14 @@ public class MainThread {
return res;
}
- static class UserApp extends Thread {
+ static class UserApp extends InterruptSource.Thread {
private final String mainClassNameShort;
private final String mainClassName;
private final String[] mainClassArgs;
private final Method mainClassMain;
- private List<Thread> nonDaemonThreadsAtStart;
+ private List<java.lang.Thread> nonDaemonThreadsAtStart;
public UserApp(final String mainClassName, final String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
- super();
this.mainClassName=mainClassName;
this.mainClassArgs=mainClassArgs;
@@ -200,10 +200,10 @@ public class MainThread {
@Override
public void run() {
nonDaemonThreadsAtStart = getNonDaemonThreads();
- if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart);
+ if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart);
// start user app ..
try {
- if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName);
+ if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" invoke "+mainClassName);
mainClassMain.invoke(null, new Object[] { mainClassArgs } );
} catch (final InvocationTargetException ite) {
ite.getTargetException().printStackTrace();
@@ -219,30 +219,30 @@ public class MainThread {
while( 0 < ( ndtr = getNonDaemonThreadCount(nonDaemonThreadsAtStart) ) ) {
if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr);
try {
- Thread.sleep(1000);
+ java.lang.Thread.sleep(1000);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
- if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin: "+ndtr);
+ if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" user app fin: "+ndtr);
}
if ( useMainThread ) {
if(isMacOSX) {
try {
if(DEBUG) {
- System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0");
+ System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.0");
}
ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication",
null, null, MainThread.class.getClassLoader());
if(DEBUG) {
- System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X");
+ System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.X");
}
} catch (final Exception e) {
e.printStackTrace();
}
} else {
- if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)");
+ if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" MainAction fin - System.exit(0)");
System.exit(0);
}
}
diff --git a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
index c2cf64da2..e02e02013 100644
--- a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
+++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
@@ -33,7 +33,6 @@ import java.security.PrivilegedAction;
import com.jogamp.nativewindow.NativeWindow;
import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode;
-import com.jogamp.nativewindow.util.InsetsImmutable;
import com.jogamp.opengl.FPSCounter;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GLAutoDrawable;
@@ -43,16 +42,17 @@ import com.jogamp.opengl.GLPipelineFactory;
import jogamp.newt.Debug;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.newt.Display;
import com.jogamp.newt.Window;
import com.jogamp.newt.Display.PointerIcon;
-import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.newt.opengl.util.NEWTDemoListener;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.AnimatorBase;
@@ -60,7 +60,7 @@ import com.jogamp.opengl.util.AnimatorBase;
/** Shows how to deploy an applet using JOGL. This demo must be
referenced from a web page via an &lt;applet&gt; tag. */
-public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
+public class JOGLNewtAppletBase implements GLEventListener {
public static final boolean DEBUG = Debug.debug("Applet");
String glEventListenerClazzName;
@@ -194,7 +194,9 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
}
if(!noDefaultKeyListener) {
- glWindow.addKeyListener(this);
+ final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow);
+ glWindow.addKeyListener(newtDemoListener);
+ glWindow.addMouseListener(newtDemoListener);
}
glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err);
@@ -220,7 +222,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
null == glWindow.getParent() && null != parentWin && 0 != parentWin.getWindowHandle() )
{
// we may be called directly by the native EDT
- new Thread(new Runnable() {
+ new InterruptSource.Thread(null, new Runnable() {
@Override
public void run() {
if( glWindow.isNativeValid() && null != parentWin && 0 != parentWin.getWindowHandle() ) {
@@ -303,86 +305,5 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
public void dispose(final GLAutoDrawable drawable) {
}
- // ***********************************************************************************
- // ***********************************************************************************
- // ***********************************************************************************
-
- @Override
- public void keyPressed(final KeyEvent e) {
- if( !e.isPrintableKey() || e.isAutoRepeat() ) {
- return;
- }
- if(e.getKeyChar()=='d') {
- new Thread() {
- public void run() {
- glWindow.setUndecorated(!glWindow.isUndecorated());
- } }.start();
- } if(e.getKeyChar()=='f') {
- new Thread() {
- public void run() {
- glWindow.setFullscreen(!glWindow.isFullscreen());
- } }.start();
- } else if(e.getKeyChar()=='a') {
- new Thread() {
- public void run() {
- glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
- } }.start();
- } else if(e.getKeyChar()=='r' && null!=parentWin) {
- new Thread() {
- public void run() {
- if(null == glWindow.getParent()) {
- glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */);
- } else {
- final InsetsImmutable insets = glWindow.getInsets();
- final int x, y;
- if ( 0 >= insets.getTopHeight() ) {
- // fail safe ..
- x = 32;
- y = 32;
- } else {
- x = insets.getLeftWidth();
- y = insets.getTopHeight();
- }
- glWindow.reparentWindow(null, x, y, 0 /* hints */);
- glWindow.setDefaultCloseOperation( glClosable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE );
- }
- } }.start();
- } else if(e.getKeyChar()=='c') {
- new Thread() {
- public void run() {
- System.err.println("[set pointer-icon pre]");
- final PointerIcon currentPI = glWindow.getPointerIcon();
- glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest);
- System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon());
- } }.start();
- } else if(e.getKeyChar()=='i') {
- new Thread() {
- public void run() {
- System.err.println("[set mouse visible pre]: "+glWindow.isPointerVisible());
- glWindow.setPointerVisible(!glWindow.isPointerVisible());
- System.err.println("[set mouse visible post]: "+glWindow.isPointerVisible());
- } }.start();
- } else if(e.getKeyChar()=='j') {
- new Thread() {
- public void run() {
- final Thread t = glWindow.setExclusiveContextThread(null);
- System.err.println("[set mouse confined pre]: "+glWindow.isPointerConfined());
- glWindow.confinePointer(!glWindow.isPointerConfined());
- System.err.println("[set mouse confined post]: "+glWindow.isPointerConfined());
- glWindow.setExclusiveContextThread(t);
- } }.start();
- } else if(e.getKeyChar()=='w') {
- new Thread() {
- public void run() {
- System.err.println("[set mouse pos pre]");
- glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2);
- System.err.println("[set mouse pos post]");
- } }.start();
- }
- }
-
- @Override
- public void keyReleased(final KeyEvent e) {
- }
}
diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
index bf46ce609..ff713410b 100644
--- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
@@ -44,6 +44,8 @@ import com.jogamp.nativewindow.NativeWindowException;
import jogamp.common.util.locks.LockDebugUtil;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.RunnableTask;
import com.jogamp.common.util.locks.Lock;
import com.jogamp.newt.util.EDTUtil;
@@ -68,7 +70,7 @@ public class DefaultEDTUtil implements EDTUtil {
this.threadGroup = tg;
this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
this.dispatchMessages=dispatchMessages;
- this.edt = new NEDT(threadGroup, name);
+ this.edt = new NEDT(threadGroup, this.name);
this.edt.setDaemon(true); // don't stop JVM from shutdown ..
}
@@ -169,8 +171,7 @@ public class DefaultEDTUtil implements EDTUtil {
};
private final boolean invokeImpl(boolean wait, Runnable task, final boolean stop, final boolean provokeError) {
- Throwable throwable = null;
- RunnableTask rTask = null;
+ final RunnableTask rTask;
final Object rTaskLock = new Object();
synchronized(rTaskLock) { // lock the optional task execution
synchronized(edtLock) { // lock the EDT status
@@ -187,6 +188,7 @@ public class DefaultEDTUtil implements EDTUtil {
task.run();
}
wait = false; // running in same thread (EDT) -> no wait
+ rTask = null;
if( stop ) {
edt.shouldStop = true;
if( edt.tasks.size()>0 ) {
@@ -230,18 +232,19 @@ public class DefaultEDTUtil implements EDTUtil {
}
} else {
wait = false;
+ rTask = null;
}
}
}
if( wait ) {
try {
- rTaskLock.wait(); // free lock, allow execution of rTask
+ while( rTask.isInQueue() ) {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ }
} catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rTask.getThrowable();
+ throw new InterruptedRuntimeException(ie);
}
+ final Throwable throwable = rTask.getThrowable();
if(null!=throwable) {
if(throwable instanceof NativeWindowException) {
throw (NativeWindowException)throwable;
@@ -268,13 +271,13 @@ public class DefaultEDTUtil implements EDTUtil {
return false;
}
synchronized(_edt.tasks) {
- while(_edt.isRunning && _edt.tasks.size()>0) {
- try {
+ try {
+ while(_edt.isRunning && _edt.tasks.size()>0) {
_edt.tasks.notifyAll();
_edt.tasks.wait();
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
return true;
}
@@ -284,12 +287,12 @@ public class DefaultEDTUtil implements EDTUtil {
final public boolean waitUntilStopped() {
synchronized(edtLock) {
if(edt.isRunning && edt != Thread.currentThread() ) {
- while( edt.isRunning ) {
- try {
+ try {
+ while( edt.isRunning ) {
edtLock.wait();
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
return true;
} else {
@@ -298,13 +301,13 @@ public class DefaultEDTUtil implements EDTUtil {
}
}
- class NEDT extends Thread {
+ class NEDT extends InterruptSource.Thread {
volatile boolean shouldStop = false;
volatile boolean isRunning = false;
final ArrayList<RunnableTask> tasks = new ArrayList<RunnableTask>(); // one shot tasks
public NEDT(final ThreadGroup tg, final String name) {
- super(tg, name);
+ super(tg, null, name);
}
final public boolean isRunning() {
@@ -347,11 +350,11 @@ public class DefaultEDTUtil implements EDTUtil {
RunnableTask task = null;
synchronized(tasks) {
// wait for tasks
- if(!shouldStop && tasks.size()==0) {
+ if( !shouldStop && tasks.size()==0 ) {
try {
tasks.wait(pollPeriod);
} catch (final InterruptedException e) {
- e.printStackTrace();
+ throw new InterruptedRuntimeException(e);
}
}
// execute one task, if available
@@ -375,7 +378,7 @@ public class DefaultEDTUtil implements EDTUtil {
}
if(!task.hasWaiter() && null != task.getThrowable()) {
// at least dump stack-trace in case nobody waits for result
- System.err.println("DefaultEDT.run(): Caught exception occured on thread "+Thread.currentThread().getName()+": "+task.toString());
+ System.err.println("DefaultEDT.run(): Caught exception occured on thread "+java.lang.Thread.currentThread().getName()+": "+task.toString());
task.getThrowable().printStackTrace();
}
}
diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java
index cc1f3d8e0..c1cd6db32 100644
--- a/src/newt/classes/jogamp/newt/DisplayImpl.java
+++ b/src/newt/classes/jogamp/newt/DisplayImpl.java
@@ -37,6 +37,7 @@ package jogamp.newt;
import com.jogamp.common.ExceptionUtils;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.newt.Display;
import com.jogamp.newt.NewtFactory;
@@ -697,8 +698,9 @@ public abstract class DisplayImpl extends Display {
} else {
throw re;
}
+ } finally {
+ eventTask.notifyCaller();
}
- eventTask.notifyCaller();
}
@Override
@@ -725,7 +727,10 @@ public abstract class DisplayImpl extends Display {
}
if( null != _events ) {
for (int i=0; i < _events.size(); i++) {
- dispatchMessage(_events.get(i));
+ final NEWTEventTask e = _events.get(i);
+ if( !e.isDispatched() ) {
+ dispatchMessage(e);
+ }
}
}
}
@@ -759,11 +764,12 @@ public abstract class DisplayImpl extends Display {
haveEvents = true;
eventsLock.notifyAll();
}
- if( wait ) {
+ while( wait && !eTask.isDispatched() ) {
try {
lock.wait();
} catch (final InterruptedException ie) {
- throw new RuntimeException(ie);
+ eTask.setDispatched(); // Cancels NEWTEvent ..
+ throw new InterruptedRuntimeException(ie);
}
if( null != eTask.getException() ) {
throw eTask.getException();
diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
index 9d3121635..3d9073769 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
@@ -33,6 +33,8 @@ import java.awt.EventQueue;
import com.jogamp.nativewindow.NativeWindowException;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.RunnableTask;
import com.jogamp.common.util.awt.AWTEDTExecutor;
import com.jogamp.newt.util.EDTUtil;
@@ -54,7 +56,7 @@ public class AWTEDTUtil implements EDTUtil {
this.threadGroup = tg;
this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
this.dispatchMessages=dispatchMessages;
- this.nedt = new NEDT(threadGroup, name);
+ this.nedt = new NEDT(threadGroup, this.name);
this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
}
@@ -132,8 +134,7 @@ public class AWTEDTUtil implements EDTUtil {
}
private final boolean invokeImpl(boolean wait, final Runnable task, final boolean stop) {
- Throwable throwable = null;
- RunnableTask rTask = null;
+ final RunnableTask rTask;
final Object rTaskLock = new Object();
synchronized(rTaskLock) { // lock the optional task execution
synchronized(edtLock) { // lock the EDT status
@@ -150,6 +151,7 @@ public class AWTEDTUtil implements EDTUtil {
task.run();
}
wait = false; // running in same thread (EDT) -> no wait
+ rTask = null;
if(stop) {
nedt.shouldStop = true;
}
@@ -182,18 +184,21 @@ public class AWTEDTUtil implements EDTUtil {
true /* always catch and report Exceptions, don't disturb EDT */,
wait ? null : System.err);
AWTEDTExecutor.singleton.invoke(false, rTask);
+ } else {
+ wait = false;
+ rTask = null;
}
}
}
if( wait ) {
try {
- rTaskLock.wait(); // free lock, allow execution of rTask
+ while( rTask.isInQueue() ) {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ }
} catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rTask.getThrowable();
+ throw new InterruptedRuntimeException(ie);
}
+ final Throwable throwable = rTask.getThrowable();
if(null!=throwable) {
if(throwable instanceof NativeWindowException) {
throw (NativeWindowException)throwable;
@@ -227,12 +232,12 @@ public class AWTEDTUtil implements EDTUtil {
final public boolean waitUntilStopped() {
synchronized(edtLock) {
if( nedt.isRunning && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) {
- while( nedt.isRunning ) {
- try {
+ try {
+ while( nedt.isRunning ) {
edtLock.wait();
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
return true;
} else {
@@ -241,13 +246,13 @@ public class AWTEDTUtil implements EDTUtil {
}
}
- class NEDT extends Thread {
+ class NEDT extends InterruptSource.Thread {
volatile boolean shouldStop = false;
volatile boolean isRunning = false;
Object sync = new Object();
public NEDT(final ThreadGroup tg, final String name) {
- super(tg, name);
+ super(tg, null, name);
}
final public boolean isRunning() {
@@ -286,7 +291,7 @@ public class AWTEDTUtil implements EDTUtil {
try {
sync.wait(pollPeriod);
} catch (final InterruptedException e) {
- e.printStackTrace();
+ throw new InterruptedRuntimeException(e);
}
}
}
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
index bc0bfaa16..c3b7bff36 100644
--- a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
@@ -43,6 +43,7 @@ import jogamp.newt.WindowImpl;
import jogamp.newt.driver.KeyTracker;
import com.jogamp.common.nio.StructAccessor;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.newt.Window;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.WindowEvent;
@@ -63,7 +64,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker {
static {
ledt = new LinuxEventDeviceTracker();
- final Thread t = new Thread(ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager");
+ final Thread t = new InterruptSource.Thread(null, ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager");
t.setDaemon(true);
t.start();
}
@@ -153,7 +154,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker {
if(number<32&&number>=0) {
if(eventDevicePollers[number]==null){
eventDevicePollers[number] = new EventDevicePoller(number);
- final Thread t = new Thread(eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number);
+ final Thread t = new InterruptSource.Thread(null, eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number);
t.setDaemon(true);
t.start();
} else if(eventDevicePollers[number].stop) {
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
index f40728da0..53bb9c3a5 100644
--- a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
@@ -37,6 +37,7 @@ import java.io.InputStream;
import jogamp.newt.WindowImpl;
import jogamp.newt.driver.MouseTracker;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.newt.Screen;
import com.jogamp.newt.Window;
import com.jogamp.newt.event.MouseEvent;
@@ -55,7 +56,7 @@ public class LinuxMouseTracker implements WindowListener, MouseTracker {
static {
lmt = new LinuxMouseTracker();
- final Thread t = new Thread(lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker");
+ final Thread t = new InterruptSource.Thread(null, lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker");
t.setDaemon(true);
t.start();
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index a38ba4c13..2bbcdce38 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -34,6 +34,7 @@
package jogamp.newt.driver.macosx;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
import com.jogamp.nativewindow.GraphicsConfigurationFactory;
import com.jogamp.nativewindow.NativeWindow;
@@ -378,7 +379,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
}
private void superSizeChangedOffThread(final boolean defer, final int newWidth, final int newHeight, final boolean force) {
if( defer ) {
- new Thread() {
+ new InterruptSource.Thread() {
public void run() {
WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force);
} }.start();
diff --git a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
index 2bdab2796..260a1beb4 100644
--- a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
+++ b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
@@ -38,19 +38,27 @@ public class NEWTEventTask {
private final NEWTEvent event;
private final Object notifyObject;
private RuntimeException exception;
+ private volatile boolean dispatched;
public NEWTEventTask(final NEWTEvent event, final Object notifyObject) {
this.event = event ;
this.notifyObject = notifyObject ;
this.exception = null;
+ this.dispatched = false;
}
public final NEWTEvent get() { return event; }
public final void setException(final RuntimeException e) { exception = e; }
public final RuntimeException getException() { return exception; }
public final boolean isCallerWaiting() { return null != notifyObject; }
+ public final boolean isDispatched() { return dispatched; }
+ public final void setDispatched() { dispatched = true; }
+ /**
+ * Notifies caller after {@link #setDispatched()}.
+ */
public void notifyCaller() {
+ setDispatched();
if(null != notifyObject) {
synchronized (notifyObject) {
notifyObject.notifyAll();
diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
index 9039b6083..9d2b41bbc 100644
--- a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
@@ -32,6 +32,8 @@ import com.jogamp.nativewindow.NativeWindowException;
import jogamp.newt.Debug;
import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
import com.jogamp.common.util.RunnableTask;
import com.jogamp.newt.util.EDTUtil;
@@ -162,8 +164,7 @@ public class SWTEDTUtil implements EDTUtil {
}
private final boolean invokeImpl(boolean wait, final Runnable task, boolean stop) {
- Throwable throwable = null;
- RunnableTask rTask = null;
+ final RunnableTask rTask;
final Object rTaskLock = new Object();
synchronized(rTaskLock) { // lock the optional task execution
synchronized(edtLock) { // lock the EDT status
@@ -184,6 +185,7 @@ public class SWTEDTUtil implements EDTUtil {
task.run();
}
wait = false; // running in same thread (EDT) -> no wait
+ rTask = null;
if( stop ) {
nedt.shouldStop = true;
}
@@ -225,18 +227,21 @@ public class SWTEDTUtil implements EDTUtil {
true /* always catch and report Exceptions, don't disturb EDT */,
wait ? null : System.err);
swtDisplay.asyncExec(rTask);
+ } else {
+ wait = false;
+ rTask = null;
}
}
}
if( wait ) {
try {
- rTaskLock.wait(); // free lock, allow execution of rTask
+ while( rTask.isInQueue() ) {
+ rTaskLock.wait(); // free lock, allow execution of rTask
+ }
} catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rTask.getThrowable();
+ throw new InterruptedRuntimeException(ie);
}
+ final Throwable throwable = rTask.getThrowable();
if(null!=throwable) {
if(throwable instanceof NativeWindowException) {
throw (NativeWindowException)throwable;
@@ -274,12 +279,12 @@ public class SWTEDTUtil implements EDTUtil {
final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null;
final boolean onSWTEDT = swtT == curT;
if( nedt.isRunning && nedt != curT && !onSWTEDT ) {
- while( nedt.isRunning ) {
- try {
+ try {
+ while( nedt.isRunning ) {
edtLock.wait();
- } catch (final InterruptedException e) {
- e.printStackTrace();
}
+ } catch (final InterruptedException e) {
+ throw new InterruptedRuntimeException(e);
}
return true;
} else {
@@ -288,13 +293,13 @@ public class SWTEDTUtil implements EDTUtil {
}
}
- class NEDT extends Thread {
+ class NEDT extends InterruptSource.Thread {
volatile boolean shouldStop = false;
volatile boolean isRunning = false;
Object sync = new Object();
public NEDT(final ThreadGroup tg, final String name) {
- super(tg, name);
+ super(tg, null, name);
}
final public boolean isRunning() {
@@ -337,7 +342,7 @@ public class SWTEDTUtil implements EDTUtil {
try {
sync.wait(pollPeriod);
} catch (final InterruptedException e) {
- e.printStackTrace();
+ throw new InterruptedRuntimeException(e);
}
}
}