Jogamp
NewtVersionActivity: Remove 'gears' test; Version Info: Drop NativeWindow/Newt Versio...
[jogl.git] / src / jogl / classes / javax / media / opengl / awt / GLCanvas.java
index 265c7ff..d861bd7 100644 (file)
 
 package javax.media.opengl.awt;
 
-import com.jogamp.common.GlueGenVersion;
-import com.jogamp.common.util.VersionUtil;
-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 java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+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 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.nativewindow.NativeWindowVersion;
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.opengl.JoglVersion;
+
+import com.jogamp.common.util.locks.RecursiveLock;
+import jogamp.opengl.Debug;
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.GLDrawableHelper;
+import jogamp.opengl.ThreadingImpl;
 
 // FIXME: Subclasses need to call resetGLFunctionAvailability() on their
 // context whenever the displayChanged() function is called on our
 // GLEventListeners
 
 /** A heavyweight AWT component which provides OpenGL rendering
-    support. This is the primary implementation of {@link GLDrawable};
+    support. This is the primary implementation of an AWT {@link GLDrawable};
     {@link GLJPanel} is provided for compatibility with Swing user
     interfaces when adding a heavyweight doesn't work either because
-    of Z-ordering or LayoutManager problems. */
+    of Z-ordering or LayoutManager problems.
+ *
+ * <h5><A NAME="java2dgl">Java2D OpenGL Remarks</A></h5>
+ *
+ * To avoid any conflicts with a potential Java2D OpenGL context,<br>
+ * you shall consider setting the following JVM properties:<br>
+ * <ul>
+ *    <li><pre>sun.java2d.opengl=false</pre></li>
+ *    <li><pre>sun.java2d.noddraw=true</pre></li>
+ * </ul>
+ * This is especially true in case you want to utilize a GLProfile other than
+ * {@link GLProfile#GL2}, eg. using {@link GLProfile#getMaxFixedFunc()}.<br>
+ * On the other hand, if you like to experiment with GLJPanel's utilization
+ * of Java2D's OpenGL pipeline, you have to set them to
+ * <ul>
+ *    <li><pre>sun.java2d.opengl=true</pre></li>
+ *    <li><pre>sun.java2d.noddraw=true</pre></li>
+ * </ul>
+ *
+ * <h5><A NAME="backgrounderase">Disable Background Erase</A></h5>
+ *
+ * GLCanvas tries to disable background erase for the AWT Canvas
+ * before native peer creation (X11) and after it (Windows), <br>
+ * utilizing the optional {@link java.awt.Toolkit} method <code>disableBeackgroundErase(java.awt.Canvas)</code>.<br>
+ * However if this does not give you the desired results, you may want to disable AWT background erase in general:
+ * <ul>
+ *   <li><pre>sun.awt.noerasebackground=true</pre></li>
+ * </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;
 
   static {
       DEBUG = Debug.debug("GLCanvas");
-      defaultGLProfile = GLProfile.getDefault(GLProfile.getDefaultDesktopDevice());
   }
 
-  private GLProfile glProfile;
   private GLDrawableHelper drawableHelper = new GLDrawableHelper();
-  private GraphicsConfiguration chosen;
   private AWTGraphicsConfiguration awtConfig;
   private GLDrawable drawable;
   private GLContextImpl context;
   private boolean sendReshape = false;
   
-  // copy of the cstr args ..
+  // copy of the cstr args, mainly for recreation
+  private GLCapabilitiesImmutable capsReqUser;
   private GLCapabilitiesChooser chooser;
   private GLContext shareWith;
+  private int additionalCtxCreationFlags = 0;  
+  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. */
-  public GLCanvas() {
+      mechanism, on the default screen device. 
+   * @throws GLException if no default profile is available for the default desktop device.
+   */
+  public GLCanvas() throws GLException {
     this(null);
   }
 
   /** Creates a new GLCanvas component with the requested set of
       OpenGL capabilities, using the default OpenGL capabilities
-      selection mechanism, on the default screen device. */
-  public GLCanvas(GLCapabilitiesImmutable capsReqUser) {
+      selection mechanism, on the default screen device. 
+   * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+   * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice)
+   */
+  public GLCanvas(GLCapabilitiesImmutable capsReqUser) throws GLException {
     this(capsReqUser, null, null, null);
   }
 
+  /** Creates a new GLCanvas component with the requested set of
+      OpenGL capabilities, using the default OpenGL capabilities
+      selection mechanism, on the default screen device.
+   *  This constructor variant also supports using a shared GLContext.
+   *
+   * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+   * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice)
+   */
+  public GLCanvas(GLCapabilitiesImmutable capsReqUser, GLContext shareWith) 
+          throws GLException 
+  {
+    this(capsReqUser, null, shareWith, null);
+  }
+
   /** Creates a new GLCanvas component. The passed GLCapabilities
       specifies the OpenGL capabilities for the component; if null, a
       default set of capabilities is used. The GLCapabilitiesChooser
@@ -126,11 +210,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
       sharing</a>. The passed GraphicsDevice indicates the screen on
       which to create the GLCanvas; the GLDrawableFactory uses the
       default screen device of the local GraphicsEnvironment if null
-      is passed for this argument. */
+      is passed for this argument. 
+   * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+   */
   public GLCanvas(GLCapabilitiesImmutable capsReqUser,
                   GLCapabilitiesChooser chooser,
                   GLContext shareWith,
-                  GraphicsDevice device) {
+                  GraphicsDevice device) 
+      throws GLException 
+  {
     /*
      * Determination of the native window is made in 'super.addNotify()',
      * which creates the native peer using AWT's GraphicsConfiguration.
@@ -141,7 +229,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     super();
 
     if(null==capsReqUser) {
-        capsReqUser = new GLCapabilities(defaultGLProfile);
+        capsReqUser = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()));
     } else {
         // don't allow the user to change data
         capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable();
@@ -154,58 +242,18 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
         }
     }
 
-    this.glProfile = capsReqUser.getGLProfile();
+    // instantiation will be issued in addNotify()
+    this.capsReqUser = capsReqUser;
     this.chooser = chooser;
     this.shareWith = shareWith;
-
-    /*
-     * Save the 'chosen' GraphicsConfiguration for use in getGraphicsConfiguration().
-     */
-    awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
-    if(null==awtConfig) {
-        throw new GLException("Error: NULL AWTGraphicsConfiguration");
-    }
-    chosen = awtConfig.getGraphicsConfiguration();
-
-    if (!Beans.isDesignTime()) {
-        // no lock required, since this resource ain't available yet
-        drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig));
-        context = (GLContextImpl) drawable.createContext(shareWith);
-        context.setSynchronized(true);
-    }
-  }
-
-  protected interface DestroyMethod {
-    public void destroyMethod();
-  }
-
-  protected 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;
-  }
-
-  protected final static Window getWindow(Component c) {
-    while ( c!=null && ! ( c instanceof Window ) ) {
-        c = c.getParent();
-    }
-    return (Window)c;
+    this.device = device;
   }
 
   /**
    * Overridden to choose a GraphicsConfiguration on a parent container's
    * GraphicsDevice because both devices
    */
+    @Override
   public GraphicsConfiguration getGraphicsConfiguration() {
     /*
      * Workaround for problems with Xinerama and java.awt.Component.checkGD
@@ -230,6 +278,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
      * otherwise it is from an ancestor component that this Canvas is being
      * added to, and we go into this block.
      */
+    GraphicsConfiguration chosen =  awtConfig.getGraphicsConfiguration();
+
     if (gc != null && chosen != null && !chosen.equals(gc)) {
       /*
        * Check for compatibility with gc. If they differ by only the
@@ -311,88 +361,100 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
   }
   
   public GLContext createContext(GLContext shareWith) {
-    return drawable.createContext(shareWith);
+      drawableSync.lock();
+      try {
+        return (null != drawable) ? drawable.createContext(shareWith) : null;
+      } finally {
+        drawableSync.unlock();
+      }
   }
 
   public void setRealized(boolean realized) {
   }
 
   public boolean isRealized() {
-    return ( null != drawable ) ? drawable.isRealized() : false;
+      drawableSync.lock();
+      try {
+        return ( null != drawable ) ? drawable.isRealized() : false;
+      } finally {
+        drawableSync.unlock();
+      }
+  }
+
+  public int getDefaultCloseOperation() {
+      return awtWindowClosingProtocol.getDefaultCloseOperation();
   }
 
-  private Object closingListener = null;
-  private Object closingListenerLock = new Object();
+  public int setDefaultCloseOperation(int op) {
+      return awtWindowClosingProtocol.setDefaultCloseOperation(op);
+  }
 
   public void display() {
-    if(!drawable.isRealized()) {
+    if( !validateGLDrawable() ) {
+        if(DEBUG) {
+            System.err.println("Info: GLCanvas display - skipped GL render, drawable not valid yet");
+        }
         return; // not yet available ..
     }
     maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction,
                                     displayAction);
-    if(null==closingListener) {
-      synchronized(closingListenerLock) {
-        if(null==closingListener) {
-            closingListener=addClosingListener(this, new DestroyMethod() { 
-                        public void destroyMethod() { destroy(); } });
-        }
-      }
-    }
+
+    awtWindowClosingProtocol.addClosingListenerOneShot();
   }
 
-  protected void dispose(boolean regenerate) {
-    if(DEBUG) {
-        Exception ex1 = new Exception("Info: dispose("+regenerate+") - start");
-        ex1.printStackTrace();
-    }
+  private void dispose(boolean regenerate) {
+    drawableSync.lock();
+    try {
+        if(DEBUG) {
+            Exception ex1 = new Exception("Info: dispose("+regenerate+") - start, hasContext " +
+                    (null!=context) + ", hasDrawable " + (null!=drawable));
+            ex1.printStackTrace();
+        }
+
+        if(null!=context) {
+            boolean animatorPaused = false;
+            GLAnimatorControl animator =  getAnimator();
+            if(null!=animator) {
+                // can't remove us from animator for recreational addNotify()
+                animatorPaused = animator.pause();
+            }
 
-    if(null!=context) {
-        boolean animatorPaused = false;
-        GLAnimatorControl animator =  getAnimator();
-        if(null!=animator) {
-            if(regenerate) {
-                if(animator.isStarted() && !animator.isPaused()) {
-                    animator.pause();
-                    animatorPaused = true;
+            disposeRegenerate=regenerate;
+
+            if (Threading.isSingleThreaded() &&
+                !Threading.isOpenGLThread()) {
+              // Workaround for termination issues with applets --
+              // sun.applet.AppletPanel should probably be performing the
+              // remove() call on the EDT rather than on its own thread
+              // Hint: User should run remove from EDT.
+              if (ThreadingImpl.isAWTMode() &&
+                  Thread.holdsLock(getTreeLock())) {
+                // The user really should not be invoking remove() from this
+                // thread -- but since he/she is, we can not go over to the
+                // EDT at this point. Try to destroy the context from here.
+                if(context.isCreated()) {
+                    drawableHelper.invokeGL(drawable, context, disposeAction, null);
                 }
-            } else {
-                animator.remove(this);
+              } else if(context.isCreated()) {
+                Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction);
+              }
+            } else if(context.isCreated()) {
+              drawableHelper.invokeGL(drawable, context, disposeAction, null);
             }
-        }
 
-        disposeRegenerate=regenerate;
-
-        if (Threading.isSingleThreaded() &&
-            !Threading.isOpenGLThread()) {
-          // Workaround for termination issues with applets --
-          // sun.applet.AppletPanel should probably be performing the
-          // remove() call on the EDT rather than on its own thread
-          // Hint: User should run remove from EDT.
-          if (ThreadingImpl.isAWTMode() &&
-              Thread.holdsLock(getTreeLock())) {
-            // The user really should not be invoking remove() from this
-            // thread -- but since he/she is, we can not go over to the
-            // EDT at this point. Try to destroy the context from here.
-            if(context.isCreated()) {
-                drawableHelper.invokeGL(drawable, context, disposeAction, null);
+            if(animatorPaused) {
+                animator.resume();
             }
-          } else if(context.isCreated()) {
-            Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction);
-          }
-        } else if(context.isCreated()) {
-          drawableHelper.invokeGL(drawable, context, disposeAction, null);
         }
-
-        if(animatorPaused) {
-            animator.resume();
+        if(!regenerate) {
+            disposeAbstractGraphicsDevice();
         }
-    }
-    if(!regenerate) {
-        disposeAbstractGraphicsDeviceAction.run();
-    }
 
-    if(DEBUG) {
-        System.err.println("dispose("+regenerate+") - stop");
+        if(DEBUG) {
+            System.err.println("dispose("+regenerate+") - stop");
+        }
+    } finally {
+        drawableSync.unlock();
     }
   }
 
@@ -410,6 +472,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
       <B>Overrides:</B>
       <DL><DD><CODE>paint</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+    @Override
   public void paint(Graphics g) {
     if (Beans.isDesignTime()) {
       // Make GLCanvas behave better in NetBeans GUI builder
@@ -436,6 +499,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     }
   }
 
+  RecursiveLock drawableSync = new RecursiveLock();
+
   /** Overridden to track when this component is added to a container.
       Subclasses which override this method must call
       super.addNotify() in their addNotify() method in order to
@@ -443,28 +508,82 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
       <B>Overrides:</B>
       <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+    @Override
   public void addNotify() {
     if(DEBUG) {
-        Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: addNotify - start");
+        Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: addNotify - start, bounds: "+this.getBounds());
         ex1.printStackTrace();
     }
-    // 'super.addNotify()' determines the GraphicsConfiguration,
-    // while calling this class's overriden 'getGraphicsConfiguration()' method.
-    // Then it creates the native peer.
-    // Hence we chose the proper GraphicsConfiguration beforehand (see constructor).
-    super.addNotify();
 
-    if (!Beans.isDesignTime()) {
-        // no lock required, since this resource ain't available yet
+    drawableSync.lock();
+    try {
+        /**
+         * 'super.addNotify()' determines the GraphicsConfiguration,
+         * while calling this class's overriden 'getGraphicsConfiguration()' method
+         * after which it creates the native peer.
+         * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
+         * is being used in getGraphicsConfiguration().
+         * This code order also allows recreation, ie re-adding the GLCanvas.
+         */
+        awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
+        if(null==awtConfig) {
+            throw new GLException("Error: NULL AWTGraphicsConfiguration");
+        }
+
+        if (!Beans.isDesignTime()) {
+            // no lock required, since this resource ain't available yet
+            drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile())
+                           .createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig));
+            context = (GLContextImpl) drawable.createContext(shareWith);
+            context.setSynchronized(true);
+            context.setContextCreationFlags(additionalCtxCreationFlags);            
+        }
+
+        // before native peer is valid: X11
+        disableBackgroundErase();
+
+        // issues getGraphicsConfiguration() and creates the native peer
+        super.addNotify();
+
+        // after native peer is valid: Windows
         disableBackgroundErase();
-        drawable.setRealized(true);
+
+        // init drawable by paint/display makes the init sequence more equal
+        // for all launch flavors (applet/javaws/..)
+        // validateGLDrawable();
+
         if(DEBUG) {
-            System.err.println(Thread.currentThread().getName()+" - Realized Drawable: "+drawable);
+            System.err.println(Thread.currentThread().getName()+" - Info: addNotify - end: peer: "+getPeer());
         }
+    } finally {
+       drawableSync.unlock();
     }
-    if(DEBUG) {
-        System.err.println(Thread.currentThread().getName()+" - Info: addNotify - end");
+  }
+
+  private boolean validateGLDrawable() {
+    boolean realized = false;
+    if (!Beans.isDesignTime()) {
+        drawableSync.lock();
+        try {
+            if ( null != drawable ) {
+                realized = drawable.isRealized();
+                if ( !realized && 0 < drawable.getWidth() * drawable.getHeight() ) {
+                    drawable.setRealized(true);
+                    realized = true;
+                    sendReshape=true; // ensure a reshape is being send ..
+                    if(DEBUG) {
+                        String msg = Thread.currentThread().getName()+" - Realized Drawable: "+drawable.toString();
+                        // System.err.println(msg);
+                        Throwable t = new Throwable(msg);
+                        t.printStackTrace();
+                    }
+                }
+            }
+        } finally {
+           drawableSync.unlock();
+        }
     }
+    return realized;
   }
 
   /** <p>Overridden to track when this component is removed from a
@@ -475,24 +594,31 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
       about this.</p>
       <B>Overrides:</B>
       <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+    @Override
   public void removeNotify() {
     if(DEBUG) {
         Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: removeNotify - start");
         ex1.printStackTrace();
     }
 
+    awtWindowClosingProtocol.removeClosingListener();
+
     if (Beans.isDesignTime()) {
       super.removeNotify();
     } else {
+      drawableSync.lock();
       try {
         dispose(false);
       } finally {
+        context=null;
         drawable=null;
+        awtConfig=null;
         super.removeNotify();
+        drawableSync.unlock();
       }
     }
     if(DEBUG) {
-        System.err.println(Thread.currentThread().getName()+" - Info: removeNotify - end");
+        System.err.println(Thread.currentThread().getName()+" - Info: removeNotify - end, peer: "+getPeer());
     }
   }
 
@@ -503,6 +629,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
       <B>Overrides:</B>
       <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+    @Override
   public void reshape(int x, int y, int width, int height) {
     super.reshape(x, y, width, height);
     sendReshape = true;
@@ -510,8 +637,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
   /** <B>Overrides:</B>
       <DL><DD><CODE>update</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
-  // Overridden from Canvas to prevent the AWT's clearing of the
-  // canvas from interfering with the OpenGL rendering.
+  /** 
+   * Overridden from Canvas to prevent the AWT's clearing of the
+   * canvas from interfering with the OpenGL rendering.
+   */
+    @Override
   public void update(Graphics g) {
     paint(g);
   }
@@ -542,6 +672,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
   public void setContext(GLContext ctx) {
     context=(GLContextImpl)ctx;
+    if(null != context) {
+        context.setContextCreationFlags(additionalCtxCreationFlags);
+    }
   }
 
   public GLContext getContext() {
@@ -552,14 +685,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     if (Beans.isDesignTime()) {
       return null;
     }
-    GLContext context = getContext();
-    return (context == null) ? null : context.getGL();
+    GLContext ctx = getContext();
+    return (ctx == null) ? null : ctx.getGL();
   }
 
   public GL setGL(GL gl) {
-    GLContext context = getContext();
-    if (context != null) {
-      context.setGL(gl);
+    GLContext ctx = getContext();
+    if (ctx != null) {
+      ctx.setGL(gl);
       return gl;
     }
     return null;
@@ -578,8 +711,16 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction);
   }
 
+  public void setContextCreationFlags(int flags) {
+    additionalCtxCreationFlags = flags;
+  }
+      
+  public int getContextCreationFlags() {
+    return additionalCtxCreationFlags;                
+  }
+          
   public GLProfile getGLProfile() {
-    return glProfile;
+    return capsReqUser.getGLProfile();
   }
 
   public GLCapabilitiesImmutable getChosenGLCapabilities() {
@@ -592,28 +733,55 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
   public GLCapabilitiesImmutable getRequestedGLCapabilities() {
     if (awtConfig == null) {
-        throw new GLException("No AWTGraphicsConfiguration: "+this);
+        return capsReqUser;
     }
 
     return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities();
   }
 
   public NativeSurface getNativeSurface() {
-    return drawable.getNativeSurface();
+      drawableSync.lock();
+      try {
+        return (null != drawable) ? drawable.getNativeSurface() : null;
+      } finally {
+        drawableSync.unlock();
+      }
   }
 
   public long getHandle() {
-    return drawable.getHandle();
+      drawableSync.lock();
+      try {
+        return (null != drawable) ? drawable.getHandle() : 0;
+      } finally {
+        drawableSync.unlock();
+      }
   }
 
   public GLDrawableFactory getFactory() {
-    return drawable.getFactory();
+      drawableSync.lock();
+      try {
+        return (null != drawable) ? drawable.getFactory() : null;
+      } finally {
+        drawableSync.unlock();
+      }
   }
 
+  @Override
   public String toString() {
-    return "AWT-GLCanvas[ "+awtConfig+", "+((null!=drawable)?drawable.getClass().getName():"null-drawable")+"]";
+    final int dw = (null!=drawable) ? drawable.getWidth() : -1;
+    final int dh = (null!=drawable) ? drawable.getHeight() : -1;
+    
+    return "AWT-GLCanvas[Realized "+isRealized()+
+                          ",\n\t"+((null!=drawable)?drawable.getClass().getName():"null-drawable")+                         
+                          ",\n\tRealized "+isRealized()+
+                          ",\n\tFactory   "+getFactory()+
+                          ",\n\thandle    0x"+Long.toHexString(getHandle())+
+                          ",\n\tDrawable size "+dw+"x"+dh+
+                          ",\n\tAWT pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+
+                          ",\n\tvisible "+isVisible()+
+                          ",\n\t"+awtConfig+"]";
   }
-
+  
   //----------------------------------------------------------------------
   // Internals only below this point
   //
@@ -640,11 +808,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
 
       if(null!=drawable) {
           drawable.setRealized(false);
+          drawable=null;
       }
 
       if(disposeRegenerate) {
           // recreate GLDrawable to reflect it's new graphics configuration
-          drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(GLCanvas.this, awtConfig));
+          drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile())
+                        .createGLDrawable(NativeWindowFactory.getNativeWindow(GLCanvas.this, awtConfig));
           if(DEBUG) {
             System.err.println("GLCanvas.dispose(true): new drawable: "+drawable);
           }
@@ -679,12 +849,33 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
           }
           boolean closed = adevice.close();
           if(DEBUG) {
-            System.err.println("GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed);
+            System.err.println(Thread.currentThread().getName() + " - GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed);
           }
       }
+      awtConfig=null;
+    }
+  }
+  private DisposeAbstractGraphicsDeviceAction disposeAbstractGraphicsDeviceAction = new DisposeAbstractGraphicsDeviceAction();
+
+  /**
+   * Disposes the AbstractGraphicsDevice within EDT,
+   * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
+   *
+   * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
+   */
+  void disposeAbstractGraphicsDevice()  {
+    if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
+        disposeAbstractGraphicsDeviceAction.run();
+    } else {
+        try {
+            EventQueue.invokeAndWait(disposeAbstractGraphicsDeviceAction);
+        } catch (InvocationTargetException e) {
+            throw new GLException(e.getTargetException());
+        } catch (InterruptedException e) {
+            throw new GLException(e);
+        }
     }
   }
-  DisposeAbstractGraphicsDeviceAction disposeAbstractGraphicsDeviceAction = new DisposeAbstractGraphicsDeviceAction();
 
   class InitAction implements Runnable {
     public void run() {
@@ -696,6 +887,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
   class DisplayAction implements Runnable {
     public void run() {
       if (sendReshape) {
+        if(DEBUG) {
+            System.err.println(Thread.currentThread().getName()+" - reshape: "+getWidth()+"x"+getHeight());
+        }
         // Note: we ignore the given x and y within the parent component
         // since we are drawing directly into this heavyweight component.
         drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
@@ -764,31 +958,73 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
       } catch (Exception e) {
       }
       disableBackgroundEraseInitialized = true;
+      if(DEBUG) {
+        System.err.println("GLCanvas: TK disableBackgroundErase method found: "+
+                (null!=disableBackgroundEraseMethod));
+      }
     }
     if (disableBackgroundEraseMethod != null) {
+      Throwable t=null;
       try {
         disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
       } catch (Exception e) {
-        // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10)
-        // throw new GLException(e);
+        t = e;
+      }
+      if(DEBUG) {
+        System.err.println("GLCanvas: TK disableBackgroundErase error: "+t);
       }
     }
   }
 
-  private static AWTGraphicsConfiguration chooseGraphicsConfiguration(GLCapabilitiesImmutable capsChosen,
-                                                                      GLCapabilitiesImmutable capsRequested,
-                                                                      GLCapabilitiesChooser chooser,
-                                                                      GraphicsDevice device) {
+  /**
+   * Issues the GraphicsConfigurationFactory's choosing facility within EDT,
+   * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
+   *
+   * @param capsChosen
+   * @param capsRequested
+   * @param chooser
+   * @param device
+   * @return the chosen AWTGraphicsConfiguration
+   *
+   * @see #disposeAbstractGraphicsDevice()
+   */
+  private AWTGraphicsConfiguration chooseGraphicsConfiguration(final GLCapabilitiesImmutable capsChosen,
+                                                               final GLCapabilitiesImmutable capsRequested,
+                                                               final GLCapabilitiesChooser chooser,
+                                                               final GraphicsDevice device) {
     // Make GLCanvas behave better in NetBeans GUI builder
     if (Beans.isDesignTime()) {
       return null;
     }
 
-    AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT);
-    AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
-          GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen,
-                                                                                                       capsRequested,
-                                                                                                       chooser, aScreen);
+    final AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT);
+    AWTGraphicsConfiguration config = null;
+
+    if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
+        config = (AWTGraphicsConfiguration)
+                GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen,
+                                                                                                             capsRequested,
+                                                                                                             chooser, aScreen);
+    } else {
+        try {
+            final ArrayList bucket = new ArrayList(1);
+            EventQueue.invokeAndWait(new Runnable() {
+                public void run() {
+                    AWTGraphicsConfiguration c = (AWTGraphicsConfiguration)
+                            GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen,
+                                                                                                                         capsRequested,
+                                                                                                                         chooser, aScreen);
+                    bucket.add(c);
+                }
+            });
+            config = ( bucket.size() > 0 ) ? (AWTGraphicsConfiguration)bucket.get(0) : null ;
+        } catch (InvocationTargetException e) {
+            throw new GLException(e.getTargetException());
+        } catch (InterruptedException e) {
+            throw new GLException(e);
+        }
+    }
+
     if (config == null) {
       throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration");
     }
@@ -802,8 +1038,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
   public static void main(String args[]) {
     System.err.println(VersionUtil.getPlatformInfo());
     System.err.println(GlueGenVersion.getInstance());
-    System.err.println(NativeWindowVersion.getInstance());
-    System.err.print(JoglVersion.getInstance());
+    // System.err.println(NativeWindowVersion.getInstance());
+    System.err.println(JoglVersion.getInstance());
+
+    GLProfile.initSingleton(false);
+    GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory();
+    List/*<GLCapabilitiesImmutable>*/ availCaps = factory.getAvailableCapabilities(null);
+    for(int i=0; i<availCaps.size(); i++) {
+        System.err.println(availCaps.get(i));
+    }
 
     GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()) );
     Frame frame = new Frame("JOGL AWT Test");
@@ -815,7 +1058,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
     glCanvas.addGLEventListener(new GLEventListener() {
         public void init(GLAutoDrawable drawable) {
             GL gl = drawable.getGL();
-            System.err.println(JoglVersion.getInstance().toString(gl));
+            System.err.println(JoglVersion.getGLInfo(gl, null));
         }
 
         public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
http://JogAmp.org git info: FAQ, tutorial and man pages.