From 68c8e39fa8d6e700f0a99241c1a01a435b7f6284 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Tue, 15 Sep 2015 07:50:50 +0200
Subject: Bug 1211: Hardening Condition-Wait from Spurious-Wakeups and
 unintended InterruptedException(s)

Below is an updated list of Condition-Wait classifications
as described in Bug 1211.

This list includes recent changes on GlueGen
regarding this Bug 1211.

A followup commit will address the unit tests.

  - Noncancelable + Persistent-Wait
    - GLMediaPlayerImpl.StreamWorker thread (changed)
        - pauses thread in case of intr

  - Cancelable + Persistent-Wait:
    - LFRingbuffer.getImpl(..)
    - LFRingbuffer.waitForFreeSlots(int)
    - SyncedRingbuffer.getImpl(..)
    - SyncedRingbuffer.waitForFreeSlots(int)
    - FunctionTask.invokeOnNewThread(..) (changed)
    - RunnableTask.invokeOnNewThread(..) (changed)
    - SharedResourceRunner.run()
    - SharedResourceRunner.doAndWait() (changed)
    - SharedResourceRunner.start() (changed)
    - SharedResourceRunner.stop() (changed)
    - GLMediaPlayerImpl.StreamWorker ctor  (changed)
    - GLMediaPlayerImpl caller thread actions do*() (changed)
    - AndroidGLMediaPlayerAPI14.getNextTextureImpl(..) (changed)
    - DisplayImpl.enqueueEvent(..) (changed)
        -> Persistent-Wait
        -> Cancels wait and NEWTEvent
        -> dispatchMessage(NEWTEventTask): always notifyCaller!
    - GLDrawableHelper.invoke(..) (changed)
    - DefaultEDTUtil.waitUntilIdle() (changed)
    - DefaultEDTUtil.waitUntilStopped() (changed)
    - DefaultEDTUtil.invokeImpl(..)  (changed)
    - DefaultEDTUtil.NEDT.run(..)  (changed)
    - AWTEDTUtil.waitUntilStopped(..)  (changed)
    - AWTEDTUtil.invokeImpl(..)  (changed)
    - AWTEDTUtil.NEDT.run(..)  (changed)
    - SWTEDTUtil.invokeImpl(..)  (changed)
    - SWTEDTUtil.waitUntilStopped(..)  (changed)
    - SWTEDTUtil.NEDT.run(..)  (changed)
    - GLWorkerThread.invokeAndWait(..)
    - GLWorkerThread.start() (changed)
    - GLWorkerThread.WorkerRunnable.run() (changed)
    - Animator.run() (changed)
    - AnimatorBase.finishLifecycleAction() (changed)
    - OSXUtil.RunOnMainThread(..) (changed)
    - SingletonInstanceServerSocket.Server.shutdown() (changed)
    - SingletonInstanceServerSocket.Server.start() (changed)
    - com.jogamp.audio.windows.waveout.Mixer.shutdown() (changed)

  - Extending/Using InterruptSource.Thread (changed)
      - DefaultEDTUtil.NEDT
      - AWTEDTUtil.NEDT
      - SWTEDTUtil.NEDT
      - GLWorkerThread.thread
      - Mixer.FillerThread
      - Mixer.MixerThread

  - Using InterruptSource.Thread (changed)
      - TempFileCache
      - LauncherTempFileCache
      - Animator.thread
      - SingletonInstanceServerSocket.Server.serverThread

Deprecated:
    - FunctionTask.invoke(..)  (changed)
        -> on current thread, no wait -> deprecated
    - RunnableTask.invoke(..) (changed)
        -> on current thread, no wait -> deprecated
---
 .../jogamp/newt/opengl/util/NEWTDemoListener.java  | 499 +++++++++++++++++++++
 .../classes/com/jogamp/newt/util/MainThread.java   |  20 +-
 .../newt/util/applet/JOGLNewtAppletBase.java       |  93 +---
 src/newt/classes/jogamp/newt/DefaultEDTUtil.java   |  45 +-
 src/newt/classes/jogamp/newt/DisplayImpl.java      |  14 +-
 .../classes/jogamp/newt/driver/awt/AWTEDTUtil.java |  35 +-
 .../newt/driver/linux/LinuxEventDeviceTracker.java |   5 +-
 .../newt/driver/linux/LinuxMouseTracker.java       |   3 +-
 .../jogamp/newt/driver/macosx/WindowDriver.java    |   3 +-
 .../classes/jogamp/newt/event/NEWTEventTask.java   |   8 +
 src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java   |  33 +-
 11 files changed, 604 insertions(+), 154 deletions(-)
 create mode 100644 src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java

(limited to 'src/newt/classes')

diff --git a/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
new file mode 100644
index 000000000..ca4b51192
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
@@ -0,0 +1,499 @@
+/**
+ * Copyright 2015 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.opengl.util;
+
+import java.net.URLConnection;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+import com.jogamp.nativewindow.ScalableSurface;
+import com.jogamp.newt.Display;
+import com.jogamp.newt.Display.PointerIcon;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.MouseListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.FPSCounter;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GLAnimatorControl;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLRunnable;
+import com.jogamp.opengl.util.Gamma;
+import com.jogamp.opengl.util.PNGPixelRect;
+
+import jogamp.newt.driver.PNGIcon;
+
+public class NEWTDemoListener extends WindowAdapter implements KeyListener, MouseListener {
+    protected final GLWindow glWindow;
+    final PointerIcon[] pointerIcons;
+    int pointerIconIdx = 0;
+    float gamma = 1f;
+    float brightness = 0f;
+    float contrast = 1f;
+    boolean confinedFixedCenter = false;
+
+    public NEWTDemoListener(final GLWindow glWin, final PointerIcon[] pointerIcons) {
+        this.glWindow = glWin;
+        if( null != pointerIcons ) {
+            this.pointerIcons = pointerIcons;
+        } else {
+            this.pointerIcons = createPointerIcons(glWindow);
+        }
+    }
+    public NEWTDemoListener(final GLWindow glWin) {
+        this(glWin, null);
+    }
+
+    protected void printlnState(final String prelude) {
+        System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString());
+    }
+    protected void printlnState(final String prelude, final String post) {
+        System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString()+", "+post);
+    }
+
+    @Override
+    public void keyPressed(final KeyEvent e) {
+        if( e.isAutoRepeat() || e.isConsumed() ) {
+            return;
+        }
+        final int keySymbol = e.getKeySymbol();
+        switch(keySymbol) {
+            case KeyEvent.VK_SPACE:
+                e.setConsumed(true);
+                glWindow.invokeOnCurrentThread(new Runnable() {
+                    public void run() {
+                        if(glWindow.getAnimator().isPaused()) {
+                            glWindow.getAnimator().resume();
+                        } else {
+                            glWindow.getAnimator().pause();
+                        }
+                    } } );
+                break;
+            case KeyEvent.VK_A:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set alwaysontop pre]");
+                        glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
+                        printlnState("[set alwaysontop post]");
+                    } } );
+                break;
+            case KeyEvent.VK_B:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set alwaysonbottom pre]");
+                        glWindow.setAlwaysOnBottom(!glWindow.isAlwaysOnBottom());
+                        printlnState("[set alwaysonbottom post]");
+                    } } );
+                break;
+            case KeyEvent.VK_C:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        if( null != pointerIcons ) {
+                            printlnState("[set pointer-icon pre]");
+                            final PointerIcon currentPI = glWindow.getPointerIcon();
+                            final PointerIcon newPI;
+                            if( pointerIconIdx >= pointerIcons.length ) {
+                                newPI=null;
+                                pointerIconIdx=0;
+                            } else {
+                                newPI=pointerIcons[pointerIconIdx++];
+                            }
+                            glWindow.setPointerIcon( newPI );
+                            printlnState("[set pointer-icon post]", currentPI+" -> "+glWindow.getPointerIcon());
+                        }
+                    } } );
+                break;
+            case KeyEvent.VK_D:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set undecorated pre]");
+                        glWindow.setUndecorated(!glWindow.isUndecorated());
+                        printlnState("[set undecorated post]");
+                    } } );
+                break;
+            case KeyEvent.VK_F:
+                e.setConsumed(true);
+                quitAdapterOff();
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set fullscreen pre]");
+                        if( glWindow.isFullscreen() ) {
+                            glWindow.setFullscreen( false );
+                        } else {
+                            if( e.isAltDown() ) {
+                                glWindow.setFullscreen( null );
+                            } else {
+                                glWindow.setFullscreen( true );
+                            }
+                        }
+                        printlnState("[set fullscreen post]");
+                        quitAdapterOn();
+                    } } );
+                break;
+            case KeyEvent.VK_G:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        final float newGamma = gamma + ( e.isShiftDown() ? -0.1f : 0.1f );
+                        System.err.println("[set gamma]: "+gamma+" -> "+newGamma);
+                        if( Gamma.setDisplayGamma(glWindow, newGamma, brightness, contrast) ) {
+                            gamma = newGamma;
+                        }
+                    } } );
+                break;
+            case KeyEvent.VK_I:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set pointer-visible pre]");
+                        glWindow.setPointerVisible(!glWindow.isPointerVisible());
+                        printlnState("[set pointer-visible post]");
+                    } } );
+                break;
+            case KeyEvent.VK_J:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set pointer-confined pre]", "warp-center: "+e.isShiftDown());
+                        final boolean confine = !glWindow.isPointerConfined();
+                        glWindow.confinePointer(confine);
+                        printlnState("[set pointer-confined post]", "warp-center: "+e.isShiftDown());
+                        if( e.isShiftDown() ) {
+                            setConfinedFixedCenter(confine);
+                        } else if( !confine ) {
+                            setConfinedFixedCenter(false);
+                        }
+                    } } );
+                break;
+            case KeyEvent.VK_M:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        // none:  max-v
+                        // alt:   max-h
+                        // shift: max-hv
+                        // ctrl:  max-off
+                        final boolean horz, vert;
+                        if( e.isControlDown() ) {
+                            horz = false;
+                            vert = false;
+                        } else if( e.isShiftDown() ) {
+                            final boolean bothMax = glWindow.isMaximizedHorz() && glWindow.isMaximizedVert();
+                            horz = !bothMax;
+                            vert = !bothMax;
+                        } else if( !e.isAltDown() ) {
+                            horz = glWindow.isMaximizedHorz();
+                            vert = !glWindow.isMaximizedVert();
+                        } else if( e.isAltDown() ) {
+                            horz = !glWindow.isMaximizedHorz();
+                            vert = glWindow.isMaximizedVert();
+                        } else {
+                            vert = glWindow.isMaximizedVert();
+                            horz = glWindow.isMaximizedHorz();
+                        }
+                        printlnState("[set maximize pre]", "max[vert "+vert+", horz "+horz+"]");
+                        glWindow.setMaximized(horz, vert);
+                        printlnState("[set maximize post]", "max[vert "+vert+", horz "+horz+"]");
+                    } } );
+                break;
+            case KeyEvent.VK_Q:
+                if( quitAdapterEnabled && 0 == e.getModifiers() ) {
+                    System.err.println("QUIT Key "+Thread.currentThread());
+                    quitAdapterShouldQuit = true;
+                }
+                break;
+            case KeyEvent.VK_P:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set position pre]");
+                        glWindow.setPosition(100, 100);
+                        printlnState("[set position post]");
+                    } } );
+                break;
+            case KeyEvent.VK_R:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set resizable pre]");
+                        glWindow.setResizable(!glWindow.isResizable());
+                        printlnState("[set resizable post]");
+                    } } );
+                break;
+            case KeyEvent.VK_S:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set sticky pre]");
+                        glWindow.setSticky(!glWindow.isSticky());
+                        printlnState("[set sticky post]");
+                    } } );
+                break;
+            case KeyEvent.VK_V:
+                e.setConsumed(true);
+                if( e.isControlDown() ) {
+                    glWindow.invoke(false, new GLRunnable() {
+                        @Override
+                        public boolean run(final GLAutoDrawable drawable) {
+                            final GL gl = drawable.getGL();
+                            final int _i = gl.getSwapInterval();
+                            final int i;
+                            switch(_i) {
+                                case  0: i = -1; break;
+                                case -1: i =  1; break;
+                                case  1: i =  0; break;
+                                default: i =  1; break;
+                            }
+                            gl.setSwapInterval(i);
+
+                            final GLAnimatorControl a = drawable.getAnimator();
+                            if( null != a ) {
+                                a.resetFPSCounter();
+                            }
+                            if(drawable instanceof FPSCounter) {
+                                ((FPSCounter)drawable).resetFPSCounter();
+                            }
+                            System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval());
+                            return true;
+                        }
+                    });
+                } else {
+                    glWindow.invokeOnNewThread(null, false, new Runnable() {
+                        public void run() {
+                            final boolean wasVisible = glWindow.isVisible();
+                            {
+                                printlnState("[set visible pre]");
+                                glWindow.setVisible(!wasVisible);
+                                printlnState("[set visible post]");
+                            }
+                            if( wasVisible && !e.isControlDown() ) {
+                                try {
+                                    java.lang.Thread.sleep(5000);
+                                } catch (final InterruptedException e) {
+                                    e.printStackTrace();
+                                }
+                                printlnState("[reset visible pre]");
+                                glWindow.setVisible(true);
+                                printlnState("[reset visible post]");
+                            }
+                    } } );
+                }
+                break;
+            case KeyEvent.VK_W:
+                e.setConsumed(true);
+                glWindow.invokeOnNewThread(null, false, new Runnable() {
+                    public void run() {
+                        printlnState("[set pointer-pos pre]");
+                        glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2);
+                        printlnState("[set pointer-pos post]");
+                    } } );
+                break;
+            case KeyEvent.VK_X:
+                e.setConsumed(true);
+                final float[] hadSurfacePixelScale = glWindow.getCurrentSurfaceScale(new float[2]);
+                final float[] reqSurfacePixelScale;
+                if( hadSurfacePixelScale[0] == ScalableSurface.IDENTITY_PIXELSCALE ) {
+                    reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+                } else {
+                    reqSurfacePixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+                }
+                System.err.println("[set PixelScale pre]: had "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" -> req "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]);
+                glWindow.setSurfaceScale(reqSurfacePixelScale);
+                final float[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new float[2]);
+                final float[] hasSurfacePixelScale1 = glWindow.getCurrentSurfaceScale(new float[2]);
+                System.err.println("[set PixelScale post]: "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" (had) -> "+
+                        reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+
+                        valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+
+                        hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)");
+                setTitle();
+        }
+    }
+    @Override
+    public void keyReleased(final KeyEvent e) { }
+
+    public void setConfinedFixedCenter(final boolean v) {
+        confinedFixedCenter = v;
+    }
+    @Override
+    public void mouseMoved(final MouseEvent e) {
+        if( e.isConfined() ) {
+            mouseCenterWarp(e);
+        }
+    }
+    @Override
+    public void mouseDragged(final MouseEvent e) {
+        if( e.isConfined() ) {
+            mouseCenterWarp(e);
+        }
+    }
+    @Override
+    public void mouseClicked(final MouseEvent e) {
+        if(e.getClickCount() == 2 && e.getPointerCount() == 1) {
+            glWindow.setFullscreen(!glWindow.isFullscreen());
+            System.err.println("setFullscreen: "+glWindow.isFullscreen());
+        }
+    }
+    private void mouseCenterWarp(final MouseEvent e) {
+        if(e.isConfined() && confinedFixedCenter ) {
+            final int x=glWindow.getSurfaceWidth()/2;
+            final int y=glWindow.getSurfaceHeight()/2;
+            glWindow.warpPointer(x, y);
+        }
+    }
+    @Override
+    public void mouseEntered(final MouseEvent e) {}
+    @Override
+    public void mouseExited(final MouseEvent e) {}
+    @Override
+    public void mousePressed(final MouseEvent e) {}
+    @Override
+    public void mouseReleased(final MouseEvent e) {}
+    @Override
+    public void mouseWheelMoved(final MouseEvent e) {}
+
+    /////////////////////////////////////////////////////////////
+
+    private boolean quitAdapterShouldQuit = false;
+    private boolean quitAdapterEnabled = false;
+    private boolean quitAdapterEnabled2 = true;
+
+    protected void quitAdapterOff() {
+        quitAdapterEnabled2 = false;
+    }
+    protected void quitAdapterOn() {
+        clearQuitAdapter();
+        quitAdapterEnabled2 = true;
+    }
+    public void quitAdapterEnable(final boolean v) { quitAdapterEnabled = v; }
+    public void clearQuitAdapter() { quitAdapterShouldQuit = false; }
+    public boolean shouldQuit() { return quitAdapterShouldQuit; }
+    public void doQuit() { quitAdapterShouldQuit=true; }
+
+    public void windowDestroyNotify(final WindowEvent e) {
+        if( quitAdapterEnabled && quitAdapterEnabled2 ) {
+            System.err.println("QUIT Window "+Thread.currentThread());
+            quitAdapterShouldQuit = true;
+        }
+    }
+
+    /////////////////////////////////////////////////////////////
+
+    public void setTitle() {
+        setTitle(glWindow);
+    }
+    public static void setTitle(final GLWindow win) {
+        final CapabilitiesImmutable chosenCaps = win.getChosenCapabilities();
+        final CapabilitiesImmutable reqCaps = win.getRequestedCapabilities();
+        final CapabilitiesImmutable caps = null != chosenCaps ? chosenCaps : reqCaps;
+        final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl";
+        final float[] sDPI = win.getPixelsPerMM(new float[2]);
+        sDPI[0] *= 25.4f;
+        sDPI[1] *= 25.4f;
+        win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]);
+    }
+
+    public static PointerIcon[] createPointerIcons(final GLWindow glWindow) {
+        final PointerIcon[] pointerIcons = { null, null, null, null, null };
+        {
+            final Display disp = glWindow.getScreen().getDisplay();
+            disp.createNative();
+            int idx = 0;
+            {
+                PointerIcon _pointerIcon = null;
+                final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } );
+                try {
+                    _pointerIcon = disp.createPointerIcon(res, 8, 8);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+                } catch (final Exception e) {
+                    e.printStackTrace();
+                }
+                pointerIcons[idx] = _pointerIcon;
+            }
+            idx++;
+            {
+                PointerIcon _pointerIcon = null;
+                final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } );
+                try {
+                    _pointerIcon = disp.createPointerIcon(res, 0, 0);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+                } catch (final Exception e) {
+                    e.printStackTrace();
+                }
+                pointerIcons[idx] = _pointerIcon;
+            }
+            idx++;
+            {
+                PointerIcon _pointerIcon = null;
+                final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-red-alpha-64x64.png" } );
+                try {
+                    _pointerIcon = disp.createPointerIcon(res, 0, 0);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+                } catch (final Exception e) {
+                    e.printStackTrace();
+                }
+                pointerIcons[idx] = _pointerIcon;
+            }
+            idx++;
+            {
+                PointerIcon _pointerIcon = null;
+                final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-blue-alpha-64x64.png" } );
+                try {
+                    _pointerIcon = disp.createPointerIcon(res, 0, 0);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+                } catch (final Exception e) {
+                    e.printStackTrace();
+                }
+                pointerIcons[idx] = _pointerIcon;
+            }
+            idx++;
+            if( PNGIcon.isAvailable() ) {
+                PointerIcon _pointerIcon = null;
+                final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } );
+                try {
+                    final URLConnection urlConn = res.resolve(0);
+                    final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, image.toString());
+                    _pointerIcon = disp.createPointerIcon(image, 32, 0);
+                    System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString());
+                } catch (final Exception e) {
+                    e.printStackTrace();
+                }
+                pointerIcons[idx] = _pointerIcon;
+            }
+            idx++;
+        }
+        return pointerIcons;
+    }
+}
\ No newline at end of file
diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java
index 8bf4bc20f..05df63794 100644
--- a/src/newt/classes/com/jogamp/newt/util/MainThread.java
+++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java
@@ -45,6 +45,7 @@ import java.util.List;
 import com.jogamp.nativewindow.NativeWindowFactory;
 
 import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
 import com.jogamp.common.util.PropertyAccess;
 import com.jogamp.common.util.ReflectionUtil;
 
@@ -171,15 +172,14 @@ public class MainThread {
         return res;
     }
 
-    static class UserApp extends Thread {
+    static class UserApp extends InterruptSource.Thread {
         private final String mainClassNameShort;
         private final String mainClassName;
         private final String[] mainClassArgs;
         private final Method mainClassMain;
-        private List<Thread> nonDaemonThreadsAtStart;
+        private List<java.lang.Thread> nonDaemonThreadsAtStart;
 
         public UserApp(final String mainClassName, final String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
-            super();
             this.mainClassName=mainClassName;
             this.mainClassArgs=mainClassArgs;
 
@@ -200,10 +200,10 @@ public class MainThread {
         @Override
         public void run() {
             nonDaemonThreadsAtStart = getNonDaemonThreads();
-            if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart);
+            if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart);
             // start user app ..
             try {
-                if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName);
+                if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" invoke "+mainClassName);
                 mainClassMain.invoke(null, new Object[] { mainClassArgs } );
             } catch (final InvocationTargetException ite) {
                 ite.getTargetException().printStackTrace();
@@ -219,30 +219,30 @@ public class MainThread {
                 while( 0 < ( ndtr = getNonDaemonThreadCount(nonDaemonThreadsAtStart) ) ) {
                     if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr);
                     try {
-                        Thread.sleep(1000);
+                        java.lang.Thread.sleep(1000);
                     } catch (final InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
-                if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin: "+ndtr);
+                if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" user app fin: "+ndtr);
             }
 
             if ( useMainThread ) {
                 if(isMacOSX) {
                     try {
                         if(DEBUG) {
-                            System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0");
+                            System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.0");
                         }
                         ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication",
                             null, null, MainThread.class.getClassLoader());
                         if(DEBUG) {
-                            System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X");
+                            System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.X");
                         }
                     } catch (final Exception e) {
                         e.printStackTrace();
                     }
                 } else {
-                    if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)");
+                    if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" MainAction fin - System.exit(0)");
                     System.exit(0);
                 }
             }
diff --git a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
index c2cf64da2..e02e02013 100644
--- a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
+++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
@@ -33,7 +33,6 @@ import java.security.PrivilegedAction;
 
 import com.jogamp.nativewindow.NativeWindow;
 import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode;
-import com.jogamp.nativewindow.util.InsetsImmutable;
 import com.jogamp.opengl.FPSCounter;
 import com.jogamp.opengl.GL;
 import com.jogamp.opengl.GLAutoDrawable;
@@ -43,16 +42,17 @@ import com.jogamp.opengl.GLPipelineFactory;
 import jogamp.newt.Debug;
 
 import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptSource;
 import com.jogamp.newt.Display;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.Display.PointerIcon;
-import com.jogamp.newt.event.KeyEvent;
 import com.jogamp.newt.event.KeyListener;
 import com.jogamp.newt.event.MouseListener;
 import com.jogamp.newt.event.WindowAdapter;
 import com.jogamp.newt.event.WindowEvent;
 import com.jogamp.newt.event.WindowListener;
 import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.newt.opengl.util.NEWTDemoListener;
 import com.jogamp.opengl.util.Animator;
 import com.jogamp.opengl.util.AnimatorBase;
 
@@ -60,7 +60,7 @@ import com.jogamp.opengl.util.AnimatorBase;
 /** Shows how to deploy an applet using JOGL. This demo must be
     referenced from a web page via an &lt;applet&gt; tag. */
 
-public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
+public class JOGLNewtAppletBase implements GLEventListener {
     public static final boolean DEBUG = Debug.debug("Applet");
 
     String glEventListenerClazzName;
@@ -194,7 +194,9 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
             }
 
             if(!noDefaultKeyListener) {
-                glWindow.addKeyListener(this);
+                final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow);
+                glWindow.addKeyListener(newtDemoListener);
+                glWindow.addMouseListener(newtDemoListener);
             }
 
             glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err);
@@ -220,7 +222,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
                 null == glWindow.getParent() && null != parentWin && 0 != parentWin.getWindowHandle() )
             {
                 // we may be called directly by the native EDT
-                new Thread(new Runnable() {
+                new InterruptSource.Thread(null, new Runnable() {
                    @Override
                    public void run() {
                     if( glWindow.isNativeValid() && null != parentWin && 0 != parentWin.getWindowHandle() ) {
@@ -303,86 +305,5 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
     public void dispose(final GLAutoDrawable drawable) {
     }
 
-    // ***********************************************************************************
-    // ***********************************************************************************
-    // ***********************************************************************************
-
-    @Override
-    public void keyPressed(final KeyEvent e) {
-       if( !e.isPrintableKey() || e.isAutoRepeat() ) {
-           return;
-       }
-       if(e.getKeyChar()=='d') {
-           new Thread() {
-               public void run() {
-                   glWindow.setUndecorated(!glWindow.isUndecorated());
-               } }.start();
-       } if(e.getKeyChar()=='f') {
-           new Thread() {
-               public void run() {
-                   glWindow.setFullscreen(!glWindow.isFullscreen());
-               } }.start();
-       } else if(e.getKeyChar()=='a') {
-           new Thread() {
-               public void run() {
-                   glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop());
-               } }.start();
-       } else if(e.getKeyChar()=='r' && null!=parentWin) {
-           new Thread() {
-               public void run() {
-                   if(null == glWindow.getParent()) {
-                       glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */);
-                   } else {
-                       final InsetsImmutable insets = glWindow.getInsets();
-                       final int x, y;
-                       if ( 0 >= insets.getTopHeight() ) {
-                           // fail safe ..
-                           x = 32;
-                           y = 32;
-                       } else {
-                           x = insets.getLeftWidth();
-                           y = insets.getTopHeight();
-                       }
-                       glWindow.reparentWindow(null, x, y, 0 /* hints */);
-                       glWindow.setDefaultCloseOperation( glClosable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE );
-                   }
-               } }.start();
-       } else if(e.getKeyChar()=='c') {
-           new Thread() {
-               public void run() {
-                   System.err.println("[set pointer-icon pre]");
-                   final PointerIcon currentPI = glWindow.getPointerIcon();
-                   glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest);
-                   System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon());
-               } }.start();
-       } else if(e.getKeyChar()=='i') {
-           new Thread() {
-               public void run() {
-                   System.err.println("[set mouse visible pre]: "+glWindow.isPointerVisible());
-                   glWindow.setPointerVisible(!glWindow.isPointerVisible());
-                   System.err.println("[set mouse visible post]: "+glWindow.isPointerVisible());
-               } }.start();
-       } else if(e.getKeyChar()=='j') {
-           new Thread() {
-               public void run() {
-                    final Thread t = glWindow.setExclusiveContextThread(null);
-                    System.err.println("[set mouse confined pre]: "+glWindow.isPointerConfined());
-                    glWindow.confinePointer(!glWindow.isPointerConfined());
-                    System.err.println("[set mouse confined post]: "+glWindow.isPointerConfined());
-                    glWindow.setExclusiveContextThread(t);
-               } }.start();
-       } else if(e.getKeyChar()=='w') {
-           new Thread() {
-               public void run() {
-                   System.err.println("[set mouse pos pre]");
-                   glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2);
-                   System.err.println("[set mouse pos post]");
-               } }.start();
-       }
-    }
-
-    @Override
-    public void keyReleased(final KeyEvent e) {
-    }
 }
 
diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
index bf46ce609..ff713410b 100644
--- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java
@@ -44,6 +44,8 @@ import com.jogamp.nativewindow.NativeWindowException;
 import jogamp.common.util.locks.LockDebugUtil;
 
 import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
 import com.jogamp.common.util.RunnableTask;
 import com.jogamp.common.util.locks.Lock;
 import com.jogamp.newt.util.EDTUtil;
@@ -68,7 +70,7 @@ public class DefaultEDTUtil implements EDTUtil {
         this.threadGroup = tg;
         this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
         this.dispatchMessages=dispatchMessages;
-        this.edt = new NEDT(threadGroup, name);
+        this.edt = new NEDT(threadGroup, this.name);
         this.edt.setDaemon(true); // don't stop JVM from shutdown ..
     }
 
@@ -169,8 +171,7 @@ public class DefaultEDTUtil implements EDTUtil {
     };
 
     private final boolean invokeImpl(boolean wait, Runnable task, final boolean stop, final boolean provokeError) {
-        Throwable throwable = null;
-        RunnableTask rTask = null;
+        final RunnableTask rTask;
         final Object rTaskLock = new Object();
         synchronized(rTaskLock) { // lock the optional task execution
             synchronized(edtLock) { // lock the EDT status
@@ -187,6 +188,7 @@ public class DefaultEDTUtil implements EDTUtil {
                         task.run();
                     }
                     wait = false; // running in same thread (EDT) -> no wait
+                    rTask = null;
                     if( stop ) {
                         edt.shouldStop = true;
                         if( edt.tasks.size()>0 ) {
@@ -230,18 +232,19 @@ public class DefaultEDTUtil implements EDTUtil {
                         }
                     } else {
                         wait = false;
+                        rTask = null;
                     }
                 }
             }
             if( wait ) {
                 try {
-                    rTaskLock.wait(); // free lock, allow execution of rTask
+                    while( rTask.isInQueue() ) {
+                        rTaskLock.wait(); // free lock, allow execution of rTask
+                    }
                 } catch (final InterruptedException ie) {
-                    throwable = ie;
-                }
-                if(null==throwable) {
-                    throwable = rTask.getThrowable();
+                    throw new InterruptedRuntimeException(ie);
                 }
+                final Throwable throwable = rTask.getThrowable();
                 if(null!=throwable) {
                     if(throwable instanceof NativeWindowException) {
                         throw (NativeWindowException)throwable;
@@ -268,13 +271,13 @@ public class DefaultEDTUtil implements EDTUtil {
             return false;
         }
         synchronized(_edt.tasks) {
-            while(_edt.isRunning && _edt.tasks.size()>0) {
-                try {
+            try {
+                while(_edt.isRunning && _edt.tasks.size()>0) {
                     _edt.tasks.notifyAll();
                     _edt.tasks.wait();
-                } catch (final InterruptedException e) {
-                    e.printStackTrace();
                 }
+            } catch (final InterruptedException e) {
+                throw new InterruptedRuntimeException(e);
             }
             return true;
         }
@@ -284,12 +287,12 @@ public class DefaultEDTUtil implements EDTUtil {
     final public boolean waitUntilStopped() {
         synchronized(edtLock) {
             if(edt.isRunning && edt != Thread.currentThread() ) {
-                while( edt.isRunning ) {
-                    try {
+                try {
+                    while( edt.isRunning ) {
                         edtLock.wait();
-                    } catch (final InterruptedException e) {
-                        e.printStackTrace();
                     }
+                } catch (final InterruptedException e) {
+                    throw new InterruptedRuntimeException(e);
                 }
                 return true;
             } else {
@@ -298,13 +301,13 @@ public class DefaultEDTUtil implements EDTUtil {
         }
     }
 
-    class NEDT extends Thread {
+    class NEDT extends InterruptSource.Thread {
         volatile boolean shouldStop = false;
         volatile boolean isRunning = false;
         final ArrayList<RunnableTask> tasks = new ArrayList<RunnableTask>(); // one shot tasks
 
         public NEDT(final ThreadGroup tg, final String name) {
-            super(tg, name);
+            super(tg, null, name);
         }
 
         final public boolean isRunning() {
@@ -347,11 +350,11 @@ public class DefaultEDTUtil implements EDTUtil {
                     RunnableTask task = null;
                     synchronized(tasks) {
                         // wait for tasks
-                        if(!shouldStop && tasks.size()==0) {
+                        if( !shouldStop && tasks.size()==0 ) {
                             try {
                                 tasks.wait(pollPeriod);
                             } catch (final InterruptedException e) {
-                                e.printStackTrace();
+                                throw new InterruptedRuntimeException(e);
                             }
                         }
                         // execute one task, if available
@@ -375,7 +378,7 @@ public class DefaultEDTUtil implements EDTUtil {
                         }
                         if(!task.hasWaiter() && null != task.getThrowable()) {
                             // at least dump stack-trace in case nobody waits for result
-                            System.err.println("DefaultEDT.run(): Caught exception occured on thread "+Thread.currentThread().getName()+": "+task.toString());
+                            System.err.println("DefaultEDT.run(): Caught exception occured on thread "+java.lang.Thread.currentThread().getName()+": "+task.toString());
                             task.getThrowable().printStackTrace();
                         }
                     }
diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java
index cc1f3d8e0..c1cd6db32 100644
--- a/src/newt/classes/jogamp/newt/DisplayImpl.java
+++ b/src/newt/classes/jogamp/newt/DisplayImpl.java
@@ -37,6 +37,7 @@ package jogamp.newt;
 import com.jogamp.common.ExceptionUtils;
 import com.jogamp.common.nio.Buffers;
 import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptedRuntimeException;
 import com.jogamp.common.util.ReflectionUtil;
 import com.jogamp.newt.Display;
 import com.jogamp.newt.NewtFactory;
@@ -697,8 +698,9 @@ public abstract class DisplayImpl extends Display {
             } else {
                 throw re;
             }
+        } finally {
+            eventTask.notifyCaller();
         }
-        eventTask.notifyCaller();
     }
 
     @Override
@@ -725,7 +727,10 @@ public abstract class DisplayImpl extends Display {
             }
             if( null != _events ) {
                 for (int i=0; i < _events.size(); i++) {
-                    dispatchMessage(_events.get(i));
+                    final NEWTEventTask e = _events.get(i);
+                    if( !e.isDispatched() ) {
+                        dispatchMessage(e);
+                    }
                 }
             }
         }
@@ -759,11 +764,12 @@ public abstract class DisplayImpl extends Display {
                 haveEvents = true;
                 eventsLock.notifyAll();
             }
-            if( wait ) {
+            while( wait && !eTask.isDispatched() ) {
                 try {
                     lock.wait();
                 } catch (final InterruptedException ie) {
-                    throw new RuntimeException(ie);
+                    eTask.setDispatched(); // Cancels NEWTEvent ..
+                    throw new InterruptedRuntimeException(ie);
                 }
                 if( null != eTask.getException() ) {
                     throw eTask.getException();
diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
index 9d3121635..3d9073769 100644
--- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java
@@ -33,6 +33,8 @@ import java.awt.EventQueue;
 import com.jogamp.nativewindow.NativeWindowException;
 
 import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
 import com.jogamp.common.util.RunnableTask;
 import com.jogamp.common.util.awt.AWTEDTExecutor;
 import com.jogamp.newt.util.EDTUtil;
@@ -54,7 +56,7 @@ public class AWTEDTUtil implements EDTUtil {
         this.threadGroup = tg;
         this.name=Thread.currentThread().getName()+"-"+name+"-EDT-";
         this.dispatchMessages=dispatchMessages;
-        this.nedt = new NEDT(threadGroup, name);
+        this.nedt = new NEDT(threadGroup, this.name);
         this.nedt.setDaemon(true); // don't stop JVM from shutdown ..
     }
 
@@ -132,8 +134,7 @@ public class AWTEDTUtil implements EDTUtil {
     }
 
     private final boolean invokeImpl(boolean wait, final Runnable task, final boolean stop) {
-        Throwable throwable = null;
-        RunnableTask rTask = null;
+        final RunnableTask rTask;
         final Object rTaskLock = new Object();
         synchronized(rTaskLock) { // lock the optional task execution
             synchronized(edtLock) { // lock the EDT status
@@ -150,6 +151,7 @@ public class AWTEDTUtil implements EDTUtil {
                         task.run();
                     }
                     wait = false; // running in same thread (EDT) -> no wait
+                    rTask = null;
                     if(stop) {
                         nedt.shouldStop = true;
                     }
@@ -182,18 +184,21 @@ public class AWTEDTUtil implements EDTUtil {
                                                  true /* always catch and report Exceptions, don't disturb EDT */,
                                                  wait ? null : System.err);
                         AWTEDTExecutor.singleton.invoke(false, rTask);
+                    } else {
+                        wait = false;
+                        rTask = null;
                     }
                 }
             }
             if( wait ) {
                 try {
-                    rTaskLock.wait(); // free lock, allow execution of rTask
+                    while( rTask.isInQueue() ) {
+                        rTaskLock.wait(); // free lock, allow execution of rTask
+                    }
                 } catch (final InterruptedException ie) {
-                    throwable = ie;
-                }
-                if(null==throwable) {
-                    throwable = rTask.getThrowable();
+                    throw new InterruptedRuntimeException(ie);
                 }
+                final Throwable throwable = rTask.getThrowable();
                 if(null!=throwable) {
                     if(throwable instanceof NativeWindowException) {
                         throw (NativeWindowException)throwable;
@@ -227,12 +232,12 @@ public class AWTEDTUtil implements EDTUtil {
     final public boolean waitUntilStopped() {
         synchronized(edtLock) {
             if( nedt.isRunning && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) {
-                while( nedt.isRunning ) {
-                    try {
+                try {
+                    while( nedt.isRunning ) {
                         edtLock.wait();
-                    } catch (final InterruptedException e) {
-                        e.printStackTrace();
                     }
+                } catch (final InterruptedException e) {
+                    throw new InterruptedRuntimeException(e);
                 }
                 return true;
             } else {
@@ -241,13 +246,13 @@ public class AWTEDTUtil implements EDTUtil {
         }
     }
 
-    class NEDT extends Thread {
+    class NEDT extends InterruptSource.Thread {
         volatile boolean shouldStop = false;
         volatile boolean isRunning = false;
         Object sync = new Object();
 
         public NEDT(final ThreadGroup tg, final String name) {
-            super(tg, name);
+            super(tg, null, name);
         }
 
         final public boolean isRunning() {
@@ -286,7 +291,7 @@ public class AWTEDTUtil implements EDTUtil {
                             try {
                                 sync.wait(pollPeriod);
                             } catch (final InterruptedException e) {
-                                e.printStackTrace();
+                                throw new InterruptedRuntimeException(e);
                             }
                         }
                     }
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
index bc0bfaa16..c3b7bff36 100644
--- a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java
@@ -43,6 +43,7 @@ import jogamp.newt.WindowImpl;
 import jogamp.newt.driver.KeyTracker;
 
 import com.jogamp.common.nio.StructAccessor;
+import com.jogamp.common.util.InterruptSource;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.event.InputEvent;
 import com.jogamp.newt.event.WindowEvent;
@@ -63,7 +64,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker {
 
     static {
         ledt = new LinuxEventDeviceTracker();
-        final Thread t = new Thread(ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager");
+        final Thread t = new InterruptSource.Thread(null, ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager");
         t.setDaemon(true);
         t.start();
     }
@@ -153,7 +154,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker {
                         if(number<32&&number>=0) {
                             if(eventDevicePollers[number]==null){
                                 eventDevicePollers[number] = new EventDevicePoller(number);
-                                final Thread t = new Thread(eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number);
+                                final Thread t = new InterruptSource.Thread(null, eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number);
                                 t.setDaemon(true);
                                 t.start();
                             } else if(eventDevicePollers[number].stop) {
diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
index f40728da0..53bb9c3a5 100644
--- a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
+++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java
@@ -37,6 +37,7 @@ import java.io.InputStream;
 import jogamp.newt.WindowImpl;
 import jogamp.newt.driver.MouseTracker;
 
+import com.jogamp.common.util.InterruptSource;
 import com.jogamp.newt.Screen;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.event.MouseEvent;
@@ -55,7 +56,7 @@ public class LinuxMouseTracker implements WindowListener, MouseTracker {
 
     static {
         lmt = new LinuxMouseTracker();
-        final Thread t = new Thread(lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker");
+        final Thread t = new InterruptSource.Thread(null, lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker");
         t.setDaemon(true);
         t.start();
     }
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index a38ba4c13..2bbcdce38 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -34,6 +34,7 @@
 
 package jogamp.newt.driver.macosx;
 
+import com.jogamp.common.util.InterruptSource;
 import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
 import com.jogamp.nativewindow.GraphicsConfigurationFactory;
 import com.jogamp.nativewindow.NativeWindow;
@@ -378,7 +379,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
     }
     private void superSizeChangedOffThread(final boolean defer, final int newWidth, final int newHeight, final boolean force) {
         if( defer ) {
-            new Thread() {
+            new InterruptSource.Thread() {
                 public void run() {
                     WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force);
                 } }.start();
diff --git a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
index 2bdab2796..260a1beb4 100644
--- a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
+++ b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java
@@ -38,19 +38,27 @@ public class NEWTEventTask {
     private final NEWTEvent event;
     private final Object notifyObject;
     private RuntimeException exception;
+    private volatile boolean dispatched;
 
     public NEWTEventTask(final NEWTEvent event, final Object notifyObject) {
         this.event = event ;
         this.notifyObject = notifyObject ;
         this.exception = null;
+        this.dispatched = false;
     }
 
     public final NEWTEvent get() { return event; }
     public final void setException(final RuntimeException e) { exception = e; }
     public final RuntimeException getException() { return exception; }
     public final boolean isCallerWaiting() { return null != notifyObject; }
+    public final boolean isDispatched() { return dispatched; }
+    public final void setDispatched() { dispatched = true; }
 
+    /**
+     * Notifies caller after {@link #setDispatched()}.
+     */
     public void notifyCaller() {
+        setDispatched();
         if(null != notifyObject) {
             synchronized (notifyObject) {
                 notifyObject.notifyAll();
diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
index 9039b6083..9d2b41bbc 100644
--- a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
+++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java
@@ -32,6 +32,8 @@ import com.jogamp.nativewindow.NativeWindowException;
 import jogamp.newt.Debug;
 
 import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
 import com.jogamp.common.util.RunnableTask;
 import com.jogamp.newt.util.EDTUtil;
 
@@ -162,8 +164,7 @@ public class SWTEDTUtil implements EDTUtil {
     }
 
     private final boolean invokeImpl(boolean wait, final Runnable task, boolean stop) {
-        Throwable throwable = null;
-        RunnableTask rTask = null;
+        final RunnableTask rTask;
         final Object rTaskLock = new Object();
         synchronized(rTaskLock) { // lock the optional task execution
             synchronized(edtLock) { // lock the EDT status
@@ -184,6 +185,7 @@ public class SWTEDTUtil implements EDTUtil {
                         task.run();
                     }
                     wait = false; // running in same thread (EDT) -> no wait
+                    rTask = null;
                     if( stop ) {
                         nedt.shouldStop = true;
                     }
@@ -225,18 +227,21 @@ public class SWTEDTUtil implements EDTUtil {
                                                  true /* always catch and report Exceptions, don't disturb EDT */,
                                                  wait ? null : System.err);
                         swtDisplay.asyncExec(rTask);
+                    } else {
+                        wait = false;
+                        rTask = null;
                     }
                 }
             }
             if( wait ) {
                 try {
-                    rTaskLock.wait(); // free lock, allow execution of rTask
+                    while( rTask.isInQueue() ) {
+                        rTaskLock.wait(); // free lock, allow execution of rTask
+                    }
                 } catch (final InterruptedException ie) {
-                    throwable = ie;
-                }
-                if(null==throwable) {
-                    throwable = rTask.getThrowable();
+                    throw new InterruptedRuntimeException(ie);
                 }
+                final Throwable throwable = rTask.getThrowable();
                 if(null!=throwable) {
                     if(throwable instanceof NativeWindowException) {
                         throw (NativeWindowException)throwable;
@@ -274,12 +279,12 @@ public class SWTEDTUtil implements EDTUtil {
             final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null;
             final boolean onSWTEDT = swtT == curT;
             if( nedt.isRunning && nedt != curT && !onSWTEDT ) {
-                while( nedt.isRunning ) {
-                    try {
+                try {
+                    while( nedt.isRunning ) {
                         edtLock.wait();
-                    } catch (final InterruptedException e) {
-                        e.printStackTrace();
                     }
+                } catch (final InterruptedException e) {
+                    throw new InterruptedRuntimeException(e);
                 }
                 return true;
             } else {
@@ -288,13 +293,13 @@ public class SWTEDTUtil implements EDTUtil {
         }
     }
 
-    class NEDT extends Thread {
+    class NEDT extends InterruptSource.Thread {
         volatile boolean shouldStop = false;
         volatile boolean isRunning = false;
         Object sync = new Object();
 
         public NEDT(final ThreadGroup tg, final String name) {
-            super(tg, name);
+            super(tg, null, name);
         }
 
         final public boolean isRunning() {
@@ -337,7 +342,7 @@ public class SWTEDTUtil implements EDTUtil {
                             try {
                                 sync.wait(pollPeriod);
                             } catch (final InterruptedException e) {
-                                e.printStackTrace();
+                                throw new InterruptedRuntimeException(e);
                             }
                         }
                     }
-- 
cgit v1.2.3