aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2010-11-21 03:41:22 +0100
committerSven Gothel <[email protected]>2010-11-21 03:41:22 +0100
commit2aa296771e3e8dd6cf027f27b0455d1803244bfe (patch)
tree514c532f9ddff7f84e9e6fb75e883f04c71ec74f
parent6f73de7c5bb85d0175c8dda7c55317923017bbe0 (diff)
JOGL/NEWT: Animator fixes
Consider use cases with many drawables and no drawables at start, this had to be reflected all over this patch set, implementation, usage and test cases. - GLAnimatorControl - refine API doc / states - add 'void remove(GLAutoDrawable drawable);' - Animator*: - using RecursiveLock 'stateSync' for all actions out of the big synchronized (animator) block: - get status methods (thread, isPaused, ..), hence no more synchronized - display drawables change, utilizing synced ArrayList swap This removes the need for volatiles usage shouldPause/shouldStop within the display method. - added blocking wait for state change for add(GLAutoDrawable)/remove(GLAutoDrawable) method - remove flawed double checked locking in anim thread (pause/idle condition) - thread is now a daemon thread, hence it won't hinder the JVM from shutdown - - Animator use change: - Always resume after pause, except in case of final destroy -> NEWT invalidate / GLCanvas, this considers use cases with many drawables and no drawables at start. - GLDrawableHelper: Don't pause at implicit dispose()
-rw-r--r--make/scripts/tests.sh10
-rw-r--r--src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java10
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java55
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Animator.java226
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java95
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java33
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java84
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAnimatorControl.java22
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java1
-rw-r--r--src/jogl/classes/javax/media/opengl/GLCapabilities.java2
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java15
-rw-r--r--src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java33
-rw-r--r--src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java111
-rw-r--r--src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java12
-rw-r--r--src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java2
-rw-r--r--src/newt/classes/com/jogamp/newt/Window.java3
-rw-r--r--src/newt/classes/com/jogamp/newt/impl/WindowImpl.java86
-rw-r--r--src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java2
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java44
19 files changed, 502 insertions, 344 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 1aa725c94..8304b99b6 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -24,7 +24,7 @@ function jrun() {
#D_ARGS="-Djogl.debug.GLContext -Djogl.debug.ExtensionAvailabilityCache"
#D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile -Djogl.debug.GLDrawable"
#D_ARGS="-Djogl.debug.GLProfile"
- # D_ARGS="-Djogamp.debug.TraceLock"
+ D_ARGS="-Dnewt.debug.Window -Djogamp.common.utils.locks.Lock.timeout=600000 -Djogl.debug.Animator"
# D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.NativeWindow"
#D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT"
# D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.X11Util.TraceDisplayLifecycle=true"
@@ -61,7 +61,7 @@ function testawt() {
#testawt com.jogamp.test.junit.jogl.demos.gl2.gears.newt.TestGearsNEWT
#testawt com.jogamp.test.junit.newt.TestDisplayLifecycle01NEWT
#testawt com.jogamp.test.junit.newt.TestDisplayLifecycle02NEWT
-#testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT
+testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT
#testawt com.jogamp.test.junit.newt.parenting.TestParenting02NEWT
#testawt com.jogamp.test.junit.newt.TestScreenMode00NEWT
#testnoawt com.jogamp.test.junit.newt.TestScreenMode01NEWT
@@ -98,9 +98,13 @@ function testawt() {
#testawt com.jogamp.test.junit.newt.parenting.TestParenting03AWT -time 100000
#testawt com.jogamp.test.junit.newt.parenting.TestParenting03bAWT -time 100000
#testawt com.jogamp.test.junit.newt.TestCloseNewtAWT
-testawt com.jogamp.test.junit.jogl.caps.TestMultisampleAWT $*
+#testawt com.jogamp.test.junit.jogl.caps.TestMultisampleAWT $*
#testawt com.jogamp.test.junit.jogl.caps.TestMultisampleNEWT $*
+#testawt com.jogamp.test.junit.newt.TestGLWindows02NEWTAnimated $*
+#testawt com.jogamp.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $*
+#testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT $*
+
#testawt $*
$spath/count-edt-start.sh java-run.log
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
index 5b1858c41..45b04fac1 100644
--- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
+++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
@@ -238,6 +238,10 @@ public class GLDrawableHelper {
}
}
+ public final boolean isExternalAnimatorRunning() {
+ return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
+ }
+
public final boolean isExternalAnimatorAnimating() {
return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
}
@@ -298,8 +302,6 @@ public class GLDrawableHelper {
* <br>
* Remark: In case this method is called to dispose the GLDrawable/GLAutoDrawable,
* <code>initAction</code> shall be <code>null</code> to mark this cause.<br>
- * In this case, the locally delegated {@link javax.media.opengl.GLAnimatorControl} via {@link #setAnimator(javax.media.opengl.GLAnimatorControl) setAnimator(animatorControl)}
- * is paused first, if {@link javax.media.opengl.GLAnimatorControl#isAnimating()}.
*
* @param drawable
* @param context
@@ -323,10 +325,6 @@ public class GLDrawableHelper {
if(!context.isCreated()) {
throw new GLException("Dispose case (no init action given): Native context must be created: "+context);
}
- GLAnimatorControl animCtrl = getAnimator();
- if(null!=animCtrl && animCtrl.isAnimating()) {
- animCtrl.pause();
- }
}
// Support for recursive makeCurrent() calls as well as calling
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
index fbad377ad..2240063d9 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
@@ -36,10 +36,16 @@ package com.jogamp.opengl.util;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Rectangle;
-import java.util.*;
-import javax.swing.*;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.swing.JComponent;
+import javax.swing.RepaintManager;
+import javax.swing.SwingUtilities;
-import javax.media.opengl.*;
+import javax.media.opengl.GLAutoDrawable;
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
@@ -52,37 +58,34 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
private Map repaintManagers = new IdentityHashMap();
private Map dirtyRegions = new IdentityHashMap();
- public void display(AnimatorBase animator,
+ public void display(ArrayList drawables,
boolean ignoreExceptions,
boolean printExceptions) {
- List drawables = animator.acquireDrawables();
- try {
- for (int i=0;
- animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size();
- i++) {
- GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
- if (drawable instanceof JComponent) {
- // Lightweight components need a more efficient drawing
- // scheme than simply forcing repainting of each one in
- // turn since drawing one can force another one to be
- // drawn in turn
+ for (int i=0; i<drawables.size(); i++) {
+ GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
+ if (drawable instanceof JComponent) {
+ // Lightweight components need a more efficient drawing
+ // scheme than simply forcing repainting of each one in
+ // turn since drawing one can force another one to be
+ // drawn in turn
+ if(drawable.isRealized()) {
lightweights.add(drawable);
- } else {
- try {
+ }
+ } else {
+ try {
+ if(drawable.isRealized()) {
drawable.display();
- } catch (RuntimeException e) {
- if (ignoreExceptions) {
- if (printExceptions) {
- e.printStackTrace();
- }
- } else {
- throw(e);
+ }
+ } catch (RuntimeException e) {
+ if (ignoreExceptions) {
+ if (printExceptions) {
+ e.printStackTrace();
}
+ } else {
+ throw(e);
}
}
}
- } finally {
- animator.releaseDrawables();
}
if (lightweights.size() > 0) {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 4f24b22a7..2d4727bba 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -44,8 +44,6 @@ import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLException;
-
-
/** <P> An Animator can be attached to one or more {@link
GLAutoDrawable}s to drive their display() methods in a loop. </P>
@@ -61,9 +59,8 @@ public class Animator extends AnimatorBase {
private Runnable runnable;
private boolean runAsFastAsPossible;
protected boolean isAnimating;
- protected boolean isPaused;
- protected volatile boolean shouldPause;
- protected volatile boolean shouldStop;
+ protected boolean pauseIssued;
+ protected volatile boolean stopIssued;
public Animator() {
super();
@@ -104,62 +101,78 @@ public class Animator extends AnimatorBase {
* This method may not have an effect on subclasses.
*/
public final void setRunAsFastAsPossible(boolean runFast) {
- runAsFastAsPossible = runFast;
+ stateSync.lock();
+ try {
+ runAsFastAsPossible = runFast;
+ } finally {
+ stateSync.unlock();
+ }
+ }
+
+ private void setIsAnimatingSynced(boolean v) {
+ stateSync.lock();
+ try {
+ isAnimating = v;
+ } finally {
+ stateSync.unlock();
+ }
}
class MainLoop implements Runnable {
public void run() {
try {
- if(DEBUG) {
- System.err.println("Animator started: "+Thread.currentThread());
- }
- startTime = System.currentTimeMillis();
- curTime = startTime;
- totalFrames = 0;
-
synchronized (Animator.this) {
- isAnimating = true;
- isPaused = false;
+ if(DEBUG) {
+ System.err.println("Animator started: "+Thread.currentThread());
+ }
+
+ startTime = System.currentTimeMillis();
+ curTime = startTime;
+ totalFrames = 0;
+
+ animThread = Thread.currentThread();
+ setIsAnimatingSynced(false); // barrier
Animator.this.notifyAll();
}
- while (!shouldStop) {
- // Don't consume CPU unless there is work to be done and not paused
- if ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) {
- synchronized (Animator.this) {
- boolean wasPaused = false;
- while ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) {
- isAnimating = false;
- isPaused = true;
- wasPaused = true;
- if(DEBUG) {
- System.err.println("Animator paused: "+Thread.currentThread());
- }
- Animator.this.notifyAll();
- try {
- Animator.this.wait();
- } catch (InterruptedException e) {
- }
+ while (!stopIssued) {
+ synchronized (Animator.this) {
+ // Don't consume CPU unless there is work to be done and not paused
+ while (!stopIssued && (pauseIssued || drawablesEmpty)) {
+ boolean wasPaused = pauseIssued;
+ if (DEBUG) {
+ System.err.println("Animator paused: " + Thread.currentThread());
+ }
+ setIsAnimatingSynced(false); // barrier
+ Animator.this.notifyAll();
+ try {
+ Animator.this.wait();
+ } catch (InterruptedException e) {
}
- if ( wasPaused ) {
+
+ if (wasPaused) {
+ // resume from pause -> reset counter
startTime = System.currentTimeMillis();
- curTime = startTime;
+ curTime = startTime;
totalFrames = 0;
- isAnimating = true;
- isPaused = false;
- if(DEBUG) {
- System.err.println("Animator resumed: "+Thread.currentThread());
+ if (DEBUG) {
+ System.err.println("Animator resume: " + Thread.currentThread());
}
- Animator.this.notifyAll();
}
}
- }
- if ( !shouldStop && !shouldPause) {
- display();
- if ( !runAsFastAsPossible) {
- // Avoid swamping the CPU
- Thread.yield();
+ if (!stopIssued && !isAnimating) {
+ // resume from pause or drawablesEmpty,
+ // implies !pauseIssued and !drawablesEmpty
+ setIsAnimatingSynced(true);
+ Animator.this.notifyAll();
}
+ } // sync Animator.this
+ if (!stopIssued) {
+ display();
+ }
+ if (!stopIssued && !runAsFastAsPossible) {
+ // Avoid swamping the CPU
+ Thread.yield();
}
}
} finally {
@@ -167,27 +180,50 @@ public class Animator extends AnimatorBase {
if(DEBUG) {
System.err.println("Animator stopped: "+Thread.currentThread());
}
- shouldStop = false;
- shouldPause = false;
- thread = null;
- isAnimating = false;
- isPaused = false;
+ stopIssued = false;
+ pauseIssued = false;
+ animThread = null;
+ setIsAnimatingSynced(false); // barrier
Animator.this.notifyAll();
}
}
}
}
- public final synchronized boolean isStarted() {
- return (thread != null);
+ private final boolean isStartedImpl() {
+ return animThread != null ;
+ }
+ public final boolean isStarted() {
+ stateSync.lock();
+ try {
+ return animThread != null ;
+ } finally {
+ stateSync.unlock();
+ }
}
- public final synchronized boolean isAnimating() {
- return (thread != null) && isAnimating;
+ private final boolean isAnimatingImpl() {
+ return animThread != null && isAnimating ;
+ }
+ public final boolean isAnimating() {
+ stateSync.lock();
+ try {
+ return animThread != null && isAnimating ;
+ } finally {
+ stateSync.unlock();
+ }
}
- public final synchronized boolean isPaused() {
- return (thread != null) && isPaused;
+ private final boolean isPausedImpl() {
+ return animThread != null && pauseIssued ;
+ }
+ public final boolean isPaused() {
+ stateSync.lock();
+ try {
+ return animThread != null && pauseIssued ;
+ } finally {
+ stateSync.unlock();
+ }
}
interface Condition {
@@ -202,109 +238,101 @@ public class Animator extends AnimatorBase {
// dependencies on the Animator's internal thread. Currently we
// use a couple of heuristics to determine whether we should do
// the blocking wait().
- boolean doWait = !impl.skipWaitForCompletion(thread);
+ boolean doWait = !impl.skipWaitForCompletion(animThread);
if (doWait) {
while (condition.result()) {
try {
wait();
- } catch (InterruptedException ie) {
- }
+ } catch (InterruptedException ie) { }
}
}
if(DEBUG) {
System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished - waited " + doWait +
- ", started: " + isStarted() +", animating: " + isAnimating() +
- ", paused: " + isPaused());
+ ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() +
+ ", paused: " + isPausedImpl() + ", drawables " + drawables.size());
}
}
public synchronized void start() {
- boolean started = null != thread;
- if ( started || isAnimating ) {
- throw new GLException("Already running (started "+started+" (false), animating "+isAnimating+" (false))");
+ if ( isStartedImpl() ) {
+ throw new GLException("Start: Already running (started "+isStartedImpl()+" (false))");
}
if (runnable == null) {
runnable = new MainLoop();
}
resetCounter();
- int id;
String threadName = Thread.currentThread().getName()+"-"+baseName;
+ Thread thread;
if(null==threadGroup) {
thread = new Thread(runnable, threadName);
} else {
thread = new Thread(threadGroup, runnable, threadName);
}
+ thread.setDaemon(true); // don't stop JVM from shutdown ..
thread.start();
-
finishLifecycleAction(waitForStartedCondition);
}
private class WaitForStartedCondition implements Condition {
public boolean result() {
- // cont waiting until actually is animating
- return !isAnimating || thread == null;
+ return !isStartedImpl() || (!drawablesEmpty && !isAnimating) ;
}
}
Condition waitForStartedCondition = new WaitForStartedCondition();
public synchronized void stop() {
- boolean started = null != thread;
- if ( !started ) {
- throw new GLException("Not started");
+ if ( !isStartedImpl() ) {
+ throw new GLException("Stop: Not running (started "+isStartedImpl()+" (true))");
}
- shouldStop = true;
+ stopIssued = true;
notifyAll();
-
finishLifecycleAction(waitForStoppedCondition);
}
private class WaitForStoppedCondition implements Condition {
public boolean result() {
- return thread != null;
+ return isStartedImpl();
}
}
Condition waitForStoppedCondition = new WaitForStoppedCondition();
public synchronized void pause() {
- boolean started = null != thread;
- if ( !started || !isAnimating || shouldPause ) {
- throw new GLException("Invalid state (started "+started+" (true), animating "+isAnimating+" (true), paused "+shouldPause+" (false) )");
+ if ( !isStartedImpl() || pauseIssued ) {
+ throw new GLException("Pause: Invalid state (started "+isStartedImpl()+" (true), paused "+pauseIssued+" (false) )");
+ }
+ stateSync.lock();
+ try {
+ pauseIssued = true;
+ } finally {
+ stateSync.unlock();
}
- shouldPause = true;
notifyAll();
-
finishLifecycleAction(waitForPausedCondition);
}
private class WaitForPausedCondition implements Condition {
public boolean result() {
// end waiting if stopped as well
- return (!isPaused || isAnimating) && thread != null;
+ return isAnimating && isStartedImpl();
}
}
Condition waitForPausedCondition = new WaitForPausedCondition();
public synchronized void resume() {
- boolean started = null != thread;
- if ( !started || !shouldPause ) {
- throw new GLException("Invalid state (started "+started+" (true), paused "+shouldPause+" (true) )");
- }
- shouldPause = false;
+ if ( !isStartedImpl() || !pauseIssued ) {
+ throw new GLException("Resume: Invalid state (started "+isStartedImpl()+" (true), paused "+pauseIssued+" (true) )");
+ }
+ stateSync.lock();
+ try {
+ pauseIssued = false;
+ } finally {
+ stateSync.unlock();
+ }
notifyAll();
-
- finishLifecycleAction(waitForResumedCondition);
+ finishLifecycleAction(waitForResumeCondition);
}
- private class WaitForResumedCondition implements Condition {
+ private class WaitForResumeCondition implements Condition {
public boolean result() {
// end waiting if stopped as well
- return (isPaused || !isAnimating) && thread != null;
+ return !drawablesEmpty && !isAnimating && isStartedImpl();
}
}
- Condition waitForResumedCondition = new WaitForResumedCondition();
-
- protected final boolean getShouldPause() {
- return shouldPause;
- }
-
- protected final boolean getShouldStop() {
- return shouldStop;
- }
-
+ Condition waitForResumeCondition = new WaitForResumeCondition();
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index bd5d1ad68..65d6745ed 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -31,13 +31,18 @@ package com.jogamp.opengl.util;
import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.opengl.impl.Debug;
import java.util.ArrayList;
-import java.util.List;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLProfile;
/**
- * Base implementation of GLAnimatorControl
+ * Base implementation of GLAnimatorControl<br>
+ * <p>
+ * The change synchronization is done via synchronized blocks on the AnimatorBase instance.<br>
+ * Status get / set activity is synced with a RecursiveLock, used as a memory barrier.<br>
+ * This is suitable, since all change requests are allowed to be expensive
+ * as they are not expected to be called at every frame.
+ * </p>
*/
public abstract class AnimatorBase implements GLAnimatorControl {
protected static final boolean DEBUG = Debug.debug("Animator");
@@ -45,20 +50,21 @@ public abstract class AnimatorBase implements GLAnimatorControl {
private static int animatorCount = 0;
public interface AnimatorImpl {
- void display(AnimatorBase animator, boolean ignoreExceptions, boolean printExceptions);
+ void display(ArrayList drawables, boolean ignoreExceptions, boolean printExceptions);
boolean skipWaitForCompletion(Thread thread);
}
protected ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList();
- protected RecursiveLock drawablesLock = new RecursiveLock();
+ protected boolean drawablesEmpty;
protected AnimatorImpl impl;
protected String baseName;
- protected Thread thread;
+ protected Thread animThread;
protected boolean ignoreExceptions;
protected boolean printExceptions;
protected long startTime;
protected long curTime;
protected int totalFrames;
+ protected RecursiveLock stateSync = new RecursiveLock();
/** Creates a new, empty Animator. */
public AnimatorBase() {
@@ -75,6 +81,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
synchronized (Animator.class) {
animatorCount++;
baseName = baseName.concat("-"+animatorCount);
+ drawablesEmpty = true;
}
resetCounter();
}
@@ -82,25 +89,54 @@ public abstract class AnimatorBase implements GLAnimatorControl {
protected abstract String getBaseName(String prefix);
public synchronized void add(GLAutoDrawable drawable) {
- drawablesLock.lock();
+ if(DEBUG) {
+ System.err.println("Animator add: "+drawable.hashCode()+" - "+Thread.currentThread());
+ }
+ // drawables list may be in use by display
+ stateSync.lock();
try {
- drawables.add(drawable);
+ ArrayList newDrawables = (ArrayList) drawables.clone();
+ newDrawables.add(drawable);
+ drawables = newDrawables;
+ drawablesEmpty = drawables.size() == 0;
drawable.setAnimator(this);
} finally {
- drawablesLock.unlock();
+ stateSync.unlock();
}
notifyAll();
+ if(!impl.skipWaitForCompletion(animThread)) {
+ while(isStarted() && !isPaused() && !isAnimating()) {
+ try {
+ wait();
+ } catch (InterruptedException ie) { }
+ }
+ }
}
public synchronized void remove(GLAutoDrawable drawable) {
- drawablesLock.lock();
+ if(DEBUG) {
+ System.err.println("Animator remove: "+drawable.hashCode()+" - "+Thread.currentThread());
+ }
+
+ // drawables list may be in use by display
+ stateSync.lock();
try {
- drawables.remove(drawable);
+ ArrayList newDrawables = (ArrayList) drawables.clone();
+ newDrawables.remove(drawable);
+ drawables = newDrawables;
+ drawablesEmpty = drawables.size() == 0;
drawable.setAnimator(null);
} finally {
- drawablesLock.unlock();
+ stateSync.unlock();
}
notifyAll();
+ if(!impl.skipWaitForCompletion(animThread)) {
+ while(isStarted() && drawablesEmpty && isAnimating()) {
+ try {
+ wait();
+ } catch (InterruptedException ie) { }
+ }
+ }
}
/** Called every frame to cause redrawing of all of the
@@ -109,20 +145,18 @@ public abstract class AnimatorBase implements GLAnimatorControl {
components this Animator manages, in particular when multiple
lightweight widgets are continually being redrawn. */
protected void display() {
- impl.display(this, ignoreExceptions, printExceptions);
+ ArrayList dl;
+ stateSync.lock();
+ try {
+ dl = drawables;
+ } finally {
+ stateSync.unlock();
+ }
+ impl.display(dl, ignoreExceptions, printExceptions);
curTime = System.currentTimeMillis();
totalFrames++;
}
- public List acquireDrawables() {
- drawablesLock.lock();
- return drawables;
- }
-
- public void releaseDrawables() {
- drawablesLock.unlock();
- }
-
public long getCurrentTime() {
return curTime;
}
@@ -139,16 +173,21 @@ public abstract class AnimatorBase implements GLAnimatorControl {
return totalFrames;
}
+ public final Thread getThread() {
+ stateSync.lock();
+ try {
+ return animThread;
+ } finally {
+ stateSync.unlock();
+ }
+ }
+
public synchronized void resetCounter() {
startTime = System.currentTimeMillis(); // overwrite startTime to real init one
curTime = startTime;
totalFrames = 0;
}
- public final synchronized Thread getThread() {
- return thread;
- }
-
/** Sets a flag causing this Animator to ignore exceptions produced
while redrawing the drawables. By default this flag is set to
false, causing any exception thrown to halt the Animator. */
@@ -165,10 +204,6 @@ public abstract class AnimatorBase implements GLAnimatorControl {
}
public String toString() {
- return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+"]";
+ return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]";
}
-
- protected abstract boolean getShouldPause();
-
- protected abstract boolean getShouldStop();
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
index 650d2e8ae..f98c4b488 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
@@ -33,37 +33,32 @@
package com.jogamp.opengl.util;
-import java.util.*;
-import javax.media.opengl.*;
+import java.util.ArrayList;
+import javax.media.opengl.GLAutoDrawable;
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
up this behavior if desired. */
class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl {
- public void display(AnimatorBase animator,
+ public void display(ArrayList drawables,
boolean ignoreExceptions,
boolean printExceptions) {
- List drawables = animator.acquireDrawables();
- try {
- for (int i=0;
- animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size();
- i++) {
- GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
- try {
+ for (int i=0; i<drawables.size(); i++) {
+ GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
+ try {
+ if(drawable.isRealized()) {
drawable.display();
- } catch (RuntimeException e) {
- if (ignoreExceptions) {
- if (printExceptions) {
- e.printStackTrace();
- }
- } else {
- throw(e);
+ }
+ } catch (RuntimeException e) {
+ if (ignoreExceptions) {
+ if (printExceptions) {
+ e.printStackTrace();
}
+ } else {
+ throw(e);
}
}
- } finally {
- animator.releaseDrawables();
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
index 8542000c6..447c72709 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
@@ -88,16 +88,31 @@ public class FPSAnimator extends AnimatorBase {
this.scheduleAtFixedRate = scheduleAtFixedRate;
}
- public final synchronized boolean isStarted() {
- return (timer != null);
+ public final boolean isStarted() {
+ stateSync.lock();
+ try {
+ return (timer != null);
+ } finally {
+ stateSync.unlock();
+ }
}
- public final synchronized boolean isAnimating() {
- return (timer != null) && (task != null);
+ public final boolean isAnimating() {
+ stateSync.lock();
+ try {
+ return (timer != null) && (task != null);
+ } finally {
+ stateSync.unlock();
+ }
}
- public final synchronized boolean isPaused() {
- return (timer != null) && (task == null);
+ public final boolean isPaused() {
+ stateSync.lock();
+ try {
+ return (timer != null) && (task == null);
+ } finally {
+ stateSync.unlock();
+ }
}
private void startTask() {
@@ -105,7 +120,8 @@ public class FPSAnimator extends AnimatorBase {
task = new TimerTask() {
public void run() {
if(FPSAnimator.this.shouldRun) {
- FPSAnimator.this.thread = Thread.currentThread();
+ FPSAnimator.this.animThread = Thread.currentThread();
+ // display impl. uses synchronized block on the animator instance
display();
}
}
@@ -125,8 +141,13 @@ public class FPSAnimator extends AnimatorBase {
if (timer != null) {
throw new GLException("Already started");
}
- timer = new Timer();
- startTask();
+ stateSync.lock();
+ try {
+ timer = new Timer();
+ startTask();
+ } finally {
+ stateSync.unlock();
+ }
}
/** Stops this FPSAnimator. Due to the implementation of the
@@ -136,36 +157,43 @@ public class FPSAnimator extends AnimatorBase {
if (timer == null) {
throw new GLException("Already stopped");
}
- shouldRun = false;
- task.cancel();
- task = null;
- timer.cancel();
- timer = null;
- thread = null;
+ stateSync.lock();
+ try {
+ shouldRun = false;
+ task.cancel();
+ task = null;
+ timer.cancel();
+ timer = null;
+ animThread = null;
+ } finally {
+ stateSync.unlock();
+ }
}
public synchronized void pause() {
if (timer == null) {
throw new GLException("Not running");
}
- shouldRun = false;
- task.cancel();
- task = null;
- thread = null;
+ stateSync.lock();
+ try {
+ shouldRun = false;
+ task.cancel();
+ task = null;
+ animThread = null;
+ } finally {
+ stateSync.unlock();
+ }
}
public synchronized void resume() {
if (timer == null) {
throw new GLException("Not running");
}
- startTask();
- }
-
- protected final boolean getShouldPause() {
- return (timer != null) && (task == null);
- }
-
- protected final boolean getShouldStop() {
- return (timer == null);
+ stateSync.lock();
+ try {
+ startTask();
+ } finally {
+ stateSync.unlock();
+ }
}
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
index 01e5646f9..98d7bc48b 100644
--- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
+++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
@@ -79,7 +79,7 @@ public interface GLAnimatorControl {
public void resetCounter();
/**
- * Indicates whether this animator is currently running, ie started.
+ * Indicates whether this animator is running, ie. has been started and not stopped.
*
* @see #start()
* @see #stop()
@@ -89,7 +89,8 @@ public interface GLAnimatorControl {
boolean isStarted();
/**
- * Indicates whether this animator is currently running and not paused.
+ * Indicates whether this animator is running and animating,<br>
+ * the latter is true if it has {@link GLAutoDrawable}s to render and is not paused.
*
* @see #start()
* @see #stop()
@@ -99,7 +100,7 @@ public interface GLAnimatorControl {
boolean isAnimating();
/**
- * Indicates whether this animator is currently running and paused.
+ * Indicates whether this animator is running and paused.
*
* @see #start()
* @see #stop()
@@ -109,7 +110,7 @@ public interface GLAnimatorControl {
boolean isPaused();
/**
- * @return The animation thread if started, ie running.
+ * @return The animation thread if running, otherwise null.
*
* @see #start()
* @see #stop()
@@ -158,7 +159,7 @@ public interface GLAnimatorControl {
*
* @see #resume()
* @see #isAnimating()
- * @throws GLException if not started or not animating or already paused
+ * @throws GLException if not started or already paused
*/
void pause();
@@ -177,4 +178,15 @@ public interface GLAnimatorControl {
* @throws GLException if not started or not paused
*/
void resume();
+
+ /**
+ * Removes a drawable from the animator's list of rendering drawables.<br>
+ * This method should get called in case a drawable becomes invalid,
+ * and will not be recovered.<br>
+ * This allows the animator thread to become idle in case the last drawable
+ * has reached it's end of life.<br>
+ *
+ * @param drawable the to be removed drawable
+ */
+ void remove(GLAutoDrawable drawable);
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 12ded8736..cde327a07 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -40,7 +40,6 @@
package javax.media.opengl;
-import javax.media.opengl.glu.*;
import com.jogamp.opengl.impl.Debug;
import java.security.*;
diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilities.java b/src/jogl/classes/javax/media/opengl/GLCapabilities.java
index 3d2e2bcc9..82f83dc82 100644
--- a/src/jogl/classes/javax/media/opengl/GLCapabilities.java
+++ b/src/jogl/classes/javax/media/opengl/GLCapabilities.java
@@ -59,7 +59,7 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil
private boolean doubleBuffered = true;
private boolean stereo = false;
private boolean hardwareAccelerated = true;
- private int depthBits = 24;
+ private int depthBits = 16;
private int stencilBits = 0;
private int accumRedBits = 0;
private int accumGreenBits = 0;
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index f2016a23c..265c7ff49 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -347,10 +347,17 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
}
if(null!=context) {
- boolean animatorWasAnimating = false;
+ boolean animatorPaused = false;
GLAnimatorControl animator = getAnimator();
if(null!=animator) {
- animatorWasAnimating = animator.isAnimating();
+ if(regenerate) {
+ if(animator.isStarted() && !animator.isPaused()) {
+ animator.pause();
+ animatorPaused = true;
+ }
+ } else {
+ animator.remove(this);
+ }
}
disposeRegenerate=regenerate;
@@ -376,8 +383,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
drawableHelper.invokeGL(drawable, context, disposeAction, null);
}
- if(regenerate && animatorWasAnimating && animator.isPaused()) {
- animator.resume();
+ if(animatorPaused) {
+ animator.resume();
}
}
if(!regenerate) {
diff --git a/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java b/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java
index 8f56f6f46..fef0e5ad6 100644
--- a/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java
+++ b/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java
@@ -256,20 +256,25 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase {
Screen screen = win0.getScreen();
win0.setPosition(screen.getWidth()-150, 0);
win0.addGLEventListener(new Gears());
- Animator anim0 = new Animator(win0);
- anim0.start();
+ Animator anim = new Animator(win0);
+ anim.start();
GLWindow win1 = GLWindow.create(caps);
NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(win1);
- Animator anim1 = new Animator(win1);
- anim1.start();
+ anim.add(win1);
runTestGL(newtCanvasAWT, win1);
win0.destroy();
- Assert.assertEquals(false, anim0.isAnimating());
+ Assert.assertEquals(true, anim.isAnimating());
newtCanvasAWT.destroy();
- Assert.assertEquals(false, anim1.isAnimating());
+
+ win0.invalidate();
+ Assert.assertEquals(true, anim.isAnimating());
+ win1.invalidate();
+ Assert.assertEquals(false, anim.isAnimating());
+
+ anim.stop();
System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.test01NewtCanvasAWT(): End");
}
@@ -280,6 +285,9 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase {
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
+ Animator anim = new Animator();
+ anim.start();
+
/**
* Using GLCanvas _and_ NEWT side by side currently causes a deadlock
* in AWT with AMD drivers !
@@ -290,23 +298,18 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase {
Screen screen = win0.getScreen();
win0.setPosition(screen.getWidth()-150, 0);
win0.addGLEventListener(new Gears());
- Animator anim0 = new Animator(win0);
- anim0.start();
+ anim.add(win0);
*/
GLCanvas glCanvas = new GLCanvas(caps);
- Animator anim1 = new Animator(glCanvas);
- anim1.start();
+ anim.add(glCanvas);
runTestGL(glCanvas, glCanvas);
- Thread.sleep(100); // wait 1/10Hz to allow animation to be paused
- Assert.assertEquals(false, anim1.isAnimating());
-
/**
win0.destroy();
- Assert.assertEquals(false, anim0.isAnimating());
+ Assert.assertEquals(true, anim.isAnimating());
*/
-
+ anim.stop();
System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.test02GLCanvas(): End");
}
diff --git a/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java b/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java
index e79d57a4f..a019de72d 100644
--- a/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java
+++ b/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java
@@ -28,19 +28,11 @@
package com.jogamp.test.junit.newt;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Test;
-import javax.media.nativewindow.*;
import javax.media.opengl.*;
import com.jogamp.opengl.util.Animator;
@@ -131,7 +123,8 @@ public class TestGLWindows02NEWTAnimated extends UITestCase {
Thread.sleep(100);
}
destroyWindow(window);
- Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(true, animator.isAnimating());
+ animator.stop();
}
@Test
@@ -146,7 +139,8 @@ public class TestGLWindows02NEWTAnimated extends UITestCase {
}
destroyWindow(window);
destroyWindow(window);
- Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(true, animator.isAnimating());
+ animator.stop();
}
@Test
@@ -167,20 +161,44 @@ public class TestGLWindows02NEWTAnimated extends UITestCase {
Assert.assertNotNull(window2);
window2.setPosition(screen.getWidth()-width, 0);
- Animator animator1 = new Animator(window1);
- animator1.start();
- Animator animator2 = new Animator(window2);
- animator2.start();
- while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) {
+ Animator animator = new Animator();
+ Assert.assertEquals(false, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.start();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.add(window1);
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.add(window2);
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ while(animator.isAnimating() && animator.getDuration()<durationPerTest) {
Thread.sleep(100);
}
+ window1.invalidate();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
- destroyWindow(window1);
- Assert.assertEquals(false, animator1.isAnimating());
-
- destroyWindow(window2);
- Assert.assertEquals(false, animator2.isAnimating());
+ while(animator.isAnimating() && animator.getDuration()<2*durationPerTest) {
+ Thread.sleep(100);
+ }
+ window2.invalidate();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+ animator.stop();
}
+
@Test
public void testWindowDecor03TwoWinTwoDisplays() throws InterruptedException {
GLCapabilities caps = new GLCapabilities(glp);
@@ -204,19 +222,56 @@ public class TestGLWindows02NEWTAnimated extends UITestCase {
Assert.assertNotNull(window2);
window2.setPosition(screen2.getWidth()-width, 0);
- Animator animator1 = new Animator(window1);
- animator1.start();
- Animator animator2 = new Animator(window2);
- animator2.start();
- while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) {
+ Animator animator = new Animator();
+ Assert.assertEquals(false, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.start();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.add(window1);
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.add(window2);
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ while(animator.isAnimating() && animator.getDuration()<durationPerTest) {
Thread.sleep(100);
}
-
destroyWindow(window1);
- Assert.assertEquals(false, animator1.isAnimating());
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+ while(animator.isAnimating() && animator.getDuration()<2*durationPerTest) {
+ Thread.sleep(100);
+ }
destroyWindow(window2);
- Assert.assertEquals(false, animator2.isAnimating());
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.pause();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(true, animator.isPaused());
+
+ animator.resume();
+ Assert.assertEquals(true, animator.isStarted());
+ Assert.assertEquals(true, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
+
+ animator.stop();
+ Assert.assertEquals(false, animator.isStarted());
+ Assert.assertEquals(false, animator.isAnimating());
+ Assert.assertEquals(false, animator.isPaused());
}
public static void setDemoFields(GLEventListener demo, GLWindow glWindow) {
diff --git a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java
index 1f45c6c1d..97589ed3a 100644
--- a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java
+++ b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java
@@ -709,17 +709,7 @@ public class TestParenting01NEWT extends UITestCase {
}
System.err.println("durationPerTest: "+durationPerTest);
String tstname = TestParenting01NEWT.class.getName();
- org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] {
- tstname,
- "filtertrace=true",
- "haltOnError=false",
- "haltOnFailure=false",
- "showoutput=true",
- "outputtoformatters=true",
- "logfailedtests=true",
- "logtestlistenerevents=true",
- "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter",
- "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } );
+ org.junit.runner.JUnitCore.main(tstname);
}
}
diff --git a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java
index 2c3455cb0..fd52c86a1 100644
--- a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java
+++ b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java
@@ -216,6 +216,8 @@ public class TestParenting01aAWT extends UITestCase {
Animator animator1 = new Animator(glWindow1);
animator1.start();
+ Assert.assertEquals(true, animator1.isStarted());
+ Assert.assertEquals(true, animator1.isAnimating());
while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) {
Thread.sleep(100);
}
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index 8b9e7bb4e..99db47168 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -31,7 +31,6 @@ package com.jogamp.newt;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseListener;
-import com.jogamp.newt.event.ScreenModeListener;
import com.jogamp.newt.impl.Debug;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
@@ -43,7 +42,7 @@ import javax.media.nativewindow.util.Insets;
* Specifying the public Window functionality for the
* using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}.
*/
-public interface Window extends NativeWindow, ScreenModeListener {
+public interface Window extends NativeWindow {
public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent");
public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent");
public static final boolean DEBUG_WINDOW_EVENT = Debug.debug("Window.WindowEvent");
diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
index f0aa9effd..fd5c1b662 100644
--- a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
+++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
@@ -68,7 +68,7 @@ import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
import javax.media.nativewindow.util.Rectangle;
-public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenModeListener
+public abstract class WindowImpl implements Window, NEWTEventConsumer
{
public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true);
@@ -112,6 +112,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
private ArrayList windowListeners;
private boolean repaintQueued = false;
+ ScreenModeListenerImpl screenModeListenerImpl = new ScreenModeListenerImpl();
+
private void initializeStates() {
invalidate(true);
@@ -250,9 +252,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
* Invoked for expensive modifications, ie while reparenting and ScreenMode change.<br>
* No lock is hold when invoked.<br>
*
+ * @return true is paused, otherwise false. If true {@link #resumeRenderingAction()} shall be issued.
+ *
* @see #resumeRenderingAction()
*/
- void pauseRenderingAction();
+ boolean pauseRenderingAction();
/**
* Invoked for expensive modifications, ie while reparenting and ScreenMode change.
@@ -280,7 +284,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
screenReferenceAdded = true;
createNativeImpl();
setVisibleImpl(true, x, y, width, height);
- screen.addScreenModeListener(this);
+ screen.addScreenModeListener(screenModeListenerImpl);
}
} finally {
if(null!=parentWindow) {
@@ -308,7 +312,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
try {
if( null != screen ) {
if( 0 != windowHandle ) {
- screen.removeScreenModeListener(WindowImpl.this);
+ screen.removeScreenModeListener(screenModeListenerImpl);
closeNativeImpl();
removeScreenReference();
}
@@ -438,20 +442,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
public final int lockSurface() {
int res = LOCK_SURFACE_NOT_READY;
-
windowLock.lock();
- AbstractGraphicsDevice adevice = screen.getDisplay().getGraphicsDevice();
- adevice.lock();
- try {
- res = lockSurfaceImpl();
- } finally {
- if(!isNativeValid()) {
- adevice.unlock();
- windowLock.unlock();
- res = LOCK_SURFACE_NOT_READY;
+ if(isNativeValid()) {
+ AbstractGraphicsDevice adevice = screen.getDisplay().getGraphicsDevice();
+ adevice.lock();
+ try {
+ res = lockSurfaceImpl();
+ } finally {
+ if( LOCK_SURFACE_NOT_READY == res ) {
+ adevice.unlock();
+ }
}
}
+ if( LOCK_SURFACE_NOT_READY == res ) {
+ windowLock.unlock();
+ }
return res;
}
@@ -752,14 +758,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
//Exception ee = new Exception(msg);
//ee.printStackTrace();
}
+ boolean animatorPaused = false;
if(null!=lifecycleHook) {
- lifecycleHook.pauseRenderingAction();
+ animatorPaused = lifecycleHook.pauseRenderingAction();
}
if(null!=lifecycleHook) {
lifecycleHook.destroyActionPreLock();
}
runOnEDTIfAvail(true, destroyAction);
- if(null!=lifecycleHook) {
+ if(animatorPaused) {
lifecycleHook.resumeRenderingAction();
}
}
@@ -1134,15 +1141,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) {
int reparentActionStrategy = ReparentAction.ACTION_INVALID;
if(isValid()) {
+ boolean animatorPaused = false;
if(null!=lifecycleHook) {
- lifecycleHook.pauseRenderingAction();
+ animatorPaused = lifecycleHook.pauseRenderingAction();
}
try {
ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate);
runOnEDTIfAvail(true, reparentAction);
reparentActionStrategy = reparentAction.getStrategy();
} finally {
- if(null!=lifecycleHook) {
+ if(animatorPaused) {
lifecycleHook.resumeRenderingAction();
}
}
@@ -1531,31 +1539,35 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod
return this.fullscreen;
}
- public void screenModeChangeNotify(ScreenMode sm) {
- if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
- System.err.println("Window.screenModeChangeNotify: "+sm);
- }
+ class ScreenModeListenerImpl implements ScreenModeListener {
+ boolean animatorPaused = false;
- if(null!=lifecycleHook) {
- lifecycleHook.pauseRenderingAction();
- }
- }
+ public void screenModeChangeNotify(ScreenMode sm) {
+ if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+ System.err.println("Window.screenModeChangeNotify: "+sm);
+ }
- public void screenModeChanged(ScreenMode sm, boolean success) {
- if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
- System.err.println("Window.screenModeChanged: "+sm+", success: "+success);
+ if(null!=lifecycleHook) {
+ animatorPaused = lifecycleHook.pauseRenderingAction();
+ }
}
- if(success) {
- DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution();
- if ( getHeight() > screenSize.getHeight() ||
- getWidth() > screenSize.getWidth() ) {
- setSize(screenSize.getWidth(), screenSize.getHeight());
+ public void screenModeChanged(ScreenMode sm, boolean success) {
+ if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+ System.err.println("Window.screenModeChanged: "+sm+", success: "+success);
}
- }
- if(null!=lifecycleHook) {
- lifecycleHook.resumeRenderingAction();
+ if(success) {
+ DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution();
+ if ( getHeight() > screenSize.getHeight() ||
+ getWidth() > screenSize.getWidth() ) {
+ setSize(screenSize.getWidth(), screenSize.getHeight());
+ }
+ }
+
+ if(animatorPaused) {
+ lifecycleHook.resumeRenderingAction();
+ }
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
}
}
diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java
index 5d7bcd7b3..d4f4f77ea 100644
--- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java
+++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java
@@ -59,7 +59,7 @@ public class WindowsWindow extends WindowImpl {
hdc = GetDC0(getWindowHandle());
hmon = MonitorFromWindow0(getWindowHandle());
}
- return LOCK_SUCCESS;
+ return ( 0 != hdc ) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY;
}
protected void unlockSurfaceImpl() {
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index dc5c12b58..da22a6217 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -86,11 +86,11 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
public void windowDestroyNotify(WindowEvent e) {
// Is an animator thread perform rendering?
- if (GLWindow.this.helper.isExternalAnimatorAnimating()) {
+ if (GLWindow.this.helper.isExternalAnimatorRunning()) {
// Pause animations before initiating safe destroy.
GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator();
ctrl.pause();
-
+
destroy();
ctrl.resume();
@@ -251,15 +251,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
public final void addChild(NativeWindow win) {
window.addChild(win);
}
-
- public void screenModeChangeNotify(ScreenMode sm) {
- window.screenModeChangeNotify(sm);
- }
-
- public void screenModeChanged(ScreenMode sm, boolean success) {
- window.screenModeChanged(sm, success);
- }
-
+
//----------------------------------------------------------------------
// Window.LifecycleHook Implementation
//
@@ -299,12 +291,10 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
}
DisposeAction disposeAction = new DisposeAction();
- /** Window.LifecycleHook */
public synchronized void destroyActionPreLock() {
// nop
}
- /** Window.LifecycleHook */
public synchronized void destroyActionInLock() {
if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
String msg = new String("GLWindow.destroy() "+Thread.currentThread()+", start");
@@ -334,7 +324,6 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
}
}
- /** Window.LifecycleHook */
public synchronized void invalidate(boolean unrecoverable) {
if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
String msg = new String("GLWindow.invalidate("+unrecoverable+") "+Thread.currentThread()+", start");
@@ -344,14 +333,13 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
}
if(unrecoverable) {
GLAnimatorControl ctrl = GLWindow.this.getAnimator();
- if ( null!=ctrl && ctrl.isStarted() ) {
- ctrl.stop();
+ if ( null!=ctrl ) {
+ ctrl.remove(GLWindow.this);
}
helper=null;
}
}
- /** Window.LifecycleHook */
public synchronized void resetCounter() {
if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.resetCounter() "+Thread.currentThread());
@@ -394,21 +382,20 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
//e1.printStackTrace();
}
}
-
- boolean animatorPaused = false;
-
- public synchronized void pauseRenderingAction() {
+
+ public synchronized boolean pauseRenderingAction() {
+ boolean animatorPaused = false;
GLAnimatorControl ctrl = GLWindow.this.getAnimator();
- if ( null!=ctrl && ctrl.isAnimating() && ctrl.getThread() != Thread.currentThread() ) {
+ if ( null!=ctrl && ctrl.isStarted() && !ctrl.isPaused()) {
animatorPaused = true;
ctrl.pause();
}
+ return animatorPaused;
}
public synchronized void resumeRenderingAction() {
GLAnimatorControl ctrl = GLWindow.this.getAnimator();
- if ( null!=ctrl && animatorPaused ) {
- animatorPaused = false;
+ if ( null!=ctrl && ctrl.isPaused() ) {
ctrl.resume();
}
}
@@ -517,10 +504,11 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
setVisible(true);
}
- if( isVisible() && isNativeValid() && null != context ) {
- if(forceReshape) {
- sendReshape = true;
- }
+ if(forceReshape) {
+ sendReshape = true;
+ }
+
+ if( isVisible() && null != context ) {
if( NativeSurface.LOCK_SURFACE_NOT_READY < lockSurface() ) {
try {
helper.invokeGL(drawable, context, displayAction, initAction);