Jogamp
JOGL/NEWT: Introduce WindowClosingProtocol (solves Bug/Request 444)
authorSven Gothel <sgothel@jausoft.com>
Sun, 19 Dec 2010 13:54:08 +0000 (14:54 +0100)
committerSven Gothel <sgothel@jausoft.com>
Sun, 19 Dec 2010 13:54:08 +0000 (14:54 +0100)
Similar to JFrame's closing behavior,
the following components window closing follow the new WindowClosingProtocol:
   - GLCanvas
   - GLJPanel
   - NEWT Window, GLWindow
   - NEWT NewtCanvasAWT

The implementation obeys either
 1) the user value set by this interface,
 2) an underlying toolkit set user value (JFrame, ..)
 3) or it's default, eg. {@link #DO_NOTHING_ON_CLOSE DO_NOTHING_ON_CLOSE} within an AWT environment.

If none of the above determines the operation,
this protocol default behavior {@link #DISPOSE_ON_CLOSE DISPOSE_ON_CLOSE} shall be used.

21 files changed:
make/build-test.xml
make/scripts/tests.sh
src/jogl/classes/com/jogamp/opengl/impl/awt/AWTUtil.java
src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
src/nativewindow/classes/com/jogamp/nativewindow/impl/awt/AWTMisc.java [new file with mode: 0644]
src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTUtil.java
src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java [new file with mode: 0644]
src/nativewindow/classes/javax/media/nativewindow/awt/AWTWindowClosingProtocol.java [new file with mode: 0644]
src/newt/classes/com/jogamp/newt/Window.java
src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
src/test/com/jogamp/newt/impl/WindowImplAccess.java [new file with mode: 0644]
src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java
src/test/com/jogamp/opengl/test/junit/newt/TestRemoteGLWindows01NEWT.java
src/test/com/jogamp/opengl/test/junit/newt/TestRemoteWindow01NEWT.java
src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol01AWT.java [new file with mode: 0644]
src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol02NEWT.java [new file with mode: 0644]
src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol03NewtAWT.java [new file with mode: 0644]
src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java

index 0b0fe16..40bdcf7 100644 (file)
@@ -21,9 +21,9 @@
         <property name="classes"              value="${build.test}/classes" />
         <property name="classes.path"         location="${classes}"/> <!-- absolute path -->
 
+        <property name="java.part.test"       value="com/jogamp/**"/>
         <property name="java.dir.test"        value="com/jogamp/opengl/test"/>
-        <property name="java.part.test"       value="${java.dir.test}/**"/>
-        <property name="java.dir.junit"        value="${java.dir.test}/junit"/>
+        <property name="java.dir.junit"       value="${java.dir.test}/junit"/>
         <property name="java.dir.bugs"        value="${java.dir.test}/bugs"/>
 
         <property name="test.archive.name"    value="${archive.name}-test-results"/>
index f8fd30f..03f3d4b 100644 (file)
@@ -74,8 +74,8 @@ function testawt() {
 #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT $*
 #testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestTransformFeedbackVaryingsBug407NEWT $*
 #testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLSimple01NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteWindow01NEWT -time 1000000
-#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteGLWindows01NEWT -time 1000000
+#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteWindow01NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteGLWindows01NEWT $*
 #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.gears.newt.TestGearsNEWT $*
 #testawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle01NEWT
 #testawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT
@@ -92,7 +92,7 @@ function testawt() {
 #
 # awt (testawt)
 #
-testawt com.jogamp.newt.impl.awt.opengl.VersionApplet $*
+#testawt com.jogamp.newt.impl.awt.opengl.VersionApplet $*
 #testawt javax.media.opengl.awt.GLCanvas $*
 #testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWT01GLn $*
 #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListAWT $*
@@ -128,6 +128,10 @@ testawt com.jogamp.newt.impl.awt.opengl.VersionApplet $*
 #testawt com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $*
 #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $*
 
+#testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol01AWT $*
+#testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT $*
+testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol03NewtAWT $*
+
 #testawt $*
 
 #testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
index 36c0a32..081d1f9 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 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
@@ -38,8 +39,6 @@ package com.jogamp.opengl.impl.awt;
 
 import com.jogamp.nativewindow.impl.jawt.*;
 
-import com.jogamp.opengl.impl.*;
-
 import javax.media.opengl.*;
 
 import java.lang.reflect.*;
index 1329977..9578ce2 100644 (file)
 
 package javax.media.opengl.awt;
 
-import com.jogamp.common.GlueGenVersion;
-import com.jogamp.common.util.VersionUtil;
-import com.jogamp.common.util.locks.RecursiveLock;
-import com.jogamp.nativewindow.NativeWindowVersion;
-import javax.media.opengl.*;
-import javax.media.nativewindow.*;
-import javax.media.nativewindow.awt.*;
-
-import com.jogamp.opengl.impl.*;
-import com.jogamp.opengl.JoglVersion;
+import java.beans.Beans;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import java.awt.Canvas;
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.FontMetrics;
 import java.awt.Frame;
 import java.awt.Graphics;
 import java.awt.GraphicsConfiguration;
 import java.awt.GraphicsDevice;
-import java.awt.Window;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.geom.*;
-import java.beans.*;
-import java.lang.reflect.*;
-import java.security.*;
+import java.awt.geom.Rectangle2D;
+
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.GraphicsConfigurationFactory;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.awt.AWTGraphicsConfiguration;
+import javax.media.nativewindow.awt.AWTGraphicsDevice;
+import javax.media.nativewindow.awt.AWTGraphicsScreen;
+import javax.media.nativewindow.awt.AWTWindowClosingProtocol;
+import com.jogamp.nativewindow.NativeWindowVersion;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesChooser;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.GLRunnable;
+import javax.media.opengl.Threading;
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.impl.Debug;
+import com.jogamp.opengl.impl.GLContextImpl;
+import com.jogamp.opengl.impl.GLDrawableHelper;
+import com.jogamp.opengl.impl.ThreadingImpl;
 
 // FIXME: Subclasses need to call resetGLFunctionAvailability() on their
 // context whenever the displayChanged() function is called on our
@@ -105,7 +129,7 @@ import java.security.*;
  * </ul>
  */
 
-public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
+public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol {
 
   private static final boolean DEBUG;
   private static final GLProfile defaultGLProfile;
@@ -127,6 +151,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
   private GLContext shareWith;  
   private GraphicsDevice device;
 
+  private AWTWindowClosingProtocol awtWindowClosingProtocol =
+          new AWTWindowClosingProtocol(this, new Runnable() {
+                public void run() {
+                    GLCanvas.this.destroy();
+                }
+            });
+
   /** Creates a new GLCanvas component with a default set of OpenGL
       capabilities, using the default OpenGL capabilities selection
       mechanism, on the default screen device. */
@@ -203,33 +234,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     this.device = device;
   }
 
-  protected interface DestroyMethod {
-    public void destroyMethod();
-  }
-
-  /* package private */ final static Object addClosingListener(Component c, final DestroyMethod d) {
-    WindowAdapter cl = null;
-    Window w = getWindow(c);
-    if(null!=w) {
-        cl = new WindowAdapter() {
-                public void windowClosing(WindowEvent e) {
-                  // we have to issue this call rigth away,
-                  // otherwise the window gets destroyed
-                  d.destroyMethod();
-                }
-            };
-        w.addWindowListener(cl);
-    }
-    return cl;
-  }
-
-  private final static Window getWindow(Component c) {
-    while ( c!=null && ! ( c instanceof Window ) ) {
-        c = c.getParent();
-    }
-    return (Window)c;
-  }
-
   /**
    * Overridden to choose a GraphicsConfiguration on a parent container's
    * GraphicsDevice because both devices
@@ -351,8 +355,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     return ( null != drawable ) ? drawable.isRealized() : false;
   }
 
-  private Object closingListener = null;
-  private Object closingListenerLock = new Object();
+  public int getDefaultCloseOperation() {
+      return awtWindowClosingProtocol.getDefaultCloseOperation();
+  }
+
+  public int setDefaultCloseOperation(int op) {
+      return awtWindowClosingProtocol.setDefaultCloseOperation(op);
+  }
 
   public void display() {
     if( !validateGLDrawable() ) {
@@ -360,14 +369,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     }
     maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction,
                                     displayAction);
-    if(null==closingListener) {
-      synchronized(closingListenerLock) {
-        if(null==closingListener) {
-            closingListener=addClosingListener(this, new DestroyMethod() { 
-                        public void destroyMethod() { destroy(); } });
-        }
-      }
-    }
+
+    awtWindowClosingProtocol.addClosingListenerOneShot();
   }
 
   private void dispose(boolean regenerate) {
@@ -564,6 +567,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
         ex1.printStackTrace();
     }
 
+    awtWindowClosingProtocol.removeClosingListener();
+
     if (Beans.isDesignTime()) {
       super.removeNotify();
     } else {
@@ -685,15 +690,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
   }
 
   public NativeSurface getNativeSurface() {
-    return drawable.getNativeSurface();
+    return (null != drawable) ? drawable.getNativeSurface() : null;
   }
 
   public long getHandle() {
-    return drawable.getHandle();
+    return (null != drawable) ? drawable.getHandle() : 0;
   }
 
   public GLDrawableFactory getFactory() {
-    return drawable.getFactory();
+    return (null != drawable) ? drawable.getFactory() : null;
   }
 
   public String toString() {
index 18ebcd1..46c799d 100644 (file)
 
 package javax.media.opengl.awt;
 
-import javax.media.opengl.*;
-import javax.media.nativewindow.*;
-
-import java.awt.*;
-import java.awt.geom.*;
-import java.awt.image.*;
-import java.beans.*;
-import java.nio.*;
-import java.security.*;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.beans.Beans;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
 import javax.swing.JPanel;
+
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.awt.AWTWindowClosingProtocol;
+
+import javax.media.opengl.DefaultGLCapabilitiesChooser;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesChooser;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLPbuffer;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.GLRunnable;
+import javax.media.opengl.Threading;
 import com.jogamp.opengl.util.FBObject;
-import com.jogamp.opengl.impl.*;
-import com.jogamp.opengl.impl.awt.*;
+import com.jogamp.opengl.impl.Debug;
+import com.jogamp.opengl.impl.GLContextImpl;
+import com.jogamp.opengl.impl.GLDrawableFactoryImpl;
+import com.jogamp.opengl.impl.GLDrawableHelper;
+import com.jogamp.opengl.impl.GLDrawableImpl;
+import com.jogamp.opengl.impl.ThreadingImpl;
+import com.jogamp.opengl.impl.awt.Java2D;
+import com.jogamp.opengl.impl.awt.Java2DGLContext;
 
 // FIXME: Subclasses need to call resetGLFunctionAvailability() on their
 // context whenever the displayChanged() function is called on their
@@ -85,7 +123,7 @@ import com.jogamp.opengl.impl.awt.*;
  *  </P>
 */
 
-public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
+public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol {
   private static final boolean DEBUG = Debug.debug("GLJPanel");
   private static final boolean VERBOSE = Debug.verbose();
 
@@ -129,8 +167,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
     !Debug.isPropertyDefined("jogl.gljpanel.noogl", true, localACC);
 
   // For handling reshape events lazily
-  private int reshapeX;
-  private int reshapeY;
+  // private int reshapeX;
+  // private int reshapeY;
   private int reshapeWidth;
   private int reshapeHeight;
 
@@ -139,6 +177,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
   private int viewportX;
   private int viewportY;
 
+  private AWTWindowClosingProtocol awtWindowClosingProtocol =
+          new AWTWindowClosingProtocol(this, new Runnable() {
+                public void run() {
+                    GLJPanel.this.destroy();
+                }
+            });
+
   static {
     // Force eager initialization of part of the Java2D class since
     // otherwise it's likely it will try to be initialized while on
@@ -365,6 +410,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
         Exception ex1 = new Exception("Info: removeNotify - start");
         ex1.printStackTrace();
     }
+
+    awtWindowClosingProtocol.removeClosingListener();
+
     dispose(false);
     if (backend != null) {
       backend.destroy();
@@ -387,8 +435,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
   public void reshape(int x, int y, int width, int height) {
     super.reshape(x, y, width, height);
 
-    reshapeX = x;
-    reshapeY = y;
+    // reshapeX = x;
+    // reshapeY = y;
     reshapeWidth = width;
     reshapeHeight = height;
     handleReshape = true;
@@ -573,17 +621,16 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
       // a different implementation -- try again
     } while (backend == null);
 
-    if(null==closingListener) {
-      synchronized(closingListenerLock) {
-        if(null==closingListener) {
-            closingListener=GLCanvas.addClosingListener(this, new GLCanvas.DestroyMethod() {
-                        public void destroyMethod() { destroy(); } });
-        }
-      }
-    }
+    awtWindowClosingProtocol.addClosingListenerOneShot();
+  }
+
+  public int getDefaultCloseOperation() {
+      return awtWindowClosingProtocol.getDefaultCloseOperation();
+  }
+
+  public int setDefaultCloseOperation(int op) {
+      return awtWindowClosingProtocol.setDefaultCloseOperation(op);
   }
-  private Object closingListener = null;
-  private Object closingListenerLock = new Object();
 
   private void handleReshape() {
     panelWidth  = reshapeWidth;
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/awt/AWTMisc.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/awt/AWTMisc.java
new file mode 100644 (file)
index 0000000..c61ae55
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * Copyright 2010 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.nativewindow.impl.awt;
+
+import java.awt.Window;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Frame;
+import javax.swing.JFrame;
+import javax.swing.WindowConstants;
+
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.swing.MenuSelectionManager;
+
+public class AWTMisc {
+
+    public static final JFrame getJFrame(Component c) {
+        while (c != null && !(c instanceof JFrame)) {
+            c = c.getParent();
+        }
+        return (JFrame) c;
+    }
+
+    public static final Frame getFrame(Component c) {
+        while (c != null && !(c instanceof Frame)) {
+            c = c.getParent();
+        }
+        return (Frame) c;
+    }
+
+    public static final Window getWindow(Component c) {
+        while (c != null && !(c instanceof Window)) {
+            c = c.getParent();
+        }
+        return (Window) c;
+    }
+
+    public static final Container getContainer(Component c) {
+        while (c != null && !(c instanceof Container)) {
+            c = c.getParent();
+        }
+        return (Container) c;
+    }
+
+    /**
+     * Issue this when your non AWT toolkit gains focus to clear AWT menu path
+     */
+    public static final void clearAWTMenus() {
+        MenuSelectionManager.defaultManager().clearSelectedPath();
+    }
+
+    public final static int AWT2NWClosingOperation(int awtClosingOperation) {
+        switch (awtClosingOperation) {
+            case WindowConstants.DISPOSE_ON_CLOSE:
+            case WindowConstants.EXIT_ON_CLOSE:
+                return WindowClosingProtocol.DISPOSE_ON_CLOSE;
+            case WindowConstants.DO_NOTHING_ON_CLOSE:
+            case WindowConstants.HIDE_ON_CLOSE:
+                return WindowClosingProtocol.DO_NOTHING_ON_CLOSE;
+            default:
+                throw new NativeWindowException("Unhandled AWT Closing Operation: " + awtClosingOperation);
+        }
+    }
+
+    public final static int getNWClosingOperation(Component c) {
+        JFrame jf = getJFrame(c);
+        int op = (null != jf) ? jf.getDefaultCloseOperation() : WindowConstants.DO_NOTHING_ON_CLOSE ;
+        return AWT2NWClosingOperation(op);
+    }
+}
index 68d6dc2..39816ff 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 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
@@ -38,7 +39,6 @@ package com.jogamp.nativewindow.impl.jawt;
 
 import com.jogamp.nativewindow.impl.*;
 import java.awt.EventQueue;
-import java.awt.Frame;
 
 import javax.media.nativewindow.*;
 
diff --git a/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java b/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java
new file mode 100644 (file)
index 0000000..949aee7
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2010 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 javax.media.nativewindow;
+
+/**
+ * Protocol for handling window closing events.
+ * <p>
+ * The implementation shall obey either the user value set by this interface,<br>
+ * an underlying toolkit set user value or it's default, eg. {@link #DO_NOTHING_ON_CLOSE DO_NOTHING_ON_CLOSE} within an AWT environment.<br>
+ * If none of the above determines the operation,
+ * this protocol default behavior {@link #DISPOSE_ON_CLOSE DISPOSE_ON_CLOSE} shall be used.</p>
+ */
+public interface WindowClosingProtocol {
+    /**
+     * Dispose resources on native window close operation.<br>
+     * This is the default behavior in case no underlying toolkit defines otherwise.
+     */
+    int DISPOSE_ON_CLOSE = 1;
+
+    /**
+     * Do nothing on native window close operation.<br>
+     * This is the default behavior within an AWT environment.
+     */
+    int DO_NOTHING_ON_CLOSE = 0;
+
+    /**
+     * @return the current close operation value
+     * @see #DISPOSE_ON_CLOSE
+     * @see #DO_NOTHING_ON_CLOSE
+     */
+    int getDefaultCloseOperation();
+
+    /**
+     * @param op the new close operation value
+     * @return the previous close operation value
+     * @see #DISPOSE_ON_CLOSE
+     * @see #DO_NOTHING_ON_CLOSE
+     */
+    int setDefaultCloseOperation(int op);
+}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTWindowClosingProtocol.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTWindowClosingProtocol.java
new file mode 100644 (file)
index 0000000..a0e9efa
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * Copyright 2010 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 javax.media.nativewindow.awt;
+
+import java.awt.Component;
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.media.nativewindow.WindowClosingProtocol;
+import com.jogamp.nativewindow.impl.awt.AWTMisc;
+
+public class AWTWindowClosingProtocol implements WindowClosingProtocol {
+
+  private Component comp;
+  private Runnable closingOperation;
+  private volatile boolean closingListenerSet = false;
+  private Object closingListenerLock = new Object();
+  private int defaultCloseOperation = DISPOSE_ON_CLOSE;
+  private boolean defaultCloseOperationSetByUser = false;
+
+  public AWTWindowClosingProtocol(Component comp, Runnable closingOperation) {
+      this.comp = comp;
+      this.closingOperation = closingOperation;
+  }
+
+  class WindowClosingAdapter extends WindowAdapter {
+    public void windowClosing(WindowEvent e) {
+      int op = AWTWindowClosingProtocol.this.getDefaultCloseOperation();
+
+      if( DISPOSE_ON_CLOSE == op ) {
+          // we have to issue this call right away,
+          // otherwise the window gets destroyed
+          closingOperation.run();
+      }
+    }
+  }
+  WindowListener windowClosingAdapter = new WindowClosingAdapter();
+
+  final boolean addClosingListenerImpl() {
+    Window w = AWTMisc.getWindow(comp);
+    if(null!=w) {
+        w.addWindowListener(windowClosingAdapter);
+        return true;
+    }
+    return false;
+  }
+
+  /**
+   * Adds this closing listener to the components Window if exist and only one time.<br>
+   * Hence you may call this method every time to ensure it has been set,
+   * ie in case the Window parent is not available yet.
+   *
+   * @return
+   */
+  public final boolean addClosingListenerOneShot() {
+    if(!closingListenerSet) {
+      synchronized(closingListenerLock) {
+        if(!closingListenerSet) {
+            closingListenerSet=addClosingListenerImpl();
+            return closingListenerSet;
+        }
+      }
+    }
+    return false;
+  }
+
+  public final boolean removeClosingListener() {
+    if(closingListenerSet) {
+      synchronized(closingListenerLock) {
+        if(closingListenerSet) {
+            Window w = AWTMisc.getWindow(comp);
+            if(null!=w) {
+                w.removeWindowListener(windowClosingAdapter);
+                closingListenerSet = false;
+                return true;
+            }
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   *
+   * @return the user set close operation if set by {@link #setDefaultCloseOperation(int) setDefaultCloseOperation(int)},
+   *         otherwise return the AWT/Swing close operation value translated to
+   *         a {@link WindowClosingProtocol} value .
+   */
+  public final int getDefaultCloseOperation() {
+      int op = -1;
+      synchronized(closingListenerLock) {
+        if(defaultCloseOperationSetByUser) {
+          op = defaultCloseOperation;
+        }
+      }
+      if(0 <= op) {
+          return op;
+      }
+      // User didn't determine the behavior, use underlying AWT behavior
+      return AWTMisc.getNWClosingOperation(comp);
+  }
+
+  public final int setDefaultCloseOperation(int op) {
+      synchronized(closingListenerLock) {
+          int _op = defaultCloseOperation;
+          defaultCloseOperation = op;
+          defaultCloseOperationSetByUser = true;
+          return _op;
+      }
+  }
+}
index 99db471..9fe5089 100644 (file)
@@ -36,13 +36,14 @@ import javax.media.nativewindow.CapabilitiesChooser;
 import javax.media.nativewindow.CapabilitiesImmutable;
 import javax.media.nativewindow.NativeWindow;
 import javax.media.nativewindow.SurfaceUpdatedListener;
+import javax.media.nativewindow.WindowClosingProtocol;
 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 {
+public interface Window extends NativeWindow, WindowClosingProtocol {
     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");
index bee8162..18213f9 100644 (file)
@@ -38,21 +38,36 @@ import java.awt.EventQueue;
 import java.awt.Graphics;
 import java.awt.KeyboardFocusManager;
 
-import javax.media.nativewindow.*;
+import javax.media.nativewindow.NativeWindow;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.awt.AWTWindowClosingProtocol;
+import com.jogamp.nativewindow.impl.awt.AWTMisc;
 
 import com.jogamp.newt.event.awt.AWTAdapter;
 import com.jogamp.newt.event.awt.AWTParentWindowAdapter;
 import com.jogamp.newt.event.WindowEvent;
 import com.jogamp.newt.Window;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowListener;
 import com.jogamp.newt.impl.Debug;
+import javax.swing.MenuSelectionManager;
 
-public class NewtCanvasAWT extends java.awt.Canvas {
+public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol {
     public static final boolean DEBUG = Debug.debug("Window");
 
     NativeWindow nativeWindow = null;
     Window newtChild = null;
+    int newtChildCloseOp;
     AWTAdapter awtAdapter = null;
 
+    private AWTWindowClosingProtocol awtWindowClosingProtocol =
+          new AWTWindowClosingProtocol(this, new Runnable() {
+                public void run() {
+                    NewtCanvasAWT.this.destroy();
+                }
+            });
+
     /**
      * Instantiates a NewtCanvas without a NEWT child.<br>
      */
@@ -97,12 +112,18 @@ public class NewtCanvasAWT extends java.awt.Canvas {
     }
     FocusAction focusAction = new FocusAction();
     
+    WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() {
+          public void windowGainedFocus(WindowEvent arg0) {
+                  MenuSelectionManager.defaultManager().clearSelectedPath();
+          }
+    };
+
     /** sets a new NEWT child, provoking reparenting on the NEWT level. */
     public NewtCanvasAWT setNEWTChild(Window child) {
         if(newtChild!=child) {
             newtChild = child;
             if(null!=nativeWindow) {
-                java.awt.Container cont = getContainer(this);
+                java.awt.Container cont = AWTMisc.getContainer(this);
                 // reparent right away, addNotify has been called already
                 reparentWindow( (null!=newtChild) ? true : false, cont );
             }
@@ -119,24 +140,37 @@ public class NewtCanvasAWT extends java.awt.Canvas {
      * or {@link #addNotify()} hasn't been called yet.*/
     public NativeWindow getNativeWindow() { return nativeWindow; }
 
-    void setWindowAdapter(boolean attach) {
+    public int getDefaultCloseOperation() {
+        return awtWindowClosingProtocol.getDefaultCloseOperation();
+    }
+
+    public int setDefaultCloseOperation(int op) {
+        return awtWindowClosingProtocol.setDefaultCloseOperation(op);
+    }
+
+    void configureNewtChild(boolean attach) {
         if(null!=awtAdapter) {
           awtAdapter.removeFrom(this);
           awtAdapter=null;
         }
-        if(attach && null!=newtChild) {
-            awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this);
-        }
-    }
-
-    static java.awt.Container getContainer(java.awt.Component comp) {
-        while( null != comp ) {
-               if( comp instanceof java.awt.Container ) {
-                       return (java.awt.Container) comp;
+        if( null != newtChild ) {
+            if(attach) {
+                awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this);
+                if(newtChild.isValid()) {
+                    newtChild.addWindowListener(clearAWTMenusOnNewtFocus);
+                }
+                newtChild.setFocusAction(focusAction); // enable AWT focus traversal
+                newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingProtocol.DO_NOTHING_ON_CLOSE);
+                awtWindowClosingProtocol.addClosingListenerOneShot();
+            } else {
+                if(newtChild.isValid()) {
+                    newtChild.removeWindowListener(clearAWTMenusOnNewtFocus);
+                }
+                newtChild.setFocusAction(null);
+                newtChild.setDefaultCloseOperation(newtChildCloseOp);
+                awtWindowClosingProtocol.removeClosingListener();
             }
-            comp = comp.getParent();
         }
-        return null;
     }
 
     public void addNotify() {
@@ -150,7 +184,7 @@ public class NewtCanvasAWT extends java.awt.Canvas {
         // after native peer is valid: Windows
         disableBackgroundErase();
 
-        java.awt.Container cont = getContainer(this);
+        java.awt.Container cont = AWTMisc.getContainer(this);
         if(DEBUG) {
             // if ( isShowing() == false ) -> Container was not visible yet.
             // if ( isShowing() == true  ) -> Container is already visible.
@@ -161,7 +195,7 @@ public class NewtCanvasAWT extends java.awt.Canvas {
     }
 
     public void removeNotify() {
-        java.awt.Container cont = getContainer(this);
+        java.awt.Container cont = AWTMisc.getContainer(this);
         if(DEBUG) {
             System.err.println("NewtCanvasAWT.removeNotify: "+newtChild+", from "+cont);
         }
@@ -187,13 +221,12 @@ public class NewtCanvasAWT extends java.awt.Canvas {
               newtChild.setSize(w, h);
               newtChild.reparentWindow(nativeWindow);
               newtChild.setVisible(true);
-              setWindowAdapter(true);
+              configureNewtChild(true);
               newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener
               newtChild.windowRepaint(0, 0, w, h);
-              newtChild.setFocusAction(focusAction); // enable AWT focus traversal
           }
       } else {
-          setWindowAdapter(false);
+          configureNewtChild(false);
           nativeWindow = null;
           newtChild.setVisible(false);
           newtChild.reparentWindow(null);
@@ -213,10 +246,11 @@ public class NewtCanvasAWT extends java.awt.Canvas {
      */
     public final void destroy() {
         if(null!=newtChild) {
-            java.awt.Container cont = getContainer(this);
+            java.awt.Container cont = AWTMisc.getContainer(this);
             if(DEBUG) {
                 System.err.println("NewtCanvasAWT.destroy(): "+newtChild+", from "+cont);
             }
+            configureNewtChild(false);
             nativeWindow = null;
             newtChild.setVisible(false);
             newtChild.reparentWindow(null);
@@ -229,11 +263,13 @@ public class NewtCanvasAWT extends java.awt.Canvas {
     }
 
     public void paint(Graphics g) {
+        awtWindowClosingProtocol.addClosingListenerOneShot();
         if(null!=newtChild) {
             newtChild.windowRepaint(0, 0, getWidth(), getHeight());
         }
     }
     public void update(Graphics g) {
+        awtWindowClosingProtocol.addClosingListenerOneShot();
         if(null!=newtChild) {
             newtChild.windowRepaint(0, 0, getWidth(), getHeight());
         }
index ad11d8a..e04bd12 100644 (file)
@@ -372,6 +372,26 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
     protected void unlockSurfaceImpl() { }
 
     //----------------------------------------------------------------------
+    // WindowClosingProtocol implementation
+    //
+    private Object closingListenerLock = new Object();
+    private int defaultCloseOperation = DISPOSE_ON_CLOSE;
+
+    public int getDefaultCloseOperation() {
+        synchronized (closingListenerLock) {
+            return defaultCloseOperation;
+        }
+    }
+
+    public int setDefaultCloseOperation(int op) {
+        synchronized (closingListenerLock) {
+            int _op = defaultCloseOperation;
+            defaultCloseOperation = op;
+            return _op;
+        }
+    }
+
+    //----------------------------------------------------------------------
     // Window: Native implementation
     //
 
@@ -2101,7 +2121,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
 
         enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY);
 
-        if(handleDestroyNotify && isValid()) {
+        if(handleDestroyNotify && DISPOSE_ON_CLOSE == defaultCloseOperation && isValid()) {
             destroy();
         }
 
index 358a3d4..4a1855d 100644 (file)
@@ -85,24 +85,26 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
                 }
 
                 public void windowDestroyNotify(WindowEvent e) {
-                    // Is an animator thread perform rendering?
-                    if (GLWindow.this.helper.isExternalAnimatorRunning()) {
-                        // Pause animations before initiating safe destroy.
-                        GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator();
-                        boolean isPaused = ctrl.pause();
-                        destroy();
-                        if(isPaused) {
-                            ctrl.resume();
+                    if( DISPOSE_ON_CLOSE == GLWindow.this.getDefaultCloseOperation() ) {
+                        // Is an animator thread perform rendering?
+                        if (GLWindow.this.helper.isExternalAnimatorRunning()) {
+                            // Pause animations before initiating safe destroy.
+                            GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator();
+                            boolean isPaused = ctrl.pause();
+                            destroy();
+                            if(isPaused) {
+                                ctrl.resume();
+                            }
+                        } else if (GLWindow.this.window.isSurfaceLockedByOtherThread()) {
+                            // Surface is locked by another thread
+                            // Flag that destroy should be performed on the next
+                            // attempt to display.
+                            sendDestroy = true;
+                        } else {
+                            // Without an external thread animating or locking the
+                            // surface, we are safe.
+                            destroy ();
                         }
-                    } else if (GLWindow.this.window.isSurfaceLockedByOtherThread()) {
-                        // Surface is locked by another thread
-                        // Flag that destroy should be performed on the next
-                        // attempt to display.
-                        sendDestroy = true;
-                    } else {
-                        // Without an external thread animating or locking the
-                        // surface, we are safe.
-                        destroy ();
                     }
                 }
             });
@@ -152,6 +154,17 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer {
     }
 
     //----------------------------------------------------------------------
+    // WindowClosingProtocol implementation
+    //
+    public int getDefaultCloseOperation() {
+        return window.getDefaultCloseOperation();
+    }
+
+    public int setDefaultCloseOperation(int op) {
+        return window.setDefaultCloseOperation(op);
+    }
+
+    //----------------------------------------------------------------------
     // Window Access
     //
 
diff --git a/src/test/com/jogamp/newt/impl/WindowImplAccess.java b/src/test/com/jogamp/newt/impl/WindowImplAccess.java
new file mode 100644 (file)
index 0000000..5a90c80
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2010 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.impl;
+
+import com.jogamp.newt.Window;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ * Allows access to protected methods of WindowImpl
+ */
+public class WindowImplAccess {
+    public static final void windowDestroyNotify(Window win) {
+        WindowImpl winImpl = null;
+        if(win instanceof GLWindow) {
+            GLWindow glwin = (GLWindow) win;
+            winImpl = (WindowImpl) glwin.getWindow();
+        } else if(win instanceof WindowImpl) {
+            winImpl = (WindowImpl) win;
+        } else {
+            throw new RuntimeException("Given Window not a GLWindow, not WindowImpl, but "+win.getClass());
+        }
+        winImpl.windowDestroyNotify();
+    }
+}
+
+
index 8cad4f0..509a0af 100644 (file)
@@ -45,6 +45,7 @@ import com.jogamp.newt.awt.NewtCanvasAWT;
 import com.jogamp.newt.event.WindowAdapter;
 import com.jogamp.newt.event.WindowEvent;
 import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
 import com.jogamp.opengl.test.junit.util.UITestCase;
 
 public class TestCloseNewtAWT extends UITestCase {
@@ -124,11 +125,7 @@ public class TestCloseNewtAWT extends UITestCase {
         });
         Thread.sleep(1000);
 
-        // programatically issue windowClosing
-        Toolkit tk = Toolkit.getDefaultToolkit();
-        EventQueue evtQ = tk.getSystemEventQueue();
-        evtQ.postEvent(new java.awt.event.WindowEvent(frame, java.awt.event.WindowEvent.WINDOW_CLOSING));
-        Thread.sleep(200);            
+        AWTRobotUtil.closeWindow(frame);
 
         GLProfile.shutdown();
     }
index 96ea861..6b501e3 100644 (file)
@@ -49,6 +49,7 @@ public class TestRemoteGLWindows01NEWT extends UITestCase {
     static GLProfile glp;
     static int width, height;
     static long durationPerTest = 100; // ms
+    static String remoteDisplay = "nowhere:0.0";
 
     @BeforeClass
     public static void initClass() {
@@ -59,7 +60,7 @@ public class TestRemoteGLWindows01NEWT extends UITestCase {
         glp = GLProfile.getDefault();
     }
 
-    static GLWindow createWindow(Screen screen, GLCapabilities caps)
+    static GLWindow createWindow(Screen screen, GLCapabilities caps, GLEventListener demo)
         throws InterruptedException
     {
         Assert.assertNotNull(caps);
@@ -74,8 +75,7 @@ public class TestRemoteGLWindows01NEWT extends UITestCase {
             glWindow = GLWindow.create(caps);
             Assert.assertNotNull(glWindow);
         }
-
-        GLEventListener demo = new Gears();
+        
         glWindow.addGLEventListener(demo);
 
         glWindow.setSize(512, 512);
@@ -96,42 +96,49 @@ public class TestRemoteGLWindows01NEWT extends UITestCase {
 
     @Test
     public void testRemoteWindow01() throws InterruptedException {
+        Animator animator = new Animator();
         GLCapabilities caps = new GLCapabilities(glp);
         Assert.assertNotNull(caps);
-        GLWindow window1 = createWindow(null, caps); // local
+        GLWindow window1 = createWindow(null, caps, new Gears(1)); // local with vsync
         Assert.assertEquals(true,window1.isNativeValid());
         Assert.assertEquals(true,window1.isVisible());
         AbstractGraphicsDevice device1 = window1.getScreen().getDisplay().getGraphicsDevice();
 
         System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1));
 
-        Animator animator1 = new Animator(window1);
-        animator1.start();
+        animator.add(window1);
 
+        // Remote Display/Device/Screen/Window ..
         // Eager initialization of NEWT Display -> AbstractGraphicsDevice -> GLProfile (device)
-        Display display2 = NewtFactory.createDisplay("charelle:0.0"); // remote display
+        Display display2; // remote display
+        AbstractGraphicsDevice device2;
+        Screen screen2;
+        GLWindow window2;
         try {
-            display2.createNative(); 
+            display2 = NewtFactory.createDisplay(remoteDisplay); // remote display
+            display2.createNative();
+            System.err.println(display2);
+            device2 = display2.getGraphicsDevice();
+            System.err.println(device2);
+            GLProfile.initProfiles(device2); // just to make sure
+            System.err.println("");
+            System.err.println("GLProfiles window2: "+device2.getConnection()+": "+GLProfile.glAvailabilityToString(device2));
+            screen2  = NewtFactory.createScreen(display2, 0); // screen 0
+            window2 = createWindow(screen2, caps, new Gears(0)); // remote, no vsync
         } catch (NativeWindowException nwe) {
             System.err.println(nwe);
             Assume.assumeNoException(nwe);
             destroyWindow(window1);
             return;
         }
-        AbstractGraphicsDevice device2 = display2.getGraphicsDevice();
-        GLProfile.initProfiles(device2); // just to make sure
-        System.err.println("");
-        System.err.println("GLProfiles window2: "+device2.getConnection()+": "+GLProfile.glAvailabilityToString(device2));
 
-        Screen screen2  = NewtFactory.createScreen(display2, 0); // screen 0
-        GLWindow window2 = createWindow(screen2, caps); // remote
         Assert.assertEquals(true,window2.isNativeValid());
         Assert.assertEquals(true,window2.isVisible());
 
-        Animator animator2 = new Animator(window2);
-        animator2.start();
+        animator.add(window2);
+        animator.start();
 
-        for(int state=0; state*100<durationPerTest; state++) {
+        while(animator.getDuration()<durationPerTest) {
             Thread.sleep(100);
         }
 
@@ -151,9 +158,12 @@ public class TestRemoteGLWindows01NEWT extends UITestCase {
         for(int i=0; i<args.length; i++) {
             if(args[i].equals("-time")) {
                 durationPerTest = atoi(args[++i]);
+            } else if(args[i].equals("-display")) {
+                remoteDisplay = args[++i];
             }
         }
         System.out.println("durationPerTest: "+durationPerTest);
+        System.out.println("display: "+remoteDisplay);
         String tstname = TestRemoteGLWindows01NEWT.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
index f0cd3b8..9c44545 100644 (file)
@@ -43,6 +43,7 @@ import com.jogamp.opengl.test.junit.util.UITestCase;
 
 public class TestRemoteWindow01NEWT extends UITestCase {
     static int width, height;
+    static String remoteDisplay = "nowhere:0.0";
 
     @BeforeClass
     public static void initClass() {
@@ -109,18 +110,23 @@ public class TestRemoteWindow01NEWT extends UITestCase {
         Assert.assertEquals(true,window1.isNativeValid());
         Assert.assertEquals(true,window1.isVisible());
 
-        Display display2 = NewtFactory.createDisplay("charelle:0.0"); // remote display
+        // Remote Display/Device/Screen/Window ..
+        Display display2;
+        AbstractGraphicsDevice device2;
+        Screen screen2;
+        Window window2;
         try {
+            display2 = NewtFactory.createDisplay(remoteDisplay);
             display2.createNative(); 
+            screen2  = NewtFactory.createScreen(display2, 0); // screen 0
+            window2 = createWindow(screen2, caps, width, height, true /* onscreen */, false /* undecorated */);
+            window2.setVisible(true);
         } catch (NativeWindowException nwe) {
             System.err.println(nwe);
             Assume.assumeNoException(nwe);
             destroyWindow(display1, screen1, window1);
             return;
         }
-        Screen screen2  = NewtFactory.createScreen(display2, 0); // screen 0
-        Window window2 = createWindow(screen2, caps, width, height, true /* onscreen */, false /* undecorated */);
-        window2.setVisible(true);
 
         Assert.assertEquals(true,window2.isNativeValid());
         Assert.assertEquals(true,window2.isVisible());
@@ -132,6 +138,12 @@ public class TestRemoteWindow01NEWT extends UITestCase {
     }
 
     public static void main(String args[]) throws IOException {
+        for(int i=0; i<args.length; i++) {
+            if(args[i].equals("-display")) {
+                remoteDisplay = args[++i];
+            }
+        }
+        System.out.println("display: "+remoteDisplay);
         String tstname = TestRemoteWindow01NEWT.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol01AWT.java
new file mode 100644 (file)
index 0000000..c7ac009
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * Copyright 2010 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.newt;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.awt.Frame;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+import javax.media.nativewindow.WindowClosingProtocol;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.awt.GLCanvas;
+
+import com.jogamp.opengl.test.junit.jogl.demos.gl2.gears.Gears;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+public class TestWindowClosingProtocol01AWT extends UITestCase {
+
+    @Test
+    public void testCloseFrameGLCanvas() throws InterruptedException, InvocationTargetException {
+        final Frame frame = new Frame("testCloseFrameGLCanvas AWT");
+
+        GLProfile glp = GLProfile.getDefault();
+        GLCapabilities caps = new GLCapabilities(glp);
+        GLCanvas glCanvas = new GLCanvas(caps);
+        glCanvas.addGLEventListener(new Gears());
+        frame.add(glCanvas);
+        frame.pack();
+        frame.setSize(512, 512);
+        frame.validate();
+        frame.setVisible(true);
+        Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
+
+        //
+        // close with op: DO_NOTHING_ON_CLOSE -> NOP (default)
+        //
+        int op = glCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DO_NOTHING_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(true, frame.isVisible());
+        Assert.assertEquals(true, frame.isDisplayable());
+        Assert.assertEquals(true, glCanvas.isValid());
+        Assert.assertEquals(true, glCanvas.isVisible());
+        Assert.assertEquals(true, glCanvas.isDisplayable());
+
+        //
+        // close with op (GLCanvas): DISPOSE_ON_CLOSE -> dispose
+        //
+        glCanvas.setDefaultCloseOperation(WindowClosingProtocol.DISPOSE_ON_CLOSE);
+        op = glCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DISPOSE_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(true,  frame.isVisible());
+        Assert.assertEquals(true,  frame.isDisplayable());
+        Assert.assertEquals(false, glCanvas.isValid());
+        Assert.assertEquals(true,  glCanvas.isVisible());
+        Assert.assertEquals(false, glCanvas.isDisplayable());
+
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                frame.dispose();
+            } });
+    }
+
+    @Test
+    public void testCloseJFrameGLCanvas() throws InterruptedException, InvocationTargetException {
+        final JFrame frame = new JFrame("testCloseJFrameGLCanvas AWT");
+
+        GLProfile glp = GLProfile.getDefault();
+        GLCapabilities caps = new GLCapabilities(glp);
+        GLCanvas glCanvas = new GLCanvas(caps);
+        glCanvas.addGLEventListener(new Gears());
+        frame.getContentPane().add(glCanvas);
+        frame.pack();
+        frame.setSize(512, 512);
+        frame.validate();
+        frame.setVisible(true);
+        Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
+
+        //
+        // close with op: DO_NOTHING_ON_CLOSE -> NOP / HIDE (default)
+        //
+        Assert.assertEquals(JFrame.HIDE_ON_CLOSE, frame.getDefaultCloseOperation());
+        int op = glCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DO_NOTHING_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(false, frame.isVisible());
+        Assert.assertEquals(true,  frame.isDisplayable());
+        Assert.assertEquals(true,  glCanvas.isValid());
+        Assert.assertEquals(true,  glCanvas.isVisible());
+        Assert.assertEquals(true,  glCanvas.isDisplayable());
+
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                frame.setVisible(true);
+            } });
+        Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
+
+        //
+        // close with op (JFrame): DISPOSE_ON_CLOSE -- GLCanvas --> dispose
+        //
+        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        Assert.assertEquals(JFrame.DISPOSE_ON_CLOSE, frame.getDefaultCloseOperation());
+        op = glCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DISPOSE_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(false, frame.isVisible());
+        Assert.assertEquals(false, frame.isDisplayable());
+        Assert.assertEquals(false, glCanvas.isValid());
+        Assert.assertEquals(true,  glCanvas.isVisible());
+        Assert.assertEquals(false, glCanvas.isDisplayable());
+    }
+
+    public static void main(String[] args) {
+        String tstname = TestWindowClosingProtocol01AWT.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol02NEWT.java
new file mode 100644 (file)
index 0000000..f9a6003
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * Copyright 2010 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.newt;
+
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import javax.media.nativewindow.WindowClosingProtocol;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.newt.opengl.GLWindow;
+
+import com.jogamp.opengl.test.junit.jogl.demos.gl2.gears.Gears;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+public class TestWindowClosingProtocol02NEWT extends UITestCase {
+
+    static class NEWTWindowClosingAdapter extends WindowAdapter {
+        volatile boolean windowDestroyNotifyReached = false;
+
+        public void reset() {
+            windowDestroyNotifyReached = false;
+        }
+        public boolean windowDestroyNotifyReached() {
+            return windowDestroyNotifyReached;
+        }
+        public void windowDestroyNotify(WindowEvent e) {
+            windowDestroyNotifyReached = true;
+        }
+    }
+
+    @Test
+    public void testCloseGLWindow() throws InterruptedException, InvocationTargetException {
+        GLProfile glp = GLProfile.getDefault();
+        GLCapabilities caps = new GLCapabilities(glp);
+        final GLWindow glWindow = GLWindow.create(caps);
+        final NEWTWindowClosingAdapter newtWindowClosingAdapter = new NEWTWindowClosingAdapter();
+
+        glWindow.addWindowListener(newtWindowClosingAdapter);
+        glWindow.addGLEventListener(new Gears());
+        glWindow.setSize(512, 512);
+        glWindow.setVisible(true);
+        Assert.assertEquals(true, glWindow.isVisible());
+
+        // CHECK DEFAULT ..
+        int op = glWindow.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DISPOSE_ON_CLOSE, op);
+
+        //
+        // close with op: DO_NOTHING_ON_CLOSE -> NOP
+        //
+        glWindow.setDefaultCloseOperation(WindowClosingProtocol.DO_NOTHING_ON_CLOSE);
+        op = glWindow.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DO_NOTHING_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(glWindow);
+        Assert.assertEquals(true, glWindow.isValid());
+        Assert.assertEquals(true, glWindow.isVisible());        
+        Assert.assertEquals(true, glWindow.isNativeValid());
+        Assert.assertEquals(true, newtWindowClosingAdapter.windowDestroyNotifyReached());
+        newtWindowClosingAdapter.reset();
+
+        //
+        // close with op (GLCanvas): DISPOSE_ON_CLOSE -> dispose
+        //
+        glWindow.setDefaultCloseOperation(WindowClosingProtocol.DISPOSE_ON_CLOSE);
+        op = glWindow.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DISPOSE_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(glWindow);
+        Assert.assertEquals(true,  AWTRobotUtil.waitForVisible(glWindow, false));
+        Assert.assertEquals(true,  glWindow.isValid());
+        Assert.assertEquals(false, glWindow.isVisible());        
+        Assert.assertEquals(false, glWindow.isNativeValid());
+        Assert.assertEquals(true,  newtWindowClosingAdapter.windowDestroyNotifyReached());
+    }
+
+    public static void main(String[] args) {
+        String tstname = TestWindowClosingProtocol02NEWT.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol03NewtAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindowClosingProtocol03NewtAWT.java
new file mode 100644 (file)
index 0000000..e69aae9
--- /dev/null
@@ -0,0 +1,140 @@
+/**
+ * Copyright 2010 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.newt;
+
+import com.jogamp.newt.awt.NewtCanvasAWT;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import org.junit.Test;
+import org.junit.Assert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.awt.Frame;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+import javax.media.nativewindow.WindowClosingProtocol;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.awt.GLCanvas;
+
+import com.jogamp.opengl.test.junit.jogl.demos.gl2.gears.Gears;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+public class TestWindowClosingProtocol03NewtAWT extends UITestCase {
+
+    static class NEWTWindowClosingAdapter extends WindowAdapter {
+        volatile boolean windowDestroyNotifyReached = false;
+
+        public void reset() {
+            windowDestroyNotifyReached = false;
+        }
+        public boolean windowDestroyNotifyReached() {
+            return windowDestroyNotifyReached;
+        }
+        public void windowDestroyNotify(WindowEvent e) {
+            windowDestroyNotifyReached = true;
+        }
+    }
+
+    @Test
+    public void testCloseJFrameNewtCanvasAWT() throws InterruptedException, InvocationTargetException {
+        final JFrame frame = new JFrame("testCloseJFrameNewtCanvasAWT");
+
+        GLProfile glp = GLProfile.getDefault();
+        GLCapabilities caps = new GLCapabilities(glp);
+        final GLWindow glWindow = GLWindow.create(caps);
+        final NEWTWindowClosingAdapter newtWindowClosingAdapter = new NEWTWindowClosingAdapter();
+
+        glWindow.addWindowListener(newtWindowClosingAdapter);
+        glWindow.addGLEventListener(new Gears());
+
+        NewtCanvasAWT newtCanvas = new NewtCanvasAWT(glWindow);
+
+        frame.getContentPane().add(newtCanvas);
+        frame.pack();
+        frame.setSize(512, 512);
+        frame.validate();
+        frame.setVisible(true);
+        Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
+
+        //
+        // close with op: DO_NOTHING_ON_CLOSE -> NOP / HIDE (default)
+        //
+        Assert.assertEquals(JFrame.HIDE_ON_CLOSE, frame.getDefaultCloseOperation());
+        int op = newtCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DO_NOTHING_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(false, frame.isVisible());
+        Assert.assertEquals(true,  frame.isDisplayable());
+        Assert.assertEquals(true,  newtCanvas.isValid());
+        Assert.assertEquals(true,  newtCanvas.isVisible());
+        Assert.assertEquals(true,  newtCanvas.isDisplayable());
+        Assert.assertEquals(true,  glWindow.isValid());
+        Assert.assertEquals(false, glWindow.isVisible());
+        Assert.assertEquals(true,  glWindow.isNativeValid());
+        Assert.assertEquals(true,  newtWindowClosingAdapter.windowDestroyNotifyReached());
+        newtWindowClosingAdapter.reset();
+
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                frame.setVisible(true);
+            } });
+        Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
+
+        //
+        // close with op (JFrame): DISPOSE_ON_CLOSE -- newtCanvas -- glWindow --> dispose
+        //
+        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        Assert.assertEquals(JFrame.DISPOSE_ON_CLOSE, frame.getDefaultCloseOperation());
+        op = newtCanvas.getDefaultCloseOperation();
+        Assert.assertEquals(WindowClosingProtocol.DISPOSE_ON_CLOSE, op);
+
+        AWTRobotUtil.closeWindow(frame);
+        Assert.assertEquals(false, frame.isVisible());
+        Assert.assertEquals(false, frame.isDisplayable());
+        Assert.assertEquals(false, newtCanvas.isValid());
+        Assert.assertEquals(true,  newtCanvas.isVisible());
+        Assert.assertEquals(false, newtCanvas.isDisplayable());
+        Assert.assertEquals(true,  glWindow.isValid());
+        Assert.assertEquals(false, glWindow.isVisible());
+        Assert.assertEquals(false, glWindow.isNativeValid());
+        Assert.assertEquals(true,  newtWindowClosingAdapter.windowDestroyNotifyReached());
+    }
+
+    public static void main(String[] args) {
+        String tstname = TestWindowClosingProtocol03NewtAWT.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+
+}
index 61aa95b..9812be5 100644 (file)
  
 package com.jogamp.opengl.test.junit.util;
 
+import com.jogamp.newt.impl.WindowImplAccess;
 import java.lang.reflect.InvocationTargetException;
 import java.awt.AWTException;
 import java.awt.Component;
 import java.awt.Container;
+import java.awt.EventQueue;
 import java.awt.KeyboardFocusManager;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.Robot;
-import java.awt.Window;
+import java.awt.Toolkit;
 import java.awt.event.InputEvent;
 import javax.swing.JFrame;
 
@@ -92,7 +94,7 @@ public class AWTRobotUtil {
      *
      * @return True if the Window became the global focused Window within TIME_OUT
      */
-    public static boolean toFront(Robot robot, Window window) 
+    public static boolean toFront(Robot robot, final java.awt.Window window)
         throws AWTException, InterruptedException, InvocationTargetException {
 
         if(null == robot) {
@@ -104,12 +106,11 @@ public class AWTRobotUtil {
         robot.mouseMove( (int) p0.getX(), (int) p0.getY() );
         robot.delay(ROBOT_DELAY);
 
-        final Window f_window = window;
         javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
             public void run() {
-                f_window.setVisible(true);
-                f_window.toFront();
-                f_window.requestFocus();
+                window.setVisible(true);
+                window.toFront();
+                window.requestFocus();
             }});
         robot.delay(ROBOT_DELAY);
 
@@ -126,22 +127,12 @@ public class AWTRobotUtil {
      */
     public static void centerMouse(Robot robot, Object obj) 
         throws AWTException, InterruptedException, InvocationTargetException {
-        Component comp = null;
-        com.jogamp.newt.Window win = null;
 
         if(null == robot) {
             robot = new Robot();
             robot.setAutoWaitForIdle(true);
         }
 
-        if(obj instanceof com.jogamp.newt.Window) {
-            win = (com.jogamp.newt.Window) obj;
-        } else if(obj instanceof Component) {
-            comp = (Component) obj;
-        } else {
-            throw new RuntimeException("Neither AWT nor NEWT: "+obj);
-        }
-
         Point p0 = getCenterLocation(obj, false);
         System.err.println("robot pos: "+p0);
 
@@ -334,5 +325,45 @@ public class AWTRobotUtil {
         return false;
     }
 
+    /**
+     *
+     * @return True if the Component becomes <code>visible</code> within TIME_OUT
+     */
+    public static boolean waitForVisible(Object obj, boolean visible) throws InterruptedException {
+        int wait;
+        if(obj instanceof Component) {
+            Component comp = (Component) obj;
+            for (wait=0; wait<POLL_DIVIDER && visible != comp.isVisible(); wait++) {
+                Thread.sleep(TIME_OUT/POLL_DIVIDER);
+            }
+        } else if(obj instanceof com.jogamp.newt.Window) {
+            com.jogamp.newt.Window win = (com.jogamp.newt.Window) obj;
+            for (wait=0; wait<POLL_DIVIDER && visible != win.isVisible(); wait++) {
+                Thread.sleep(TIME_OUT/POLL_DIVIDER);
+            }
+        } else {
+            throw new RuntimeException("Neither AWT nor NEWT: "+obj);
+        }
+        return wait<POLL_DIVIDER;
+    }
+
+    /**
+     * Programmatically issue windowClosing on AWT or NEWT
+     *
+     * @param obj either an AWT Window (Frame, JFrame) or NEWT Window
+     * @throws InterruptedException
+     */
+    public static void closeWindow(Object obj) throws InterruptedException {
+        if(obj instanceof java.awt.Window) {
+            java.awt.Window win = (java.awt.Window) obj;
+            Toolkit tk = Toolkit.getDefaultToolkit();
+            EventQueue evtQ = tk.getSystemEventQueue();
+            evtQ.postEvent(new java.awt.event.WindowEvent(win, java.awt.event.WindowEvent.WINDOW_CLOSING));
+        } else if(obj instanceof com.jogamp.newt.Window) {
+            com.jogamp.newt.Window win = (com.jogamp.newt.Window) obj;
+            WindowImplAccess.windowDestroyNotify(win);
+        }
+        Thread.sleep(200);
+    }
 }
 
http://JogAmp.org git info: FAQ, tutorial and man pages.