@Override public void destroy(boolean waitFor){ if (waitFor) waitFor(false); if (animator.isAnimating()) animator.stop(); }
@Override public final synchronized void add(final GLAutoDrawable drawable) { if(DEBUG) { System.err.println("Animator add: 0x"+Integer.toHexString(drawable.hashCode())+" - "+toString()+" - "+getThreadName()); initImpl(false); pause(); if( isStarted() ) { drawable.setExclusiveContextThread( exclusiveContext ? getExclusiveContextThread() : null ); // if already running .. if( isPaused() ) { // either paused by pause() above, or if previously drawablesEmpty==true resume(); return isStarted() && !isPaused() && !isAnimating() && ( exclusiveContext && null == dect || !exclusiveContext && null != dect ); } }; final boolean res = finishLifecycleAction(waitForAnimatingAndECTCondition, 0); if(DEBUG) { System.err.println("Animator add: Wait for Animating/ECT OK: "+res+", "+toString()+", dect "+drawable.getExclusiveContextThread());
@Override public String toString() { return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", drawable "+drawables.size()+ ", totals[dt "+getTotalFPSDuration()+", frames "+getTotalFPSFrames()+", fps "+getTotalFPS()+ "], modeBits "+modeBits+", init'ed "+(null!=impl)+", animThread "+getThread()+", exclCtxThread "+exclusiveContext+"("+getExclusiveContextThread()+")]"; } }
final Thread _exclusiveContextThread; synchronized (AnimatorBase.this) { propagateState = isStarted() && !drawablesEmpty; _exclusiveContextThread = userExclusiveContextThread; oldExclusiveContext = exclusiveContext; UncaughtAnimatorException displayCaught = null; if( propagateState ) { setDrawablesExclCtxState(enable); if( !enable ) { if( Thread.currentThread() == getThread() || Thread.currentThread() == _exclusiveContextThread ) { try { display(); // propagate exclusive context -> off! } catch (final UncaughtAnimatorException dre) { displayCaught = dre; final boolean resumed = isAnimating() ? false : resume(); int counter = 10; while( 0<counter && isAnimating() && !validateDrawablesExclCtxState(dECT) ) { try { Thread.sleep(20); pause(); System.err.println("AnimatorBase.setExclusiveContextThread: all-GLAD Ok: "+validateDrawablesExclCtxState(dECT)+", "+this); if( null != displayCaught ) { System.err.println("AnimatorBase.setExclusiveContextThread: caught: "+displayCaught.getMessage());
@Override public final synchronized void remove(final GLAutoDrawable drawable) { if(DEBUG) { System.err.println("Animator remove: 0x"+Integer.toHexString(drawable.hashCode())+" - "+toString()+" - "+getThreadName()); if( exclusiveContext && isAnimating() ) { drawable.setExclusiveContextThread( null ); final Condition waitForNullECTCondition = new Condition() { return null != drawable.getExclusiveContextThread(); } }; final boolean res = finishLifecycleAction(waitForNullECTCondition, POLLP_WAIT_FOR_FINISH_LIFECYCLE_ACTION); if(DEBUG) { System.err.println("Animator remove: Wait for Null-ECT OK: "+res+", "+toString()+", dect "+drawable.getExclusiveContextThread()); final boolean paused = pause(); drawables.remove(drawable); drawablesEmpty = drawables.size() == 0; drawable.setAnimator(null); if(paused) { resume(); final boolean res = finishLifecycleAction(waitForNotAnimatingIfEmptyCondition, 0); if(DEBUG) { System.err.println("Animator remove: Wait for !Animating-if-empty OK: "+res+", "+toString());
/** * Initializes implementation details post setup, * invoked at {@link #add(GLAutoDrawable)}, {@link #start()}, .. * <p> * Operation is a NOP if <code>force</code> is <code>false</code> * and this instance is already initialized. * </p> * * @throws GLException if Animator is {@link #isStarted()} */ protected final synchronized void initImpl(final boolean force) { if( force || null == impl ) { final String seqSuffix = String.format("#%02d", seqInstanceNumber++); if( useAWTAnimatorImpl( modeBits ) ) { try { impl = (AnimatorImpl) awtAnimatorImplClazz.newInstance(); baseName = getBaseName("AWT")+seqSuffix; } catch (final Exception e) { e.printStackTrace(); } } if( null == impl ) { impl = new DefaultAnimatorImpl(); baseName = getBaseName("")+seqSuffix; } if(DEBUG) { System.err.println("Animator.initImpl: baseName "+baseName+", implClazz "+impl.getClass().getName()+" - "+toString()+" - "+getThreadName()); } } } protected abstract String getBaseName(String prefix);
@Override public boolean eval() { final Thread dect = drawable.getExclusiveContextThread(); return isStarted() && !isPaused() && !isAnimating() && ( exclusiveContext && null == dect || !exclusiveContext && null != dect ); } }; final boolean res = finishLifecycleAction(waitForAnimatingAndECTCondition, 0);
initImpl(false); final boolean blocking; long remaining; if(DEBUG || blocking && nok) { // Info only if DEBUG or ( blocking && not-ok ) ; !blocking possible if AWT if( blocking && remaining<=0 && nok ) { System.err.println("finishLifecycleAction(" + waitCondition.getClass().getName() + "): ++++++ timeout reached ++++++ " + getThreadName()); " - " + getThreadName()); System.err.println(" - "+toString()); if(nok) { Thread.dumpStack();
@Override public boolean eval() { return isStarted() && drawablesEmpty && isAnimating(); } };
/** * Should be called at {@link #start()} and {@link #stop()} * from within the animator thread. * <p> * At {@link #stop()} an additional {@link #display()} call shall be issued * to allow propagation of releasing the exclusive thread. * </p> */ protected final synchronized void setDrawablesExclCtxState(final boolean enable) { if(DEBUG) { System.err.println("AnimatorBase.setExclusiveContextImpl exlusive "+exclusiveContext+": Enable "+enable+" for "+this+" - "+Thread.currentThread()); // Thread.dumpStack(); } final Thread ect = getExclusiveContextThread(); for (int i=0; i<drawables.size(); i++) { try { drawables.get(i).setExclusiveContextThread( enable ? ect : null ); } catch (final RuntimeException e) { e.printStackTrace(); } } } protected final boolean validateDrawablesExclCtxState(final Thread expected) {
synchronized (Animator.this) { if(DEBUG) { System.err.println("Animator start on " + getThreadName() + ": " + toString());
@Override public final synchronized void add(final GLAutoDrawable drawable) { if(DEBUG) { System.err.println("Animator add: 0x"+Integer.toHexString(drawable.hashCode())+" - "+toString()+" - "+getThreadName()); initImpl(false); pause(); if( isStarted() ) { drawable.setExclusiveContextThread( exclusiveContext ? getExclusiveContextThread() : null ); // if already running .. if( isPaused() ) { // either paused by pause() above, or if previously drawablesEmpty==true resume(); return isStarted() && !isPaused() && !isAnimating() && ( exclusiveContext && null == dect || !exclusiveContext && null != dect ); } }; final boolean res = finishLifecycleAction(waitForAnimatingAndECTCondition, 0); if(DEBUG) { System.err.println("Animator add: Wait for Animating/ECT OK: "+res+", "+toString()+", dect "+drawable.getExclusiveContextThread());
@Override public String toString() { return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", drawable "+drawables.size()+ ", totals[dt "+getTotalFPSDuration()+", frames "+getTotalFPSFrames()+", fps "+getTotalFPS()+ "], modeBits "+modeBits+", init'ed "+(null!=impl)+", animThread "+getThread()+", exclCtxThread "+exclusiveContext+"("+getExclusiveContextThread()+")]"; } }
final Thread _exclusiveContextThread; synchronized (AnimatorBase.this) { propagateState = isStarted() && !drawablesEmpty; _exclusiveContextThread = userExclusiveContextThread; oldExclusiveContext = exclusiveContext; UncaughtAnimatorException displayCaught = null; if( propagateState ) { setDrawablesExclCtxState(enable); if( !enable ) { if( Thread.currentThread() == getThread() || Thread.currentThread() == _exclusiveContextThread ) { try { display(); // propagate exclusive context -> off! } catch (final UncaughtAnimatorException dre) { displayCaught = dre; final boolean resumed = isAnimating() ? false : resume(); int counter = 10; while( 0<counter && isAnimating() && !validateDrawablesExclCtxState(dECT) ) { try { Thread.sleep(20); pause(); System.err.println("AnimatorBase.setExclusiveContextThread: all-GLAD Ok: "+validateDrawablesExclCtxState(dECT)+", "+this); if( null != displayCaught ) { System.err.println("AnimatorBase.setExclusiveContextThread: caught: "+displayCaught.getMessage());
@Override public final synchronized void remove(final GLAutoDrawable drawable) { if(DEBUG) { System.err.println("Animator remove: 0x"+Integer.toHexString(drawable.hashCode())+" - "+toString()+" - "+getThreadName()); if( exclusiveContext && isAnimating() ) { drawable.setExclusiveContextThread( null ); final Condition waitForNullECTCondition = new Condition() { return null != drawable.getExclusiveContextThread(); } }; final boolean res = finishLifecycleAction(waitForNullECTCondition, POLLP_WAIT_FOR_FINISH_LIFECYCLE_ACTION); if(DEBUG) { System.err.println("Animator remove: Wait for Null-ECT OK: "+res+", "+toString()+", dect "+drawable.getExclusiveContextThread()); final boolean paused = pause(); drawables.remove(drawable); drawablesEmpty = drawables.size() == 0; drawable.setAnimator(null); if(paused) { resume(); final boolean res = finishLifecycleAction(waitForNotAnimatingIfEmptyCondition, 0); if(DEBUG) { System.err.println("Animator remove: Wait for !Animating-if-empty OK: "+res+", "+toString());
/** * Initializes implementation details post setup, * invoked at {@link #add(GLAutoDrawable)}, {@link #start()}, .. * <p> * Operation is a NOP if <code>force</code> is <code>false</code> * and this instance is already initialized. * </p> * * @throws GLException if Animator is {@link #isStarted()} */ protected final synchronized void initImpl(final boolean force) { if( force || null == impl ) { final String seqSuffix = String.format("#%02d", seqInstanceNumber++); if( useAWTAnimatorImpl( modeBits ) ) { try { impl = (AnimatorImpl) awtAnimatorImplClazz.newInstance(); baseName = getBaseName("AWT")+seqSuffix; } catch (final Exception e) { e.printStackTrace(); } } if( null == impl ) { impl = new DefaultAnimatorImpl(); baseName = getBaseName("")+seqSuffix; } if(DEBUG) { System.err.println("Animator.initImpl: baseName "+baseName+", implClazz "+impl.getClass().getName()+" - "+toString()+" - "+getThreadName()); } } } protected abstract String getBaseName(String prefix);
@Override public boolean eval() { final Thread dect = drawable.getExclusiveContextThread(); return isStarted() && !isPaused() && !isAnimating() && ( exclusiveContext && null == dect || !exclusiveContext && null != dect ); } }; final boolean res = finishLifecycleAction(waitForAnimatingAndECTCondition, 0);
initImpl(false); final boolean blocking; long remaining; if(DEBUG || blocking && nok) { // Info only if DEBUG or ( blocking && not-ok ) ; !blocking possible if AWT if( blocking && remaining<=0 && nok ) { System.err.println("finishLifecycleAction(" + waitCondition.getClass().getName() + "): ++++++ timeout reached ++++++ " + getThreadName()); " - " + getThreadName()); System.err.println(" - "+toString()); if(nok) { ExceptionUtils.dumpStack(System.err);
@Override public boolean eval() { return isStarted() && drawablesEmpty && isAnimating(); } };
/** * Should be called at {@link #start()} and {@link #stop()} * from within the animator thread. * <p> * At {@link #stop()} an additional {@link #display()} call shall be issued * to allow propagation of releasing the exclusive thread. * </p> */ protected final synchronized void setDrawablesExclCtxState(final boolean enable) { if(DEBUG) { System.err.println("AnimatorBase.setExclusiveContextImpl exlusive "+exclusiveContext+": Enable "+enable+" for "+this+" - "+Thread.currentThread()); // Thread.dumpStack(); } final Thread ect = getExclusiveContextThread(); for (int i=0; i<drawables.size(); i++) { try { drawables.get(i).setExclusiveContextThread( enable ? ect : null ); } catch (final RuntimeException e) { e.printStackTrace(); } } } protected final boolean validateDrawablesExclCtxState(final Thread expected) {