/**
* Copyright 2012 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.opengl.test.junit.jogl.swt;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.swt.SWT ;
import org.eclipse.swt.layout.FillLayout ;
import org.eclipse.swt.widgets.Composite ;
import org.eclipse.swt.widgets.Display ;
import org.eclipse.swt.widgets.Shell ;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities ;
import com.jogamp.opengl.GLProfile;
import jogamp.newt.swt.SWTEDTUtil;
import jogamp.newt.swt.event.SWTNewtEventFactory;
import com.jogamp.common.util.InterruptSource;
import com.jogamp.nativewindow.swt.SWTAccessor;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.opengl.GLWindow ;
import com.jogamp.newt.swt.NewtCanvasSWT ;
import com.jogamp.opengl.swt.GLCanvas;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
import com.jogamp.opengl.test.junit.util.MiscUtils;
import com.jogamp.opengl.test.junit.util.UITestCase;
import com.jogamp.opengl.util.Animator;
////////////////////////////////////////////////////////////////////////////////
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestSWTBug643AsyncExec extends UITestCase {
static int duration = 500;
static boolean useAnimator = false;
////////////////////////////////////////////////////////////////////////////////
static void resetSWTAndNEWTEDTCounter() {
synchronized(swtCountSync) {
swtCount=0;
}
synchronized(edtCountSync) {
edtCount=0;
}
}
static int incrSWTCount() {
synchronized(swtCountSync) {
swtCount++;
return swtCount;
}
}
static int getSWTCount() {
synchronized(swtCountSync) {
return swtCount;
}
}
static int incrNEWTCount() {
synchronized(edtCountSync) {
edtCount++;
return edtCount;
}
}
static int getNEWTCount() {
synchronized(edtCountSync) {
return edtCount;
}
}
static Object swtCountSync = new Object();
static int swtCount = 0;
static Object edtCountSync = new Object();
static int edtCount = 0;
////////////////////////////////////////////////////////////////////////////////
static class AsyncExecEDTFeederThread extends InterruptSource.Thread {
volatile boolean shallStop = false;
private final Display swtDisplay ;
private final jogamp.newt.DisplayImpl newtDisplay;
private int swtN, newtN ;
public AsyncExecEDTFeederThread( final Display swtDisplay, final com.jogamp.newt.Display newtDisplay )
{
this.swtDisplay = swtDisplay ;
this.newtDisplay = (jogamp.newt.DisplayImpl)newtDisplay;
}
final Runnable swtAsyncAction = new Runnable() {
public void run()
{
++swtN ; incrSWTCount();
System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+getSWTCount()+"]");
} };
final Runnable newtAsyncAction = new Runnable() {
public void run()
{
++newtN ; incrNEWTCount();
System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+getNEWTCount()+"]");
} };
public void run()
{
System.err.println("[A-0 shallStop "+shallStop+"]");
while( !shallStop && !swtDisplay.isDisposed() )
{
try
{
if( !swtDisplay.isDisposed() ) {
swtDisplay.asyncExec( swtAsyncAction );
}
if(null != newtDisplay && newtDisplay.isNativeValid() && newtDisplay.getEDTUtil().isRunning()) {
// only perform async exec on valid and already running NEWT EDT!
newtDisplay.runOnEDTIfAvail(false, newtAsyncAction);
}
java.lang.Thread.sleep( 50L ) ;
} catch( final InterruptedException e ) {
break ;
}
}
System.err.println("*R-Exit* shallStop "+shallStop);
}
}
////////////////////////////////////////////////////////////////////////////////
private volatile boolean shallStop = false;
static class SWT_DSC {
Display display;
Shell shell;
Composite composite;
public void init() {
SWTAccessor.invoke(true, new Runnable() {
public void run() {
display = new Display();
Assert.assertNotNull( display );
}});
display.syncExec(new Runnable() {
public void run() {
shell = new Shell( display );
Assert.assertNotNull( shell );
shell.setLayout( new FillLayout() );
composite = new Composite( shell, SWT.NO_BACKGROUND );
composite.setLayout( new FillLayout() );
Assert.assertNotNull( composite );
}});
}
public void dispose() {
Assert.assertNotNull( display );
Assert.assertNotNull( shell );
Assert.assertNotNull( composite );
try {
display.syncExec(new Runnable() {
public void run() {
composite.dispose();
shell.dispose();
}});
SWTAccessor.invoke(true, new Runnable() {
public void run() {
display.dispose();
}});
}
catch( final Throwable throwable ) {
throwable.printStackTrace();
Assume.assumeNoException( throwable );
}
display = null;
shell = null;
composite = null;
}
}
private void testImpl(final boolean useJOGLGLCanvas, final boolean useNewtCanvasSWT, final boolean glWindowPreVisible) throws InterruptedException, InvocationTargetException {
resetSWTAndNEWTEDTCounter();
final SWT_DSC dsc = new SWT_DSC();
dsc.init();
final com.jogamp.newt.Display newtDisplay;
{
final GLProfile gl2Profile = GLProfile.get( GLProfile.GL2 ) ;
final GLCapabilities caps = new GLCapabilities( gl2Profile ) ;
final GLAutoDrawable glad;
if( useJOGLGLCanvas ) {
final GearsES2 demo = new GearsES2();
final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null);
final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory();
swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys);
glc.addGLEventListener( demo ) ;
glad = glc;
newtDisplay = null;
} else if( useNewtCanvasSWT ) {
newtDisplay = NewtFactory.createDisplay(null, false); // no-reuse
final com.jogamp.newt.Screen screen = NewtFactory.createScreen(newtDisplay, 0);
final GLWindow glWindow = GLWindow.create( screen, caps ) ;
glWindow.addGLEventListener( new GearsES2() ) ;
if( glWindowPreVisible ) {
newtDisplay.setEDTUtil(new SWTEDTUtil(newtDisplay, dsc.display)); // Especially Windows requires creation access via same thread!
glWindow.setVisible(true);
AWTRobotUtil.waitForRealized(glWindow, true);
Thread.sleep(120); // let it render a bit, before consumed by SWT
}
glad = glWindow;
NewtCanvasSWT.create( dsc.composite, 0, glWindow ) ;
} else {
throw new InternalError("XXX");
}
if(useAnimator) {
final Animator animator = new Animator(glad);
animator.start();
}
}
System.err.println("**** Pre Shell Open");
dsc.display.syncExec( new Runnable() {
public void run() {
dsc.shell.setText( "NewtCanvasSWT Resize Bug Demo" ) ;
dsc.shell.setSize( 400, 450 ) ;
dsc.shell.open() ;
} } );
System.err.println("**** Post Shell Open");
shallStop = false;
final int[] counterBeforeExit = new int[] { 0 /* SWT */, 0 /* NEWT */ };
final AsyncExecEDTFeederThread asyncExecFeeder;
{
asyncExecFeeder = new AsyncExecEDTFeederThread(dsc.display, newtDisplay) ;
asyncExecFeeder.start() ;
}
{
final Thread t = new InterruptSource.Thread(null, new Runnable() {
@Override
public void run() {
try {
Thread.sleep(duration);
} catch (final InterruptedException e) {}
counterBeforeExit[0] = getSWTCount();
counterBeforeExit[1] = getNEWTCount();
asyncExecFeeder.shallStop = true;
try
{
asyncExecFeeder.join();
} catch( final InterruptedException e ) { }
shallStop = true;
dsc.display.wake();
} } );
t.setDaemon(true);
t.start();
}
try {
final Display d = dsc.display;
while( !shallStop && !d.isDisposed() ) {
if( !d.readAndDispatch() && !shallStop ) {
// blocks on linux .. dsc.display.sleep();
Thread.sleep(10);
}
}
} catch (final Exception e0) {
e0.printStackTrace();
Assert.assertTrue("Deadlock @ dispatch: "+e0, false);
}
// canvas is disposed implicit, due to it's disposed listener !
dsc.dispose();
System.err.println("EDT Counter before exit: SWT " + counterBeforeExit[0] + ", NEWT "+counterBeforeExit[1]);
Assert.assertTrue("SWT EDT Counter not greater zero before dispose!", 0 < counterBeforeExit[0]);
if( null != newtDisplay ) {
Assert.assertTrue("NEWT EDT Counter not greater zero before dispose!", 0 < counterBeforeExit[1]);
}
}
@Test
public void test01JOGLGLCanvas() throws InterruptedException, InvocationTargetException {
testImpl(true /* useJOGLGLCanvas */, false /* useNewtCanvasSWT */, false /* glWindowPreVisible */);
}
@Test
public void test02NewtCanvasSWTSimple() throws InterruptedException, InvocationTargetException {
testImpl(false /* useJOGLGLCanvas */, true /* useNewtCanvasSWT */, false /* glWindowPreVisible */);
}
@Test
public void test02NewtCanvasSWTPreVisible() throws InterruptedException, InvocationTargetException {
testImpl(false /* useJOGLGLCanvas */, true /* useNewtCanvasSWT */, true /* glWindowPreVisible */);
}
public static void main( final String[] args ) {
for(int i=0; i<args.length; i++) {
if(args[i].equals("-time")) {
duration = MiscUtils.atoi(args[++i], duration);
} else if(args[i].equals("-anim")) {
useAnimator = true;
}
}
System.out.println("durationPerTest: "+duration);
org.junit.runner.JUnitCore.main(TestSWTBug643AsyncExec.class.getName());
}
}