Jogamp
NewtVersionActivity: Remove 'gears' test; Version Info: Drop NativeWindow/Newt Versio...
[jogl.git] / src / newt / classes / com / jogamp / newt / opengl / GLWindow.java
index b5d55ae..1cc2298 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2008 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
 
 package com.jogamp.newt.opengl;
 
+import java.io.PrintStream;
+import java.util.List;
+
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.nativewindow.NativeWindowVersion;
 import com.jogamp.newt.*;
 import com.jogamp.newt.event.*;
+import jogamp.newt.WindowImpl;
+
 import javax.media.nativewindow.*;
+import javax.media.nativewindow.util.Point;
+import javax.media.nativewindow.util.Insets;
 import javax.media.opengl.*;
-import com.jogamp.opengl.impl.GLDrawableHelper;
-import java.util.*;
+
+import jogamp.opengl.FPSCounterImpl;
+import jogamp.opengl.GLDrawableHelper;
+import com.jogamp.opengl.JoglVersion;
 
 /**
- * An implementation of {@link Window} which is customized for OpenGL
- * use, and which implements the {@link javax.media.opengl.GLAutoDrawable} interface.
+ * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface,
+ * using an aggregation of a {@link com.jogamp.newt.Window} implementation.
  * <P>
  * This implementation does not make the OpenGL context current<br>
- * before calling the various input EventListener callbacks (MouseListener, KeyListener,
- * etc.).<br>
- * This design decision is made to favor a more performant and simplified
- * implementation, as well as the event dispatcher shall be allowed
- * not having a notion about OpenGL.
+ * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br>
+ * This design decision is made in favor of a more performant and simplified
+ * implementation. Also the event dispatcher shall be implemented OpenGL agnostic.<br>
+ * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},<br>
+ * you can inject {@link javax.media.opengl.GLRunnable} objects
+ * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br>
  * <p>
  */
-public class GLWindow extends Window implements GLAutoDrawable {
-    private static List/*GLWindow*/ glwindows = new ArrayList();
-
-    private boolean ownerOfWinScrDpy;
-    private Window window;
-    private boolean runPumpMessages;
+public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSCounter {
+    private WindowImpl window;
 
     /**
      * Constructor. Do not call this directly -- use {@link #create()} instead.
      */
-    protected GLWindow(Window window, boolean ownerOfWinScrDpy) {
-        this.ownerOfWinScrDpy = ownerOfWinScrDpy;
-        this.window = window;
-        this.window.setAutoDrawableClient(true);
-        this.runPumpMessages = ( null == getScreen().getDisplay().getEDTUtil() ) ;
+    protected GLWindow(Window window) {
+        resetFPSCounter();
+        this.window = (WindowImpl) window;
+        ((WindowImpl)this.window).setHandleDestroyNotify(false);
         window.addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowRepaint(WindowUpdateEvent e) {
+                    if( !GLWindow.this.window.isWindowLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) {
+                        display();
+                    }
+                }
+
+                @Override
                 public void windowResized(WindowEvent e) {
                     sendReshape = true;
+                    if( !GLWindow.this.window.isWindowLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) {
+                        display();
+                    }
                 }
 
+                @Override
                 public void windowDestroyNotify(WindowEvent e) {
-                    sendDestroy = true;
+                    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.isWindowLockedByOtherThread()) {
+                            // Window 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 ();
+                        }
+                    }
                 }
             });
-
-        List newglw = (List) ((ArrayList) glwindows).clone();
-        newglw.add(this);
-        glwindows=newglw;
+        this.window.setLifecycleHook(new GLLifecycleHook());
     }
 
-    /** Creates a new GLWindow attaching the given window - not owning the Window. */
-    public static GLWindow create(Window window) {
-        return create(null, window, null, false);
-    }
-
-    /** Creates a new GLWindow attaching a new native child Window of the given <code>parentWindowObject</code>
-        with the given GLCapabilities - owning the Window */
-    public static GLWindow create(Object parentWindowObject, GLCapabilities caps) {
-        return create(parentWindowObject, null, caps, true);
-    }
-
-    /** Creates a new GLWindow attaching a new decorated Window on the local display, screen 0, with a
-        dummy visual ID and given GLCapabilities - owning the window */
-    public static GLWindow create(GLCapabilities caps) {
-        return create(null, null, caps, false);
-    }
-
-    /** Creates a new GLWindow attaching a new Window on the local display, screen 0, with a
-        dummy visual ID and given GLCapabilities - owning the window */
-    public static GLWindow create(GLCapabilities caps, boolean undecorated) {
-        return create(null, null, caps, undecorated);
+    /**
+     * Creates a new GLWindow attaching a new Window referencing a new Screen
+     * with the given GLCapabilities.
+     * <P>
+     * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed.
+     */
+    public static GLWindow create(GLCapabilitiesImmutable caps) {
+        return new GLWindow(NewtFactory.createWindow(caps));
     }
 
-    /** Either or: window (prio), or caps and undecorated (2nd choice) */
-    private static GLWindow create(Object parentWindowObject, Window window, 
-                                   GLCapabilities caps,
-                                   boolean undecorated) {
-        boolean ownerOfWinScrDpy=false;
-        if (window == null) {
-            if (caps == null) {
-                caps = new GLCapabilities(null); // default ..
-            }
-            ownerOfWinScrDpy = true;
-            window = NewtFactory.createWindow(parentWindowObject, caps, undecorated);
-        }
-
-        return new GLWindow(window, ownerOfWinScrDpy);
-    }
-    
-    public boolean isDestroyed() {
-        return null == window ;
+    /**
+     * Creates a new GLWindow attaching a new Window referencing the given Screen
+     * with the given GLCapabilities.
+     * <P>
+     * The resulting GLWindow owns the Window, ie it will be destructed.
+     */
+    public static GLWindow create(Screen screen, GLCapabilitiesImmutable caps) {
+        return new GLWindow(NewtFactory.createWindow(screen, caps));
     }
 
-    public Window getWindow() {
-        return window;
+    /** 
+     * Creates a new GLWindow attaching the given window.
+     * <P>
+     * The resulting GLWindow does not own the given Window, ie it will not be destructed. 
+     */
+    public static GLWindow create(Window window) {
+        return new GLWindow(window);
     }
 
     /** 
-     * EXPERIMENTAL<br> 
-     * Enable or disables running the {@link Display#pumpMessages} in the {@link #display()} call.<br>
-     * The default behavior is to run {@link Display#pumpMessages}.<P>
-     *
-     * The idea was that in a single threaded environment with one {@link Display} and many {@link Window}'s,
-     * a performance benefit was expected while disabling the implicit {@link Display#pumpMessages} and
-     * do it once via {@link GLWindow#runCurrentThreadPumpMessage()} <br>
-     * This could not have been verified. No measurable difference could have been recognized.<P>
-     *
-     * Best performance has been achieved with one GLWindow per thread.<br> 
-     *
-     * Enabling local pump messages while using the EDT, 
-     * {@link com.jogamp.newt.NewtFactory#setUseEDT(boolean)},
-     * will result in an exception.
-     *
-     * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification.
+     * Creates a new GLWindow attaching a new child Window 
+     * of the given <code>parentNativeWindow</code> with the given GLCapabilities.
+     * <P>
+     * The Display/Screen will be compatible with the <code>parentNativeWindow</code>,
+     * or even identical in case it's a Newt Window.
+     * <P>
+     * The resulting GLWindow owns the Window, ie it will be destructed. 
      */
-    public void setRunPumpMessages(boolean onoff) {
-        if( onoff && null!=getScreen().getDisplay().getEDTUtil() ) {
-            throw new GLException("GLWindow.setRunPumpMessages(true) - Can't do with EDT on");
-        }
-        runPumpMessages = onoff;
+    public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilitiesImmutable caps) {
+        return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps));
     }
 
-    protected void createNativeImpl() {
-        shouldNotCallThis();
+    //----------------------------------------------------------------------
+    // WindowClosingProtocol implementation
+    //
+    public int getDefaultCloseOperation() {
+        return window.getDefaultCloseOperation();
     }
 
-    protected void closeNative() {
-        shouldNotCallThis();
+    public int setDefaultCloseOperation(int op) {
+        return window.setDefaultCloseOperation(op);
     }
 
-    protected void dispose(boolean regenerate, boolean sendEvent) {
-        if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
-            Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", 1");
-            e1.printStackTrace();
-        }
-
-        if(sendEvent) {
-            sendDisposeEvent();
-        }
-
-        if (context != null) {
-            context.destroy();
-        }
-        if (drawable != null) {
-            drawable.setRealized(false);
-        }
-
-        if(regenerate) {
-            if(null==window) {
-                throw new GLException("GLWindow.dispose(true): null window");
-            }
-
-            // recreate GLDrawable, to reflect the new graphics configurations
-            NativeWindow nw;
-            if (window.getWrappedWindow() != null) {
-                nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
-            } else {
-                nw = window;
-            }
-            drawable = factory.createGLDrawable(nw);
-            drawable.setRealized(true);
-            context = drawable.createContext(null);
-            sendReshape = true; // ensure a reshape event is send ..
-        }
-
-        if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
-            System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", fin: "+this);
-        }
-    }
+    //----------------------------------------------------------------------
+    // Window Access
+    //
 
-    public synchronized void destroy() {
-        destroy(true);
+    public CapabilitiesChooser setCapabilitiesChooser(CapabilitiesChooser chooser) {
+        return window.setCapabilitiesChooser(chooser);
     }
 
-    /** @param sendDisposeEvent should be false in a [time,reliable] critical shutdown */
-    public synchronized void destroy(boolean sendDisposeEvent) {
-        List newglw = (List) ((ArrayList) glwindows).clone();
-        newglw.remove(this);
-        glwindows=newglw;
-
-        dispose(false, sendDisposeEvent);
-
-        if(null!=window) {
-            if(ownerOfWinScrDpy) {
-                window.destroy(true);
-            }
+    public final CapabilitiesImmutable getChosenCapabilities() {
+        if (drawable == null) {
+            return window.getChosenCapabilities();
         }
 
-        drawable = null;
-        context = null;
-        window = null;
+        return drawable.getChosenGLCapabilities();
     }
 
-    public boolean getPerfLogEnabled() { return perfLog; }
-
-    public void enablePerfLog(boolean v) {
-        perfLog = v;
+    public final CapabilitiesImmutable getRequestedCapabilities() {
+        return window.getRequestedCapabilities();
     }
 
-    protected void setVisibleImpl() {
-        shouldNotCallThis();
+    public final Window getWindow() {
+        return window;
     }
 
-    public void setVisible(final boolean visible) {
-        window.setVisible(visible);
-        if (visible && null == context && 0 != window.getWindowHandle()) {
-            NativeWindow nw;
-            if (window.getWrappedWindow() != null) {
-                nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
-            } else {
-                nw = window;
-            }
-            GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities();
-            factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
-            drawable = factory.createGLDrawable(nw);
-            drawable.setRealized(true);
-            context = drawable.createContext(null);
-            sendReshape = true; // ensure a reshape event is send ..
-        }
+    public final NativeWindow getParent() {
+        return window.getParent();
     }
 
-    public Screen getScreen() {
+    public final Screen getScreen() {
         return window.getScreen();
     }
 
-    public void setTitle(String title) {
+    public final void setTitle(String title) {
         window.setTitle(title);
     }
 
-    public String getTitle() {
+    public final String getTitle() {
         return window.getTitle();
     }
 
-    public void setUndecorated(boolean value) {
+    public final void setUndecorated(boolean value) {
         window.setUndecorated(value);
     }
 
-    public boolean isUndecorated() {
+    public final boolean isUndecorated() {
         return window.isUndecorated();
     }
 
-    public void requestFocus() {
+    public final void setFocusAction(FocusRunnable focusAction) {
+        window.setFocusAction(focusAction);
+    }
+    
+    public final void requestFocus() {
         window.requestFocus();
     }
 
-    public void setSize(int width, int height) {
-        window.setSize(width, height);
+    public boolean hasFocus() {
+        return window.hasFocus();
     }
 
-    public void setPosition(int x, int y) {
-        window.setPosition(x, y);
+    public final Insets getInsets() {
+        return window.getInsets();
     }
 
-    public Insets getInsets() {
-        return window.getInsets();
+    public final void setPosition(int x, int y) {
+        window.setPosition(x, y);
     }
 
-    public boolean setFullscreen(boolean fullscreen) {
+    public final boolean setFullscreen(boolean fullscreen) {
         return window.setFullscreen(fullscreen);
     }
 
-    public boolean isVisible() {
-        return window.isVisible();
+    public final boolean isFullscreen() {
+        return window.isFullscreen();
     }
 
-    public int getX() {
-        return window.getX();
+    public final boolean isVisible() {
+        return window.isVisible();
     }
 
-    public int getY() {
-        return window.getY();
+    @Override
+    public final String toString() {
+        return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + 
+               ", \n\tContext: " + context + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]";
     }
 
-    public int getWidth() {
-        return window.getWidth();
+    public final int reparentWindow(NativeWindow newParent) {
+        return window.reparentWindow(newParent);
     }
 
-    public int getHeight() {
-        return window.getHeight();
+    public final int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) {
+        return window.reparentWindow(newParent, forceDestroyCreate);
     }
 
-    public boolean isFullscreen() {
-        return window.isFullscreen();
+    public final void removeChild(NativeWindow win) {
+        window.removeChild(win);
     }
 
-    public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
-        window.addSurfaceUpdatedListener(l);
-    }
-    public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
-        window.removeSurfaceUpdatedListener(l);
-    }
-    public void removeAllSurfaceUpdatedListener() {
-        window.removeAllSurfaceUpdatedListener();
-    }
-    public SurfaceUpdatedListener[] getSurfaceUpdatedListener() {
-        return window.getSurfaceUpdatedListener();
-    }
-    public void surfaceUpdated(Object updater, NativeWindow window0, long when) { 
-        window.surfaceUpdated(updater, window, when);
+    public final void addChild(NativeWindow win) {
+        window.addChild(win);
     }
+    
+    //----------------------------------------------------------------------
+    // Window.LifecycleHook Implementation
+    //
 
-    public void sendEvent(NEWTEvent e) {
-        window.sendEvent(e);
+    public final void destroy() {
+        window.destroy();
     }
 
-    public void addMouseListener(MouseListener l) {
-        window.addMouseListener(l);
+    public final void setVisible(boolean visible) {
+        window.setVisible(visible);
     }
 
-    public void removeMouseListener(MouseListener l) {
-        window.removeMouseListener(l);
+    public final void setSize(int width, int height) {
+        window.setSize(width, height);
     }
 
-    public MouseListener[] getMouseListeners() {
-        return window.getMouseListeners();
+    public final boolean isValid() {
+        return window.isValid();
     }
 
-    public void addKeyListener(KeyListener l) {
-        window.addKeyListener(l);
+    public final boolean isNativeValid() {
+        return window.isNativeValid();
     }
 
-    public void removeKeyListener(KeyListener l) {
-        window.removeKeyListener(l);
+    public Point getLocationOnScreen(Point storage) {
+        return window.getLocationOnScreen(storage);
     }
 
-    public KeyListener[] getKeyListeners() {
-        return window.getKeyListeners();
-    }
+    // Hide methods here ..
+    protected class GLLifecycleHook implements WindowImpl.LifecycleHook {
 
-    public void addWindowListener(WindowListener l) {
-        window.addWindowListener(l);
-    }
+        private class DisposeAction implements Runnable {
+            public final void run() {
+                // Lock: Covered by DestroyAction ..
+                helper.dispose(GLWindow.this);
+            }
+        }
+        DisposeAction disposeAction = new DisposeAction();
 
-    public void removeWindowListener(WindowListener l) {
-        window.removeWindowListener(l);
-    }
+        public synchronized void destroyActionPreLock() {
+            // nop
+        }
 
-    public WindowListener[] getWindowListeners() {
-        return window.getWindowListeners();
-    }
+        public synchronized void destroyActionInLock() {
+            if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
+                String msg = "GLWindow.destroy() "+Thread.currentThread()+", start";
+                System.err.println(msg);
+                //Exception e1 = new Exception(msg);
+                //e1.printStackTrace();
+            }
+
+            if( window.isNativeValid() && null != drawable && drawable.isRealized() ) {
+                if( null != context && context.isCreated() ) {
+                    // Catch dispose GLExceptions by GLEventListener, just 'print' them
+                    // so we can continue with the destruction.
+                    try {
+                        helper.invokeGL(drawable, context, disposeAction, null);
+                    } catch (GLException gle) {
+                        gle.printStackTrace();
+                    }
+                    context.destroy();
+                }
+                drawable.setRealized(false);
+            }
+            context = null;
+            drawable = null;
+            
+            GLAnimatorControl ctrl = GLWindow.this.getAnimator();
+            if ( null!=ctrl ) {
+                ctrl.remove(GLWindow.this);
+            }            
+            // helper=null; // pending events ..
+            
+            if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
+                System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin");
+            }
+        }
+
+        public synchronized void resetCounter() {
+            if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
+                System.err.println("GLWindow.resetCounter() "+Thread.currentThread());
+            }
+            GLWindow.this.resetFPSCounter();
+        }
+
+        public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) {
+            if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
+                String msg = "GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", start";
+                System.err.println(msg);
+                // Exception e1 = new Exception(msg);
+                // e1.printStackTrace();
+            }
 
-    public String toString() {
-        return "NEWT-GLWindow[ \n\tHelper: "+helper+", \n\tDrawable: "+drawable + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]";
+            /* if (nativeWindowCreated && null != context) {
+                throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)");
+            } */
+            if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) {
+                NativeWindow nw;
+                if (window.getWrappedWindow() != null) {
+                    nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
+                } else {
+                    nw = window;
+                }
+                GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities();
+                if(null==factory) {
+                    factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
+                }
+                if(null==drawable) {
+                    drawable = factory.createGLDrawable(nw);
+                }
+                drawable.setRealized(true);
+                context = drawable.createContext(sharedContext);
+                context.setContextCreationFlags(additionalCtxCreationFlags);                
+            }
+            if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) {
+                String msg = "GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin";
+                System.err.println(msg);
+                //Exception e1 = new Exception(msg);
+                //e1.printStackTrace();
+            }
+        }
+        
+        private GLAnimatorControl savedAnimator = null;
+        
+        public synchronized boolean pauseRenderingAction() {
+            boolean animatorPaused = false;
+            savedAnimator = GLWindow.this.getAnimator();
+            if ( null != savedAnimator ) {
+                animatorPaused = savedAnimator.pause();
+            }
+            return animatorPaused;
+        }
+
+        public synchronized void resumeRenderingAction() {
+            if ( null != savedAnimator && savedAnimator.isPaused() ) {
+                savedAnimator.resume();
+            }
+        }
     }
 
     //----------------------------------------------------------------------
     // OpenGL-related methods and state
     //
 
+    private GLContext sharedContext = null;
+    private int additionalCtxCreationFlags = 0;
     private GLDrawableFactory factory;
     private GLDrawable drawable;
     private GLContext context;
@@ -388,14 +428,29 @@ public class GLWindow extends Window implements GLAutoDrawable {
     // To make reshape events be sent immediately before a display event
     private boolean sendReshape=false;
     private boolean sendDestroy=false;
-    private boolean perfLog = false;
+    private FPSCounterImpl fpsCounter = new FPSCounterImpl();    
 
     public GLDrawableFactory getFactory() {
         return factory;
     }
 
+    /**
+     * Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.<br>
+     * At native creation, {@link #setVisible(boolean) setVisible(true)},
+     * a {@link javax.media.opengl.GLDrawable drawable} and {@link javax.media.opengl.GLContext context} is created besides the native Window itself,<br>
+     * hence you shall set the shared context before.
+     *
+     * @param sharedContext The OpenGL context shared by this GLWindow's one
+     */
+    public void setSharedContext(GLContext sharedContext) {
+        this.sharedContext = sharedContext;
+    }
+
     public void setContext(GLContext newCtx) {
         context = newCtx;
+        if(null != context) {
+            context.setContextCreationFlags(additionalCtxCreationFlags);
+        }        
     }
 
     public GLContext getContext() {
@@ -418,11 +473,40 @@ public class GLWindow extends Window implements GLAutoDrawable {
     }
 
     public void addGLEventListener(GLEventListener listener) {
-        helper.addGLEventListener(listener);
+        if(null!=helper) {
+            helper.addGLEventListener(listener);
+        }
+    }
+
+    public void addGLEventListener(int index, GLEventListener listener) {
+        if(null!=helper) {
+            helper.addGLEventListener(index, listener);
+        }
     }
 
     public void removeGLEventListener(GLEventListener listener) {
-        helper.removeGLEventListener(listener);
+        if(null!=helper) {
+            helper.removeGLEventListener(listener);
+        }
+    }
+
+    public void setAnimator(GLAnimatorControl animatorControl) {
+        if(null!=helper) {
+            helper.setAnimator(animatorControl);
+        }
+    }
+
+    public GLAnimatorControl getAnimator() {
+        if(null!=helper) {
+            return helper.getAnimator();
+        }
+        return null;
+    }
+
+    public void invoke(boolean wait, GLRunnable glRunnable) {
+        if(null!=helper) {
+            helper.invoke(this, wait, glRunnable);
+        }
     }
 
     public void display() {
@@ -432,189 +516,176 @@ public class GLWindow extends Window implements GLAutoDrawable {
     public void display(boolean forceReshape) {
         if( null == window ) { return; }
 
-        if( null == context && window.isVisible() ) {
+        if(sendDestroy || ( null!=window && window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) ) {
+            sendDestroy=false;
+            destroy();
+            return;
+        }
+
+        if( null == context && isVisible() && 0<getWidth()*getHeight() ) {
             // retry native window and drawable/context creation 
             setVisible(true);
         }
 
-        if( null != context ) {
-            if(runPumpMessages) {
-                window.getScreen().getDisplay().pumpMessages();
-            }
-            if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) {
-                dispose(true, true);
-            }
-            if (sendDestroy) {
-                destroy();
-                sendDestroy=false;
-            } else if ( window.isVisible() ) {
-                if(forceReshape) {
-                    sendReshape = true;
+        if(forceReshape) {
+            sendReshape = true;
+        }
+        
+        if( isVisible() && null != context ) {
+            if( NativeSurface.LOCK_SURFACE_NOT_READY < lockSurface() ) {
+                try {
+                    helper.invokeGL(drawable, context, displayAction, initAction);
+                } finally {
+                    unlockSurface();
                 }
-                helper.invokeGL(drawable, context, displayAction, initAction);
             }
         }
     }
-
-    private void sendDisposeEvent() {
-        if(drawable!=null && context != null) {
-            helper.invokeGL(drawable, context, disposeAction, null);
-        }
-    }
-
+    
     /** This implementation uses a static value */
     public void setAutoSwapBufferMode(boolean onOrOff) {
-        helper.setAutoSwapBufferMode(onOrOff);
+        if(null!=helper) {
+            helper.setAutoSwapBufferMode(onOrOff);
+        }
     }
 
     /** This implementation uses a static value */
     public boolean getAutoSwapBufferMode() {
-        return helper.getAutoSwapBufferMode();
+        if(null!=helper) {
+            return helper.getAutoSwapBufferMode();
+        }
+        return false;
     }
-
+    
     public void swapBuffers() {
         if(drawable!=null && context != null) {
-            if (context != GLContext.getCurrent()) {
-                // Assume we should try to make the context current before swapping the buffers
-                helper.invokeGL(drawable, context, swapBuffersAction, initAction);
-            } else {
-                drawable.swapBuffers();
-            }
+            drawable.swapBuffers();
         }
     }
 
-    class InitAction implements Runnable {
-        public void run() {
+    public void setContextCreationFlags(int flags) {
+        additionalCtxCreationFlags = flags;
+    }
+      
+    public int getContextCreationFlags() {
+        return additionalCtxCreationFlags;                
+    }
+        
+    private class InitAction implements Runnable {
+        public final void run() {
+            // Lock: Locked Surface/Window by MakeCurrent/Release
             helper.init(GLWindow.this);
-            startTime = System.currentTimeMillis();
-            curTime   = startTime;
-            if(perfLog) {
-                lastCheck  = startTime;
-                totalFrames = 0; lastFrames = 0;
-            }
+            resetFPSCounter();
         }
     }
     private InitAction initAction = new InitAction();
 
-    class DisposeAction implements Runnable {
-        public void run() {
-            helper.dispose(GLWindow.this);
-        }
-    }
-    private DisposeAction disposeAction = new DisposeAction();
-
-    class DisplayAction implements Runnable {
-        public void run() {
+    private class DisplayAction implements Runnable {
+        public final void run() {
+            // Lock: Locked Surface/Window by display _and_ MakeCurrent/Release
             if (sendReshape) {
-                int width = getWidth();
-                int height = getHeight();
-                getGL().glViewport(0, 0, width, height);
-                helper.reshape(GLWindow.this, 0, 0, width, height);
+                helper.reshape(GLWindow.this, 0, 0, getWidth(), getHeight());
                 sendReshape = false;
             }
 
             helper.display(GLWindow.this);
 
-            curTime = System.currentTimeMillis();
-            totalFrames++;
-
-            if(perfLog) {
-                long dt0, dt1;
-                lastFrames++;
-                dt0 = curTime-lastCheck;
-                if ( dt0 > 5000 ) {
-                    dt1 = curTime-startTime;
-                    System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+
-                                       "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f");
-                    lastCheck=curTime;
-                    lastFrames=0;
-                }
-            }
+            fpsCounter.tickFPS();
         }
     }
     private DisplayAction displayAction = new DisplayAction();
 
-    public long getStartTime()   { return startTime; }
-    public long getCurrentTime() { return curTime; }
-    public long getDuration()    { return curTime-startTime; }
-    public int  getTotalFrames() { return totalFrames; }
-
-    private long startTime = 0;
-    private long curTime = 0;
-    private long lastCheck  = 0;
-    private int  totalFrames = 0, lastFrames = 0;
-
-    class SwapBuffersAction implements Runnable {
-        public void run() {
-            drawable.swapBuffers();
-        }
+    public final void setUpdateFPSFrames(int frames, PrintStream out) {
+        fpsCounter.setUpdateFPSFrames(frames, out);
+    }
+    
+    public final void resetFPSCounter() {
+        fpsCounter.resetFPSCounter();
     }
-    private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
 
-    //----------------------------------------------------------------------
-    // NativeWindow/Window methods
-    //
+    public final int getUpdateFPSFrames() {
+        return fpsCounter.getUpdateFPSFrames();
+    }
+    
+    public final long getFPSStartTime()   {
+        return fpsCounter.getFPSStartTime();
+    }
 
-    public synchronized int lockSurface() throws NativeWindowException {
-        if(null!=drawable) return drawable.getNativeWindow().lockSurface();
-        return NativeWindow.LOCK_SURFACE_NOT_READY;
+    public final long getLastFPSUpdateTime() {
+        return fpsCounter.getLastFPSUpdateTime();
     }
 
-    public synchronized void unlockSurface() {
-        if(null!=drawable) drawable.getNativeWindow().unlockSurface();
-        else throw new NativeWindowException("NEWT-GLWindow not locked");
+    public final long getLastFPSPeriod() {
+        return fpsCounter.getLastFPSPeriod();
+    }
+    
+    public final float getLastFPS() {
+        return fpsCounter.getLastFPS();
+    }
+    
+    public final int getTotalFPSFrames() {
+        return fpsCounter.getTotalFPSFrames();
     }
 
-    public synchronized boolean isSurfaceLocked() {
-        if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked();
-        return false;
+    public final long getTotalFPSDuration() {
+        return fpsCounter.getTotalFPSDuration();
     }
+    
+    public final float getTotalFPS() {
+        return fpsCounter.getTotalFPS();
+    }        
 
-    public synchronized Exception getLockedStack() {
-        if(null!=drawable) return drawable.getNativeWindow().getLockedStack();
-        return null;
+    private class SwapBuffersAction implements Runnable {
+        public final void run() {
+            drawable.swapBuffers();
+        }
     }
+    private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
+
+    //----------------------------------------------------------------------
+    // GLDrawable methods
+    //
 
-    public boolean surfaceSwap() { 
-        if(null!=drawable) return drawable.getNativeWindow().surfaceSwap();
-        return super.surfaceSwap();
+    public final NativeSurface getNativeSurface() {
+        return null!=drawable ? drawable.getNativeSurface() : null;
     }
 
-    public long getWindowHandle() {
-        if(null!=drawable) return drawable.getNativeWindow().getWindowHandle();
-        return window.getWindowHandle();
+    public final long getHandle() {
+        return null!=drawable ? drawable.getHandle() : 0;
     }
 
-    public long getSurfaceHandle() {
-        if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle();
-        return window.getSurfaceHandle();
+    public final int getX() {
+        return window.getX();
     }
 
-    public AbstractGraphicsConfiguration getGraphicsConfiguration() {
-        if(null!=drawable) return drawable.getNativeWindow().getGraphicsConfiguration();
-        return window.getGraphicsConfiguration();
+    public final int getY() {
+        return window.getY();
     }
 
-    //----------------------------------------------------------------------
-    // GLDrawable methods
-    //
+    public final int getWidth() {
+        return window.getWidth();
+    }
 
-    public NativeWindow getNativeWindow() {
-        return null!=drawable ? drawable.getNativeWindow() : null;
+    public final int getHeight() {
+        return window.getHeight();
     }
 
     //----------------------------------------------------------------------
     // GLDrawable methods that are not really needed
     //
 
-    public GLContext createContext(GLContext shareWith) {
+    public final GLContext createContext(GLContext shareWith) {
         return drawable.createContext(shareWith);
     }
 
-    public void setRealized(boolean realized) {
+    public final void setRealized(boolean realized) {
     }
 
-    public GLCapabilities getChosenGLCapabilities() {
+    public final boolean isRealized() {
+        return ( null != drawable ) ? drawable.isRealized() : false;
+    }
+
+    public final GLCapabilitiesImmutable getChosenGLCapabilities() {
         if (drawable == null) {
             throw new GLException("No drawable yet");
         }
@@ -622,7 +693,7 @@ public class GLWindow extends Window implements GLAutoDrawable {
         return drawable.getChosenGLCapabilities();
     }
 
-    public GLProfile getGLProfile() {
+    public final GLProfile getGLProfile() {
         if (drawable == null) {
             throw new GLException("No drawable yet");
         }
@@ -631,10 +702,211 @@ public class GLWindow extends Window implements GLAutoDrawable {
     }
 
     //----------------------------------------------------------------------
-    // Internals only below this point
+    // NEWTEventConsumer 
+    //
+    public boolean consumeEvent(NEWTEvent event) {
+        return window.consumeEvent(event);
+    }
+
+    //----------------------------------------------------------------------
+    // Window completion
+    //
+    public final void windowRepaint(int x, int y, int width, int height) {
+        window.windowRepaint(x, y, width, height);
+    }
+
+    public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) {
+        window.enqueueEvent(wait, event);
+    }
+
+    public final void runOnEDTIfAvail(boolean wait, final Runnable task) {
+        window.runOnEDTIfAvail(wait, task);
+    }
+
+    public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) {
+        return window.getSurfaceUpdatedListener(index);
+    }
+
+    public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() {
+        return window.getSurfaceUpdatedListeners();
+    }
+
+    public final void removeAllSurfaceUpdatedListener() {
+        window.removeAllSurfaceUpdatedListener();
+    }
+
+    public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+        window.removeSurfaceUpdatedListener(l);
+    }
+
+    public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+        window.addSurfaceUpdatedListener(l);
+    }
+
+    public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+        window.addSurfaceUpdatedListener(index, l);
+    }
+
+    public void sendWindowEvent(int eventType) {
+        window.sendWindowEvent(eventType);
+    }
+
+    public final WindowListener getWindowListener(int index) {
+        return window.getWindowListener(index);
+    }
+
+    public final WindowListener[] getWindowListeners() {
+        return window.getWindowListeners();
+    }
+
+    public final void removeWindowListener(WindowListener l) {
+        window.removeWindowListener(l);
+    }
+
+    public final void addWindowListener(WindowListener l) {
+        window.addWindowListener(l);
+    }
+
+    public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException {
+        window.addWindowListener(index, l);
+    }
+
+    public final void addKeyListener(KeyListener l) {
+        window.addKeyListener(l);
+    }
+
+    public final void addKeyListener(int index, KeyListener l) {
+        window.addKeyListener(index, l);
+    }
+
+    public final void removeKeyListener(KeyListener l) {
+        window.removeKeyListener(l);
+    }
+
+    public final KeyListener getKeyListener(int index) {
+        return window.getKeyListener(index);
+    }
+
+    public final KeyListener[] getKeyListeners() {
+        return window.getKeyListeners();
+    }
+
+    public final void addMouseListener(MouseListener l) {
+        window.addMouseListener(l);
+    }
+
+    public final void addMouseListener(int index, MouseListener l) {
+        window.addMouseListener(index, l);
+    }
+
+    public final void removeMouseListener(MouseListener l) {
+        window.removeMouseListener(l);
+    }
+
+    public final MouseListener getMouseListener(int index) {
+        return window.getMouseListener(index);
+    }
+
+    public final MouseListener[] getMouseListeners() {
+        return window.getMouseListeners();
+    }
+
+    //----------------------------------------------------------------------
+    // NativeWindow completion
     //
 
-    private void shouldNotCallThis() {
-        throw new NativeWindowException("Should not call this");
+    public final int lockSurface() {
+        return window.lockSurface();
+    }
+
+    public final void unlockSurface() throws NativeWindowException {
+        window.unlockSurface();
+    }
+
+    public final boolean isSurfaceLockedByOtherThread() {
+        return window.isSurfaceLockedByOtherThread();
     }
+
+    public final boolean isSurfaceLocked() {
+        return window.isSurfaceLocked();
+    }
+
+    public final Thread getSurfaceLockOwner() {
+        return window.getSurfaceLockOwner();
+
+    }
+
+    public final boolean surfaceSwap() {
+        return window.surfaceSwap();
+    }
+
+    public final long getWindowHandle() {
+        return window.getWindowHandle();
+
+    }
+
+    public final long getSurfaceHandle() {
+        return window.getSurfaceHandle();
+
+    }
+
+    public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
+        return window.getGraphicsConfiguration();
+    }
+
+    public final long getDisplayHandle() {
+        return window.getDisplayHandle();
+    }
+
+    public final int  getScreenIndex() {
+        return window.getScreenIndex();
+    }
+
+    public final void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+        window.surfaceUpdated(updater, ns, when);
+    }
+
+    /**
+     * A most simple JOGL AWT test entry
+     */
+    public static void main(String args[]) {
+        System.err.println(VersionUtil.getPlatformInfo());
+        System.err.println(GlueGenVersion.getInstance());
+        // System.err.println(NativeWindowVersion.getInstance());
+        System.err.println(JoglVersion.getInstance());
+        System.err.println(NewtVersion.getInstance());
+
+        final GLProfile glp = GLProfile.getDefault();
+        final GLDrawableFactory factory = GLDrawableFactory.getFactory(glp);
+        final List/*<GLCapabilitiesImmutable>*/ availCaps = factory.getAvailableCapabilities(null);
+        for(int i=0; i<availCaps.size(); i++) {
+            System.err.println(availCaps.get(i));
+        }
+        final GLCapabilitiesImmutable caps = new GLCapabilities( glp );
+
+        GLWindow glWindow = GLWindow.create(caps);
+        glWindow.setSize(128, 128);
+
+        glWindow.addGLEventListener(new GLEventListener() {
+            public void init(GLAutoDrawable drawable) {
+                GL gl = drawable.getGL();
+                System.err.println(JoglVersion.getGLInfo(gl, null));
+                System.err.println("Requested: "+drawable.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities());
+                System.err.println("Chosen   : "+drawable.getChosenGLCapabilities());
+            }
+
+            public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+            }
+
+            public void display(GLAutoDrawable drawable) {
+            }
+
+            public void dispose(GLAutoDrawable drawable) {
+            }
+        });
+
+        glWindow.setVisible(true);
+        glWindow.destroy();
+    }
+
 }
http://JogAmp.org git info: FAQ, tutorial and man pages.