From a34d04ad4d9a46a30772b3984baf692a59e8b608 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Tue, 26 Oct 2010 04:35:15 +0200
Subject: NEWT: ScreenMode changes

    - New type definition:
        ScreenMode { MonitorMode { SurfaceSize { Resolution, bpp }, ScreenSizeMM, refreshRate }, rotation },
        where Resolution and ScreenSizeMM are of type DimensionReadOnly

    - ScreenMute instance is
        - immutable
        - hashable
        - cloneable

    The above allows fast query and storage w/o redundancies.
    More than 300 modes via permutation could be expected.

ScreenMode impl. changes:
  ScreenImpl:
    To be implemented methods by native specialization:
        - protected int[] getScreenModeFirstImpl()
        - protected int[] getScreenModeNextImpl()
        - protected ScreenMode getCurrentScreenModeImpl()
        - protected boolean setCurrentScreenModeImpl(ScreenMode screenMode)

    The data unification etc is implemented generic using ScreenModeUtil
    and the 'int[]' streaming.

  ScreenModeStatus holds all ScreenMode related data
  and provides a locking strategy.

  ScreenModeListener provides a callback facility for ScreenMode change events.
    - Screens listen to ScreenModeStatus, so all FQN referenced Screen's receive the change.
    - Windows listen to Screen, to take appropriate action for the event (fullscreen, reshape).

Misc:
    - Screen/Display: promoting 'addReference'/'removeReference' to public interface,
      so a user may trigger construction/destruction (-> junit tests, plus other clients than WindowImpl).

    - Gears: 'setSwapInterval' at 'reshape' instead of 'init',
      so it's reset when ScreenMode is changing.

    -
---
 src/newt/classes/com/jogamp/newt/Display.java      |  47 +-
 src/newt/classes/com/jogamp/newt/Screen.java       | 131 ++--
 src/newt/classes/com/jogamp/newt/ScreenMode.java   | 249 +++++---
 src/newt/classes/com/jogamp/newt/Window.java       |   3 +-
 .../com/jogamp/newt/event/ScreenModeListener.java  |  39 ++
 .../com/jogamp/newt/impl/DefaultEDTUtil.java       |  47 +-
 .../classes/com/jogamp/newt/impl/DisplayImpl.java  |   8 +-
 .../classes/com/jogamp/newt/impl/ScreenImpl.java   | 668 +++++++++++++--------
 .../com/jogamp/newt/impl/ScreenModeStatus.java     | 286 ++++++---
 .../com/jogamp/newt/impl/ScreensModeState.java     |  21 -
 .../classes/com/jogamp/newt/impl/WindowImpl.java   | 136 ++++-
 .../com/jogamp/newt/impl/awt/AWTScreen.java        |   1 -
 .../com/jogamp/newt/impl/intel/gdl/Screen.java     |   4 +-
 .../com/jogamp/newt/impl/macosx/MacScreen.java     |   4 +-
 .../newt/impl/opengl/broadcom/egl/Screen.java      |   2 +-
 .../com/jogamp/newt/impl/opengl/kd/KDScreen.java   |   2 +-
 .../jogamp/newt/impl/windows/WindowsScreen.java    | 194 ++----
 .../com/jogamp/newt/impl/x11/X11Screen.java        | 339 ++++++-----
 .../com/jogamp/newt/impl/x11/X11Window.java        |   1 +
 .../classes/com/jogamp/newt/opengl/GLWindow.java   |   8 +
 .../classes/com/jogamp/newt/util/MonitorMode.java  | 105 ++++
 .../com/jogamp/newt/util/ScreenModeUtil.java       | 367 +++++++++++
 22 files changed, 1851 insertions(+), 811 deletions(-)
 create mode 100644 src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java
 delete mode 100644 src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java
 create mode 100644 src/newt/classes/com/jogamp/newt/util/MonitorMode.java
 create mode 100644 src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java

(limited to 'src/newt/classes/com')

diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java
index b09f63962..7ce20e4bb 100644
--- a/src/newt/classes/com/jogamp/newt/Display.java
+++ b/src/newt/classes/com/jogamp/newt/Display.java
@@ -54,24 +54,69 @@ public abstract class Display {
 
     public abstract void destroy();
 
+    /**
+     * @return the value set by {@link #setDestroyWhenUnused(boolean)}
+     * or the default <code>false</code>.
+     *
+     * @see #addReference()
+     * @see #removeReference()
+     */
     public abstract boolean getDestroyWhenUnused();
 
     /**
+     * Handles the lifecycle of the native Display instance.<br>
+     * If set to <code>true</code>, the last {@link #removeReference()} call
+     * will destroy this instance, otherwise it will stay alive.<br>
+     * Default is <code>false</code>.
      *
-     * @param v
+     * @see #addReference()
+     * @see #removeReference()
      */
     public abstract void setDestroyWhenUnused(boolean v);
 
+    /**
+     * The 1st call will initiate native creation,
+     * since we follow the lazy creation pattern.
+     *
+     * @return number of references after adding one
+     * @see #removeReference()
+     */
+    public abstract int addReference();
+
+    /**
+     * The last call may destroy this instance,
+     * if {@link #getDestroyWhenUnused()} returns <code>true</code>.
+     *
+     * @return number of references after removing one
+     * @see #addReference()
+     * @see #getDestroyWhenUnused()
+     * @see #setDestroyWhenUnused(boolean)
+     */
+    public abstract int removeReference();
+
     public abstract AbstractGraphicsDevice getGraphicsDevice();
 
+    /**
+     * @return the fully qualified Display name,
+     * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()}
+     */
     public abstract String getFQName();
 
     public abstract long getHandle();
 
+    /**
+     * @return this display internal serial id
+     */
     public abstract int getId();
 
+    /**
+     * @return this display instance name as defined at creation time
+     */
     public abstract String getName();
 
+    /**
+     * @return the native display type, ie {@link javax.media.nativewindow.NativeWindowFactory#getNativeWindowType(boolean)}
+     */
     public abstract String getType();
 
     public abstract EDTUtil getEDTUtil();
diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java
index b57e34091..2cea88d19 100644
--- a/src/newt/classes/com/jogamp/newt/Screen.java
+++ b/src/newt/classes/com/jogamp/newt/Screen.java
@@ -25,13 +25,21 @@
  * authors and should not be interpreted as representing official policies, either expressed
  * or implied, of JogAmp Community.
  */
-
 package com.jogamp.newt;
 
+import com.jogamp.newt.event.ScreenModeListener;
 import com.jogamp.newt.impl.Debug;
+import java.util.List;
 import javax.media.nativewindow.AbstractGraphicsScreen;
 
 public interface Screen {
+
+    /**
+     * A 10s timeout for screen mode change. It is observed, that some platforms
+     * need a notable amount of time for this task, especially in case of rotation change.
+     */
+    public static final int SCREEN_MODE_CHANGE_TIMEOUT = 10000;
+
     public static final boolean DEBUG = Debug.debug("Screen");
 
     boolean isNativeValid();
@@ -44,69 +52,106 @@ public interface Screen {
 
     void destroy();
 
+    /**
+     * @return {@link Display#getDestroyWhenUnused()}
+     *
+     * @see #addReference()
+     * @see #removeReference()
+     * @see Display#setDestroyWhenUnused(boolean)
+     */
     boolean getDestroyWhenUnused();
 
+    /**
+     * calls {@link Display#setDestroyWhenUnused(boolean)}.
+     *
+     * @see #addReference()
+     * @see #removeReference()
+     * @see Display#setDestroyWhenUnused(boolean)
+     */
     void setDestroyWhenUnused(boolean v);
 
+    /**
+     * See {@link Display#addReference()}
+     *
+     * @see #removeReference()
+     * @see #setDestroyWhenUnused(boolean)
+     * @see #getDestroyWhenUnused()
+     */
+    int addReference();
+
+    /**
+     * See {@link Display#removeReference()}
+     *
+     * @see #addReference()
+     * @see #setDestroyWhenUnused(boolean)
+     * @see #getDestroyWhenUnused()
+     */
+    int removeReference();
+
     AbstractGraphicsScreen getGraphicsScreen();
 
+    /**
+     * @return this Screen index of all Screens of {@link #getDisplay()}.
+     */
     int getIndex();
 
     /**
-     * The actual implementation shall return the detected display value,
-     * if not we return 800.
-     * This can be overwritten with the user property 'newt.ws.swidth',
+     * @return the current screen width
      */
     int getWidth();
 
     /**
-     * The actual implementation shall return the detected display value,
-     * if not we return 480.
-     * This can be overwritten with the user property 'newt.ws.sheight',
+     * @return the current screen height
      */
     int getHeight();
 
+    /**
+     * @return the associated Display
+     */
     Display getDisplay();
-    
-    /** Get the screen fully qualified name
-     *  which can be used to get the screen controller 
-     *  associated with this screen
+
+    /** 
+     * @return the screen fully qualified Screen name,
+     * which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}.
      */
-    String getScreenFQN();
-    
+    String getFQName();
+
     /**
-     * Get the Current Desktop Screen mode index
-     * returns -1 if functionality not implemented
-     * for screen platform
+     * @param sml ScreenModeListener to be added for ScreenMode change events
      */
-    int getDesktopScreenModeIndex();
-    
-    /** Get the current screen rate
-     *  returns -1 if not natively implemented
+    public void addScreenModeListener(ScreenModeListener sml);
+
+    /**
+     * @param sml ScreenModeListener to be removed from ScreenMode change events
      */
-    short getCurrentScreenRate();
-    
+    public void removeScreenModeListener(ScreenModeListener sml);
+
     /** 
-     * Get list of available screen modes
-     * null if not implemented for screen platform
+     * Return a list of available {@link com.jogamp.newt.ScreenMode}s.
+     * @return a shallow copy of the internal immutable {@link com.jogamp.newt.ScreenMode}s,
+     * or null if not implemented for this native type {@link com.jogamp.newt.Display#getType()}.
      */
-    ScreenMode[] getScreenModes();
-    
-    /** 
-     * change the screen mode
-     * @param modeIndex mode index from the list of available screen modes
-     * @param rate the desired rate should be one of the available rates.
-     */
-    void setScreenMode(int modeIndex, short rate);
-    
-    /** Change the Screen Rotation to 
-     * one of the rotations defined in ScreenMode
-     * @param rot rotation id, example ScreenMode.ROTATE_0
-     */
-    public void setScreenRotation(int rot);
-	
-	/** Get the Current screen rotation
-	 *  returns -1 if not implemented natively
-	 */
-	public int getCurrentScreenRotation();
+    List/*<ScreenMode>*/ getScreenModes();
+
+    /**
+     * Return the original {@link com.jogamp.newt.ScreenMode}, as used at NEWT initialization.
+     * @return null if functionality not implemented,
+     * otherwise the original ScreenMode which is element of the list {@link #getScreenModes()}.
+     *
+     */
+    ScreenMode getOriginalScreenMode();
+
+    /**
+     * Return the current {@link com.jogamp.newt.ScreenMode}.
+     * @return null if functionality not implemented,
+     * otherwise the current ScreenMode which is element of the list {@link #getScreenModes()}.
+     */
+    ScreenMode getCurrentScreenMode();
+
+    /**
+     * Set the current {@link com.jogamp.newt.ScreenMode}.
+     * @param screenMode to be made current, must be element of the list {@link #getScreenModes()}.
+     * @return true if successful, otherwise false
+     */
+    boolean setCurrentScreenMode(ScreenMode screenMode);
 }
diff --git a/src/newt/classes/com/jogamp/newt/ScreenMode.java b/src/newt/classes/com/jogamp/newt/ScreenMode.java
index f37652a23..8fb5aabb8 100644
--- a/src/newt/classes/com/jogamp/newt/ScreenMode.java
+++ b/src/newt/classes/com/jogamp/newt/ScreenMode.java
@@ -1,76 +1,179 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
 package com.jogamp.newt;
 
-public class ScreenMode {
-	public static final int ROTATE_0   = 0;
-	public static final int ROTATE_90  = 90;
-	public static final int ROTATE_180 = 180;
-	public static final int ROTATE_270 = 270;
-	
-	private int index;
-	private int width;
-	private int height;
-	private int bitsPerPixel = -1;
-	
-	private short[] rates = null;
-
-	public ScreenMode(int index, int width, int height) {
-		this.index = index;
-		this.width = width;
-		this.height = height;
-	}
-	/** Not safe to use this on platforms 
-	 * other than windows. Since the mode ids
-	 * on X11 match the native ids. unlike windows
-	 * where the ids are generated .
-	 * @param index
-	 */
-	public void setIndex(int index) {
-		this.index = index;
-	}
-	public int getIndex() {
-		return index;
-	}
-	public int getWidth() {
-		return width;
-	}
-	public void setWidth(int width) {
-		this.width = width;
-	}
-	public int getHeight() {
-		return height;
-	}
-	public void setHeight(int height) {
-		this.height = height;
-	}
-	public short[] getRates() {
-		return rates;
-	}
-	public void setRates(short[] rates) {
-		this.rates = rates;
-	}
-
-	public int getBitsPerPixel() {
-		return bitsPerPixel;
-	}
-
-	public void setBitsPerPixel(int bitsPerPixel) {
-		this.bitsPerPixel = bitsPerPixel;
-	}
-	
-	public short getHighestAvailableRate(){
-		short highest = rates[0];
-		if(rates.length > 1){
-			for (int i = 1; i < rates.length; i++) {
-				if(rates[i] > highest){
-					highest = rates[i];
-				}
-			}
-		}
-		return highest;
-	}
-	
-	public String toString() {
-		return "ScreenMode: " + this.index + " - " + this.width + " x " 
-			+ this.height + " " + getHighestAvailableRate() + " Hz";
-	}
+import com.jogamp.newt.util.MonitorMode;
+
+/** Immutable ScreenMode Class, consisting of it's read only components:<br>
+ * <ul>
+ *  <li>{@link com.jogamp.newt.util.MonitorMode}</li>
+ *  <li><code>rotation</code></li>
+ * </ul>
+ *
+ * <i>Aquire and filter ScreenModes</i><br>
+ * <ul>
+ *  <li>A List of read only ScreenMode's is being returned by {@link com.jogamp.newt.Screen#getScreenModes()}.</li>
+ *  <li>You may utilize {@link com.jogamp.newt.util.ScreenModeUtil} to filter and select a desired ScreenMode.</li>
+ *  <li>The current ScreenMode can be obtained via {@link com.jogamp.newt.Screen#getCurrentScreenMode()}.</li>
+ *  <li>The initial original ScreenMode (at startup) can be obtained via {@link com.jogamp.newt.Screen#getOriginalScreenMode()}.</li>
+ * </ul>
+ * <br>
+ *
+ * <i>Changing ScreenModes</i><br>
+ * <ul>
+ *  <li> Use {@link com.jogamp.newt.Screen#setCurrentScreenMode(com.jogamp.newt.ScreenMode)}</li>
+ *       to change the current ScreenMode of all Screen's referenced via the full qualified name (FQN)
+ *       {@link com.jogamp.newt.Screen#getFQName()}.</li>
+ *  <li> When the last FQN referenced Screen closes, the original ScreenMode ({@link com.jogamp.newt.Screen#getOriginalScreenMode()})
+ * is restored.</li>
+ * </ul>
+ * <br>
+ * Example for changing the ScreenMode:
+ * <pre>
+        // determine target refresh rate
+        ScreenMode orig = screen.getOriginalScreenMode();
+        int freq = orig.getMonitorMode().getRefreshRate();
+
+        // target resolution
+        Dimension res = new Dimension(800, 600);
+
+        // target rotation
+        int rot = 0;
+
+        // filter available ScreenModes
+        List screenModes = screen.getScreenModes();
+        screenModes = ScreenModeUtil.filterByRate(screenModes, freq); // get the nearest ones
+        screenModes = ScreenModeUtil.filterByRotation(screenModes, rot);
+        screenModes = ScreenModeUtil.filterByResolution(screenModes, res); // get the nearest ones
+        screenModes = ScreenModeUtil.getHighestAvailableBpp(screenModes);
+
+        // pick 1st one ..
+        screen.setCurrentScreenMode((ScreenMode) screenModes.get(0)); 
+ * </pre>
+ *
+ * X11 / AMD just works<br>
+ * <br>
+ * X11 / NVidia difficulties
+ * <pre>
+    NVidia RANDR RefreshRate Bug
+        If NVidia's 'DynamicTwinView' is enabled, all refresh rates are
+        unique, ie consequent numbers starting with the default refresh, ie 50, 51, ..
+        The only way to workaround it is to disable 'DynamicTwinView'.
+        Read: http://us.download.nvidia.com/XFree86/Linux-x86/260.19.12/README/configtwinview.html
+
+        Check to see if 'DynamicTwinView' is enable:
+            nvidia-settings -q :0/DynamicTwinview
+
+        To disable it (workaround), add the following option to your xorg.conf device section:
+            Option "DynamicTwinView" "False"
+
+    NVidia RANDR Rotation:
+        To enable it, add the following option to your xorg.conf device section:
+            Option "RandRRotation" "on"
+ * </pre>
+ *
+ */
+public class ScreenMode implements Cloneable {
+    public static final int ROTATE_0   = 0;
+    public static final int ROTATE_90  = 90;
+    public static final int ROTATE_180 = 180;
+    public static final int ROTATE_270 = 270;
+
+    MonitorMode monitorMode;
+    int rotation;
+
+    public static boolean isRotationValid(int rotation) {
+        return rotation == ScreenMode.ROTATE_0 || rotation == ScreenMode.ROTATE_90 ||
+               rotation == ScreenMode.ROTATE_180 || rotation == ScreenMode.ROTATE_270 ;
+    }
+
+    /**
+     * @param monitorMode the monitor mode
+     * @param rotation the screen rotation
+     */
+    public ScreenMode(MonitorMode monitorMode, int rotation) {
+        if ( !isRotationValid(rotation) ) {
+            throw new RuntimeException("invalid rotation: "+rotation);
+        }
+        this.monitorMode = monitorMode;
+        this.rotation = rotation;
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException ex) {
+            throw new InternalError();
+        }
+    }
+
+    public final MonitorMode getMonitorMode() {
+        return monitorMode;
+    }
+
+    public final int getRotation() {
+        return rotation;
+    }
+
+    public final String toString() {
+        return "ScreenMode[" +  getMonitorMode() + ", " + rotation + " degr]";
+    }
+
+    /**
+     * Tests equality of two <code>ScreenMode</code> objects 
+     * by evaluating equality of it's components:<br>
+     * <ul>
+     *  <li><code>monitorMode</code></li>
+     *  <li><code>rotation</code></li>
+     * </ul>
+     * <br>
+     */
+    public final boolean equals(Object obj) {
+        if (obj instanceof ScreenMode) {
+            ScreenMode sm = (ScreenMode)obj;
+            return sm.getMonitorMode().equals(getMonitorMode()) &&
+                   sm.getRotation() == this.getRotation() ;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a combined hash code of it's elements:<br>
+     * <ul>
+     *  <li><code>monitorMode</code></li>
+     *  <li><code>rotation</code></li>
+     * </ul>
+     */
+    public final int hashCode() {
+        // 31 * x == (x << 5) - x
+        int hash = 31 + getMonitorMode().hashCode();
+        hash = ((hash << 5) - hash) + getRotation();
+        return hash;
+    }
 }
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index 7e1a55b21..1be5949fe 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -31,6 +31,7 @@ package com.jogamp.newt;
 import com.jogamp.newt.event.WindowListener;
 import com.jogamp.newt.event.KeyListener;
 import com.jogamp.newt.event.MouseListener;
+import com.jogamp.newt.event.ScreenModeListener;
 import com.jogamp.newt.impl.Debug;
 import javax.media.nativewindow.Capabilities;
 import javax.media.nativewindow.NativeWindow;
@@ -42,7 +43,7 @@ import javax.media.nativewindow.util.Point;
  * Specifying the public Window functionality for the
  * using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}.
  */
-public interface Window extends NativeWindow {
+public interface Window extends NativeWindow, ScreenModeListener {
     public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent");
     public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent");
     public static final boolean DEBUG_WINDOW_EVENT = Debug.debug("Window.WindowEvent");
diff --git a/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java b/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java
new file mode 100644
index 000000000..7bca23cfe
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.newt.event;
+
+import com.jogamp.newt.ScreenMode;
+
+public interface ScreenModeListener {
+    /** called before the screen mode will be changed */
+    void screenModeChangeNotify(ScreenMode sm);
+
+    /** called after the screen mode has been changed */
+    void screenModeChanged(ScreenMode sm, boolean success);
+}
diff --git a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java
index ce204cd25..0fdfd44fe 100644
--- a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java
+++ b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java
@@ -64,8 +64,10 @@ public class DefaultEDTUtil implements EDTUtil {
             waitUntilStopped();
             if(DEBUG) {
                 if(edt.tasks.size()>0) {
-                    Throwable t = new Throwable("Warning: EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt);
-                    t.printStackTrace();
+                    String msg = Thread.currentThread()+": EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt;
+                    System.err.println(msg);
+                    // Throwable t = new Throwable(msg);
+                    // t.printStackTrace();
                 }
                 System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt);
             }
@@ -75,7 +77,7 @@ public class DefaultEDTUtil implements EDTUtil {
 
     public final void start() {
         synchronized(edtLock) { 
-            if(!edt.isRunning()) {
+            if(!edt.isRunning() && !edt.shouldStop) {
                 if(edt.isAlive()) {
                     throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size());
                 }
@@ -83,7 +85,10 @@ public class DefaultEDTUtil implements EDTUtil {
                 edt.setName(name+start_iter);
                 edt.shouldStop = false;
                 if(DEBUG) {
-                    System.err.println(Thread.currentThread()+": EDT START - edt: "+edt);
+                    String msg = Thread.currentThread()+": EDT START - edt: "+edt;
+                    System.err.println(msg);
+                    // Throwable t = new Throwable(msg);
+                    // t.printStackTrace();
                 }
                 edt.start();
             }
@@ -128,8 +133,10 @@ public class DefaultEDTUtil implements EDTUtil {
                 if(stop) {
                     edt.shouldStop = true;
                     if(DEBUG) {
-                        System.err.println(Thread.currentThread()+
-                                           ": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - edt: "+edt);
+                        String msg = Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - edt: "+edt;
+                        System.err.println(msg);
+                        // Throwable t = new Throwable(msg);
+                        // t.printStackTrace();
                     }
                 }
                 if( isCurrentThreadEDT() ) {
@@ -140,14 +147,15 @@ public class DefaultEDTUtil implements EDTUtil {
                         t.printStackTrace();
                     }
                 } else {
-                    start(); // start if not started yet
-                    rTask = new RunnableTask(task,
-                                             wait ? rTaskLock : null,
-                                             wait /* catch Exceptions if waiting for result */);
-                    if(stop) {
-                        rTask.setAttachment(new Boolean(true)); // mark final task
-                    }
                     synchronized(edt.tasks) {
+                        start(); // start if not started yet and !shouldStop
+                        wait = wait && edt.isRunning();
+                        rTask = new RunnableTask(task,
+                                                 wait ? rTaskLock : null,
+                                                 wait /* catch Exceptions if waiting for result */);
+                        if(stop) {
+                            rTask.setAttachment(new Boolean(true)); // mark final task
+                        }
                         // append task ..
                         edt.tasks.add(rTask);
                         edt.tasks.notifyAll();
@@ -178,6 +186,7 @@ public class DefaultEDTUtil implements EDTUtil {
             synchronized(edt.tasks) {
                 while(edt.isRunning() && edt.tasks.size()>0) {
                     try {
+                        edt.tasks.notifyAll();
                         edt.tasks.wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
@@ -190,11 +199,13 @@ public class DefaultEDTUtil implements EDTUtil {
     public void waitUntilStopped() {
         if(edt.isRunning() && edt != Thread.currentThread() ) {
             synchronized(edtLock) {
-                while(edt.isRunning()) {
-                    try {
-                        edtLock.wait();
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
+                if(edt.isRunning() && edt != Thread.currentThread() ) {
+                    while(edt.isRunning()) {
+                        try {
+                            edtLock.wait();
+                        } catch (InterruptedException e) {
+                            e.printStackTrace();
+                        }
                     }
                 }
             }
diff --git a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java
index 840411984..30b3cc409 100644
--- a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java
+++ b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java
@@ -81,7 +81,7 @@ public abstract class DisplayImpl extends Display {
             display.refCount=0;
             synchronized(displayList) {
                 display.id = serialno++;
-                display.fqname = getFQName(display.id, display.type, display.name);
+                display.fqname = getFQName(display.type, display.name, display.id);
                 displayList.add(display);
             }
             display.createEDTUtil();
@@ -191,7 +191,7 @@ public abstract class DisplayImpl extends Display {
         }
     }
 
-    protected synchronized final int addReference() {
+    public synchronized final int addReference() {
         if(DEBUG) {
             System.err.println("Display.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1));
         }
@@ -205,7 +205,7 @@ public abstract class DisplayImpl extends Display {
     }
 
 
-    protected synchronized final int removeReference() {
+    public synchronized final int removeReference() {
         if(DEBUG) {
             System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1));
         }
@@ -251,7 +251,7 @@ public abstract class DisplayImpl extends Display {
         return ( null == name ) ? nilString : name ;
     }
 
-    public static final String getFQName(int id, String type, String name) {
+    protected static final String getFQName(String type, String name, int id) {
         if(null==type) type=nilString;
         if(null==name) name=nilString;
         StringBuffer sb = new StringBuffer();
diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java
index 37a751fe1..9dc1c1bcc 100644
--- a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java
+++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java
@@ -34,259 +34,429 @@
 
 package com.jogamp.newt.impl;
 
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.common.util.IntIntHashMap;
+import com.jogamp.newt.Display;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Screen;
 import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.*;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.ScreenModeListener;
+import com.jogamp.newt.util.ScreenModeUtil;
 
 import javax.media.nativewindow.*;
 
 import java.security.*;
-
-public abstract class ScreenImpl implements Screen {
-	protected DisplayImpl display;
-	protected int idx;
-	protected AbstractGraphicsScreen aScreen;
-	protected int refCount; // number of Screen references by Window
-	protected int width=-1, height=-1; // detected values: set using setScreenSize
-	protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight
-	private static AccessControlContext localACC = AccessController.getContext();
-
-
-	protected static ScreensModeState screensModeState = new ScreensModeState(); // hold all screen mode controllers
-	private String screenFQN = null; // string fully qualified name
-
-	private static Class getScreenClass(String type) 
-	throws ClassNotFoundException 
-	{
-		Class screenClass = NewtFactory.getCustomClass(type, "Screen");
-		if(null==screenClass) {
-			if (NativeWindowFactory.TYPE_EGL.equals(type)) {
-				screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen");
-			} else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) {
-				screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen");
-			} else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) {
-				screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen");
-			} else if (NativeWindowFactory.TYPE_X11.equals(type)) {
-				screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen");
-			} else if (NativeWindowFactory.TYPE_AWT.equals(type)) {
-				screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen");
-			} else {
-				throw new RuntimeException("Unknown window type \"" + type + "\"");
-			}
-		}
-		return screenClass;
-	}
-
-	public static ScreenImpl create(String type, Display display, final int idx) {
-		try {
-			if(usrWidth<0 || usrHeight<0) {
-				usrWidth  = Debug.getIntProperty("newt.ws.swidth", true, localACC);
-				usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC);
-				if(usrWidth>0 || usrHeight>0) {
-					System.err.println("User screen size "+usrWidth+"x"+usrHeight);
-				}
-			}
-			Class screenClass = getScreenClass(type);
-			ScreenImpl screen  = (ScreenImpl) screenClass.newInstance();
-			screen.display = (DisplayImpl) display;
-			screen.idx = idx;
-
-			return screen;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	protected  synchronized final void createNative() {
-		if(null == aScreen) {
-			if(DEBUG) {
-				System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")");
-			}
-			display.addReference();
-			createNativeImpl();
-			if(null == aScreen) {
-				throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen");
-			}
-			if(DEBUG) {
-				System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")");
-			}
-		}
-
-		initScreenModes();
-	}
-
-	/** Retrieve screen modes
-	 * and screen rate initializing the status
-	 * of the screen mode
-	 */
-	private void initScreenModes(){
-		ScreenMode[] screenModes = getScreenModes();
-		String screenFQN = display.getFQName()+idx;
-		setScreenFQN(screenFQN);
-		ScreenModeStatus screenModeStatus = new ScreenModeStatus(screenFQN , 
-				getDesktopScreenModeIndex(), getCurrentScreenRate(),getCurrentScreenRotation());
-		screenModeStatus.setScreenModes(screenModes);
-
-		screensModeState.setScreenModeController(screenModeStatus);
-	}
-
-	private void resetScreenMode() {
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		
-		/**Revert the screen mode and rate 
-		 * to original state of creation
-		 */
-		if(!sms.isOriginalMode()) {
-			setScreenMode(sms.getOriginalScreenMode(), 
-					sms.getOriginalScreenRate());
-		}
-		/**Revert Screen Rotation
-		 * to original value
-		 */
-		if(!sms.isOriginalRotation()) {
-			setScreenRotation(sms.getOriginalScreenRotation());
-		}
-	}
-
-	public synchronized final void destroy() {
-		resetScreenMode();
-
-		if ( null != aScreen ) {
-			closeNativeImpl();
-			aScreen = null;
-		}
-		refCount = 0;
-		display.removeReference();
-	}
-
-	protected synchronized final int addReference() {
-		if(DEBUG) {
-			System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1));
-		}
-		if ( 0 == refCount ) {
-			createNative();
-		}
-		if(null == aScreen) {
-			throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen");
-		}
-		return ++refCount;
-	}
-
-	protected synchronized final int removeReference() {
-		if(DEBUG) {
-			System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1));
-		}
-		refCount--; // could become < 0, in case of forced destruction without actual creation/addReference
-		if(0>=refCount && getDestroyWhenUnused()) {
-			destroy();
-		}
-		return refCount;
-	}
-
-	public synchronized final int getReferenceCount() {
-		return refCount;
-	}
-
-	public final boolean getDestroyWhenUnused() { 
-		return display.getDestroyWhenUnused(); 
-	}
-	public final void setDestroyWhenUnused(boolean v) { 
-		display.setDestroyWhenUnused(v); 
-	}
-
-	protected abstract void createNativeImpl();
-	protected abstract void closeNativeImpl();
-
-	public int getDesktopScreenModeIndex() {
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		if(sms != null){
-			return sms.getCurrentScreenMode();
-		}
-		return -1;
-	}
-
-	/** 
-	 * Get list of available screen modes
-	 * null if not implemented for screen platform
-	 */
-	public ScreenMode[] getScreenModes(){
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		if(sms != null) {
-			return sms.getScreenModes();
-		}
-		return null;
-	}
-
-	public void setScreenMode(int modeIndex, short rate) {
-	}
-
-	public short getCurrentScreenRate() {
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		if(sms != null){
-			return sms.getCurrentScreenRate();
-		}
-		return -1;
-	}
-
-
-	public void setScreenRotation(int rot) {
-				
-	}
-	
-	public int getCurrentScreenRotation() {
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		if(sms != null) {
-			return sms.getCurrentScreenRotation();
-		}
-		return -1;
-	}
-
-	/** get the screens mode state handler
-	 * which contain the screen mode controller of each screen
-	 * @return the ScreensModeState static object
-	 */
-	protected ScreensModeState getScreensModeState() {
-		return screensModeState;
-	}
-
-	public String getScreenFQN() {
-		return screenFQN;
-	}
-
-	private void setScreenFQN(String screenFQN) {
-		this.screenFQN = screenFQN;
-	}
-
-	protected void setScreenSize(int w, int h) {
-		System.err.println("Detected screen size "+w+"x"+h);
-		width=w; height=h;
-	}
-
-	public final Display getDisplay() {
-		return display;
-	}
-
-	public final int getIndex() {
-		return idx;
-	}
-
-	public final AbstractGraphicsScreen getGraphicsScreen() {
-		return aScreen;
-	}
-
-	public final boolean isNativeValid() {
-		return null != aScreen;
-	}
-
-	public final int getWidth() {
-		return (usrWidth>0) ? usrWidth : (width>0) ? width : 480;
-	}
-
-	public final int getHeight() {
-		return (usrHeight>0) ? usrHeight : (height>0) ? height : 480;
-	}
-
-	public String toString() {
-		return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]";
-	}
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class ScreenImpl implements Screen, ScreenModeListener {
+    protected DisplayImpl display;
+    protected int screen_idx;
+    protected String fqname;
+    protected AbstractGraphicsScreen aScreen;
+    protected int refCount; // number of Screen references by Window
+    protected int width=-1, height=-1; // detected values: set using setScreenSize
+    protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight
+    private static AccessControlContext localACC = AccessController.getContext();
+    private List/*<ScreenModeListener>*/ referencedScreenModeListener = new ArrayList();
+    long t0; // creationTime
+
+    private static Class getScreenClass(String type) 
+    throws ClassNotFoundException 
+    {
+        Class screenClass = NewtFactory.getCustomClass(type, "Screen");
+        if(null==screenClass) {
+            if (NativeWindowFactory.TYPE_EGL.equals(type)) {
+                screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen");
+            } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) {
+                screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen");
+            } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) {
+                screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen");
+            } else if (NativeWindowFactory.TYPE_X11.equals(type)) {
+                screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen");
+            } else if (NativeWindowFactory.TYPE_AWT.equals(type)) {
+                screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen");
+            } else {
+                throw new RuntimeException("Unknown window type \"" + type + "\"");
+            }
+        }
+        return screenClass;
+    }
+
+    public static ScreenImpl create(String type, Display display, final int idx) {
+        try {
+            if(usrWidth<0 || usrHeight<0) {
+                usrWidth  = Debug.getIntProperty("newt.ws.swidth", true, localACC);
+                usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC);
+                if(usrWidth>0 || usrHeight>0) {
+                    System.err.println("User screen size "+usrWidth+"x"+usrHeight);
+                }
+            }
+            Class screenClass = getScreenClass(type);
+            ScreenImpl screen  = (ScreenImpl) screenClass.newInstance();
+            screen.display = (DisplayImpl) display;
+            screen.screen_idx = idx;
+            screen.fqname = display.getFQName()+idx;
+            return screen;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected  synchronized final void createNative() {
+        if(null == aScreen) {
+            if(DEBUG) {
+                System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")");
+            }
+            t0 = System.currentTimeMillis();
+            display.addReference();
+            createNativeImpl();
+            if(null == aScreen) {
+                throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen");
+            }
+            if(DEBUG) {
+                System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")");
+            }
+        }
+        initScreenModeStatus();
+    }
+
+    public synchronized final void destroy() {
+        releaseScreenModeStatus();
+
+        if ( null != aScreen ) {
+            closeNativeImpl();
+            aScreen = null;
+        }
+        refCount = 0;
+        display.removeReference();
+    }
+
+    public synchronized final int addReference() {
+        if(DEBUG) {
+            System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1));
+        }
+        if ( 0 == refCount ) {
+            createNative();
+        }
+        if(null == aScreen) {
+            throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen");
+        }
+        return ++refCount;
+    }
+
+    public synchronized final int removeReference() {
+        if(DEBUG) {
+            System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1));
+        }
+        refCount--; // could become < 0, in case of forced destruction without actual creation/addReference
+        if(0>=refCount && getDestroyWhenUnused()) {
+            destroy();
+        }
+        return refCount;
+    }
+
+    public synchronized final int getReferenceCount() {
+        return refCount;
+    }
+
+    public final boolean getDestroyWhenUnused() { 
+        return display.getDestroyWhenUnused(); 
+    }
+    public final void setDestroyWhenUnused(boolean v) { 
+        display.setDestroyWhenUnused(v); 
+    }
+
+    protected abstract void createNativeImpl();
+    protected abstract void closeNativeImpl();
+
+    public final String getFQName() {
+        return fqname;
+    }
+
+    protected void setScreenSize(int w, int h) {
+        System.err.println("Detected screen size "+w+"x"+h);
+        width=w; height=h;
+    }
+
+    public final Display getDisplay() {
+        return display;
+    }
+
+    public final int getIndex() {
+        return screen_idx;
+    }
+
+    public final AbstractGraphicsScreen getGraphicsScreen() {
+        return aScreen;
+    }
+
+    public final boolean isNativeValid() {
+        return null != aScreen;
+    }
+
+    public final int getWidth() {
+        return (usrWidth>0) ? usrWidth : (width>0) ? width : 480;
+    }
+
+    public final int getHeight() {
+        return (usrHeight>0) ? usrHeight : (height>0) ? height : 480;
+    }
+
+    public String toString() {
+        return "NEWT-Screen["+getFQName()+", idx "+screen_idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]";
+    }
+
+    public final List/*<ScreenMode>*/ getScreenModes() {
+        ArrayHashSet screenModes = getScreenModesOrig();
+        if(null != screenModes) {
+            return screenModes.toArrayList();
+        }
+        return null;
+    }
+
+    public ScreenMode getOriginalScreenMode() {
+        ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+        return ( null != sms ) ? sms.getOriginalScreenMode() : null ;
+    }
+
+    public ScreenMode getCurrentScreenMode() {
+        ScreenMode smU = null;
+        ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+        if(null != sms) {
+            ScreenMode sm0 = getCurrentScreenModeImpl();
+            if(null == sm0) {
+                return null;
+            }
+            sms.lock();
+            try {
+                smU = (ScreenMode) sms.getScreenModes().get(sm0); // unify via value hash
+                if(null == smU) {
+                    throw new RuntimeException(sm0+" could not be hashed from ScreenMode list");
+                }
+
+                // if mode has changed somehow, update it ..
+                if( sms.getCurrentScreenMode().hashCode() != smU.hashCode() ) {
+                    sms.fireScreenModeChanged(smU, true);
+                }
+            } finally {
+                sms.unlock();
+            }
+        }
+        return smU;
+    }
+
+    public boolean setCurrentScreenMode(ScreenMode screenMode) {
+        ScreenMode smU = (ScreenMode) getScreenModesOrig().get(screenMode); // unify via value hash
+        ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+        if(null!=sms) {
+            sms.lock();
+            try {
+                if(DEBUG) {
+                    System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.0 "+screenMode);
+                }
+
+                sms.fireScreenModeChangeNotify(smU);
+
+                if(DEBUG) {
+                    System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.1 "+screenMode);
+                }
+
+                boolean success = setCurrentScreenModeImpl(smU);
+                if(success) {
+                    setScreenSize(screenMode.getMonitorMode().getSurfaceSize().getResolution().getWidth(),
+                                  screenMode.getMonitorMode().getSurfaceSize().getResolution().getHeight());
+                }
+
+                if(DEBUG) {
+                    System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.0 "+screenMode+", success: "+success);
+                }
+
+                sms.fireScreenModeChanged(smU, success);
+
+                if(DEBUG) {
+                    System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.X "+screenMode+", success: "+success);
+                }
+
+                return success;
+            } finally {
+                sms.unlock();
+            }
+        }
+        return false;
+    }
+
+    public void screenModeChangeNotify(ScreenMode sm) {
+        for(int i=0; i<referencedScreenModeListener.size(); i++) {
+            ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChangeNotify(sm);
+        }
+    }
+
+    public void screenModeChanged(ScreenMode sm, boolean success) {
+        for(int i=0; i<referencedScreenModeListener.size(); i++) {
+            ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChanged(sm, success);
+        }
+    }
+
+    public synchronized final void addScreenModeListener(ScreenModeListener sml) {
+        referencedScreenModeListener.add(sml);
+    }
+
+    public synchronized final void removeScreenModeListener(ScreenModeListener sml) {
+        referencedScreenModeListener.remove(sml);
+    }
+
+    /** ScreenModeStatus bridge to native implementation */
+    protected final ArrayHashSet getScreenModesOrig() {
+        ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+        if(null!=sms) {
+            return sms.getScreenModes();
+        }
+        return null;
+    }
+
+    /** ScreenModeStatus bridge to native implementation */
+    protected final IntIntHashMap getScreenModesIdx2NativeIdx() {
+        ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+        if(null!=sms) {
+            return sms.getScreenModesIdx2NativeIdx();
+        }
+        return null;
+    }
+
+    /**
+     * To be implemented by the native specification.<br>
+     * Is called within a thread safe environment.<br>
+     * Is called only to collect the ScreenModes, usually at startup setting up modes.<br>
+     * <br>
+     * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES},
+     * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br>
+     * <br>
+     * <b>Note</b>: Additional 1st element is native mode id.
+     */
+    protected int[] getScreenModeFirstImpl() {
+        return null;
+    }
+
+    /**
+     * To be implemented by the native specification.<br>
+     * Is called within a thread safe environment.<br>
+     * Is called only to collect the ScreenModes, usually at startup setting up modes.<br>
+     * <br>
+     * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES},
+     * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br>
+     * <br>
+     * <b>Note</b>: Additional 1st element is native mode id.
+     */
+    protected int[] getScreenModeNextImpl() {
+        return null;
+    }
+
+    /**
+     * To be implemented by the native specification.<br>
+     * Is called within a thread safe environment.<br>
+     * Is called only to collect the ScreenModes, usually at startup setting up modes.<br>
+     */
+    protected ScreenMode getCurrentScreenModeImpl() {
+        return null;
+    }
+
+    /**
+     * To be implemented by the native specification.<br>
+     * Is called within a thread safe environment.<br>
+     */
+    protected boolean setCurrentScreenModeImpl(ScreenMode screenMode) {
+        return false;
+    }
+
+    private void initScreenModeStatus() {
+        ScreenModeStatus sms;
+        ScreenModeStatus.lockScreenModeStatus();
+        try {
+            sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+            if(null==sms) {                
+                IntIntHashMap screenModesIdx2NativeIdx = new IntIntHashMap();
+
+                ArrayHashSet screenModes = collectNativeScreenModes(screenModesIdx2NativeIdx);
+                sms = new ScreenModeStatus(screenModes, screenModesIdx2NativeIdx);
+                if(null!=screenModes && screenModes.size()>0) {
+                    ScreenMode originalScreenMode = getCurrentScreenModeImpl();
+                    if(null == originalScreenMode) {
+                        throw new RuntimeException("Couldn't fetch current ScreenMode (null), but ScreenMode list size is: "+screenModes.size());
+                    }
+                    sms.setOriginalScreenMode(originalScreenMode);
+                }
+                ScreenModeStatus.mapScreenModeStatus(this.getFQName(), sms);
+            }
+            sms.addListener(this);
+        } finally {
+            ScreenModeStatus.unlockScreenModeStatus();
+        }
+    }
+
+    private ArrayHashSet collectNativeScreenModes(IntIntHashMap screenModesIdx2NativeId) {
+        ArrayHashSet resolutionPool  = new ArrayHashSet();
+        ArrayHashSet surfaceSizePool = new ArrayHashSet();
+        ArrayHashSet screenSizeMMPool = new ArrayHashSet();
+        ArrayHashSet monitorModePool = new ArrayHashSet();
+        ArrayHashSet screenModePool = null;
+
+        screenModePool = new ArrayHashSet();
+
+        int[] smProps = null;
+        int num = 0;
+        do {
+            if(0 == num) {
+                smProps = getScreenModeFirstImpl();
+            } else {
+                smProps = getScreenModeNextImpl();
+            }
+            if(null != smProps) {
+                int nativeId = smProps[0];
+                int screenModeIdx = ScreenModeUtil.streamIn(resolutionPool, surfaceSizePool, screenSizeMMPool,
+                                                            monitorModePool, screenModePool, smProps, 1);
+                if(screenModeIdx >= 0) {
+                    screenModesIdx2NativeId.put(screenModeIdx, nativeId);
+                }
+            }
+            num++;
+        } while ( null != smProps );
+
+        ScreenModeUtil.validate(screenModePool, true);
+
+        if(DEBUG) {
+            System.err.println("ScreenImpl.collectNativeScreenModes: ScreenMode number  : "+screenModePool.size());
+            System.err.println("ScreenImpl.collectNativeScreenModes: MonitorMode number : "+monitorModePool.size());
+            System.err.println("ScreenImpl.collectNativeScreenModes: ScreenSizeMM number: "+screenSizeMMPool.size());
+            System.err.println("ScreenImpl.collectNativeScreenModes: SurfaceSize number : "+surfaceSizePool.size());
+            System.err.println("ScreenImpl.collectNativeScreenModes: Resolution number  : "+resolutionPool.size());
+        }
+
+        return screenModePool;
+    }
+
+    private void releaseScreenModeStatus() {
+        ScreenModeStatus sms;
+        ScreenModeStatus.lockScreenModeStatus();
+        try {
+            sms = ScreenModeStatus.getScreenModeStatus(this.getFQName());
+            if(null != sms) {
+                sms.lock();
+                try {
+                    if(0 == sms.removeListener(this)) {
+                        if(!sms.isOriginalMode()) {
+                            setCurrentScreenMode(sms.getOriginalScreenMode());
+                        }
+                        ScreenModeStatus.unmapScreenModeStatus(this.getFQName());
+                    }
+                } finally {
+                    sms.unlock();
+                }
+            }            
+        } finally {
+            ScreenModeStatus.unlockScreenModeStatus();
+        }
+    }
 }
 
diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java b/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java
index 94d3eb4e6..3ca9b638b 100644
--- a/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java
+++ b/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java
@@ -1,91 +1,207 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
 package com.jogamp.newt.impl;
 
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.common.util.IntIntHashMap;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.newt.Screen;
 import com.jogamp.newt.ScreenMode;
+import com.jogamp.newt.event.ScreenModeListener;
+import java.util.ArrayList;
+import java.util.HashMap;
 
 public class ScreenModeStatus {
-	private String screenFQN = null;
-	private ScreenMode[] screenModes = null;
-	
-	private int currentScreenMode = -1;
-	private short currentScreenRate = -1;
-	private int currentScreenRotation = -1;
-	
-	private int originalScreenMode = -1;
-	private short originalScreenRate = -1;
-	private int originalScreenRotation = -1;
-	
-	public ScreenModeStatus(String screenFQN, int originalScreenMode,
-			short originalScreenRate, int originalScreenRotation) {
-		this.screenFQN = screenFQN;
-		this.originalScreenMode = originalScreenMode;
-		this.originalScreenRate = originalScreenRate;
-		this.originalScreenRotation = originalScreenRotation;
-		
-		this.currentScreenMode = originalScreenMode;
-		this.currentScreenRate = originalScreenRate;
-		this.currentScreenRotation = originalScreenRotation;
-	}
-
-	public void setCurrentScreenRotation(int currentScreenRotation) {
-		this.currentScreenRotation = currentScreenRotation;
-	}
-
-	public int getCurrentScreenRotation() {
-		return currentScreenRotation;
-	}
-
-	public int getOriginalScreenRotation() {
-		return originalScreenRotation;
-	}
-
-	public int getCurrentScreenMode() {
-		return currentScreenMode;
-	}
-
-	public void setCurrentScreenMode(int currentScreenMode) {
-		this.currentScreenMode = currentScreenMode;
-	}
-
-	public short getCurrentScreenRate() {
-		return currentScreenRate;
-	}
-
-	public void setCurrentScreenRate(short currentRate) {
-		this.currentScreenRate = currentRate;
-	}
-
-	public String getScreenFQN() {
-		return screenFQN;
-	}
-
-	public void setScreenFQN(String screenFQN) {
-		this.screenFQN = screenFQN;
-	}
-
-	public ScreenMode[] getScreenModes() {
-		return screenModes;
-	}
-
-	public void setScreenModes(ScreenMode[] screenModes) {
-		this.screenModes = screenModes;
-	}
-	public boolean isOriginalMode(){
-		if(currentScreenMode == originalScreenMode
-				&& currentScreenRate == originalScreenRate)
-			return true;
-		return false;
-	}
-	public boolean isOriginalRotation(){
-		if(currentScreenRotation == originalScreenRotation)
-			return true;
-		return false;
-	}
-	
-	public int getOriginalScreenMode() {
-		return originalScreenMode;
-	}
-
-	public short getOriginalScreenRate() {
-		return originalScreenRate;
-	}
+    private static boolean DEBUG = Screen.DEBUG;
+
+    private RecursiveLock lock = new RecursiveLock();
+    private ArrayHashSet/*<ScreenMode>*/ screenModes;
+    private IntIntHashMap screenModesIdx2NativeIdx;
+    private ScreenMode currentScreenMode;
+    private ScreenMode originalScreenMode;
+    private ArrayList/*<ScreenModeChangeListener>*/ listener = new ArrayList();
+
+    private static HashMap screenFQN2ScreenModeStatus = new HashMap();
+    private static RecursiveLock screen2ScreenModeStatusLock = new RecursiveLock();
+
+    protected static void mapScreenModeStatus(String screenFQN, ScreenModeStatus sms) {
+        screen2ScreenModeStatusLock.lock();
+        try {
+            ScreenModeStatus _sms = (ScreenModeStatus) screenFQN2ScreenModeStatus.get(screenFQN);
+            if( null != _sms ) {
+                throw new RuntimeException("ScreenModeStatus "+_sms+" already mapped to "+screenFQN);
+            }
+            screenFQN2ScreenModeStatus.put(screenFQN, sms);
+            if(DEBUG) {
+                System.err.println("ScreenModeStatus.map "+screenFQN+" -> "+sms);
+            }
+        } finally {
+            screen2ScreenModeStatusLock.unlock();
+        }
+    }
+
+    /**
+     * @param screen the prev user
+     * @return true if mapping is empty, ie no more usage of the mapped ScreenModeStatus
+     */
+    protected static void unmapScreenModeStatus(String screenFQN) {
+        screen2ScreenModeStatusLock.lock();
+        try {
+            ScreenModeStatus sms = (ScreenModeStatus) screenFQN2ScreenModeStatus.remove(screenFQN);
+            if(DEBUG) {
+                System.err.println("ScreenModeStatus.unmap "+screenFQN+" -> "+sms);
+            }
+        } finally {
+            screen2ScreenModeStatusLock.unlock();
+        }
+    }
+
+    protected static ScreenModeStatus getScreenModeStatus(String screenFQN) {
+        screen2ScreenModeStatusLock.lock();
+        try {
+            return (ScreenModeStatus) screenFQN2ScreenModeStatus.get(screenFQN);
+        } finally {
+            screen2ScreenModeStatusLock.unlock();
+        }
+    }
+
+    protected static void lockScreenModeStatus() {
+        screen2ScreenModeStatusLock.lock();
+    }
+
+    protected static void unlockScreenModeStatus() {
+        screen2ScreenModeStatusLock.unlock();
+    }
+    
+    public ScreenModeStatus(ArrayHashSet/*<ScreenMode>*/ screenModes,
+                            IntIntHashMap screenModesIdx2NativeIdx) {
+        this.screenModes = screenModes;
+        this.screenModesIdx2NativeIdx = screenModesIdx2NativeIdx;
+    }
+
+    protected final void setOriginalScreenMode(ScreenMode originalScreenMode) {
+        this.originalScreenMode = originalScreenMode;
+        this.currentScreenMode = originalScreenMode;
+    }
+
+    public final ScreenMode getOriginalScreenMode() {
+        return originalScreenMode;
+    }
+
+    public final ScreenMode getCurrentScreenMode() {
+        lock();
+        try {
+            return currentScreenMode;
+        } finally {
+            unlock();
+        }
+    }
+
+    public final boolean isOriginalMode() {
+        lock();
+        try {
+            if(null != currentScreenMode && null != originalScreenMode) {
+                return currentScreenMode.hashCode() == originalScreenMode.hashCode();
+            }
+            return true;
+        } finally {
+            unlock();
+        }
+    }
+
+    protected final ArrayHashSet/*<ScreenMode>*/ getScreenModes() {
+        return screenModes;
+    }
+
+    protected final IntIntHashMap getScreenModesIdx2NativeIdx() {
+        return screenModesIdx2NativeIdx;
+    }
+
+    protected final int addListener(ScreenModeListener l) {
+        lock();
+        try {
+            listener.add(l);
+            if(DEBUG) {
+                System.err.println("ScreenModeStatus.addListener (size: "+listener.size()+"): "+l);
+            }
+            return listener.size();
+        } finally {
+            unlock();
+        }
+    }
+
+    protected final int removeListener(ScreenModeListener l) {
+        lock();
+        try {
+            if(!listener.remove(l)) {
+                throw new RuntimeException("ScreenModeListener "+l+" not contained");
+            }
+            if(DEBUG) {
+                System.err.println("ScreenModeStatus.removeListener (size: "+listener.size()+"): "+l);
+            }
+            return listener.size();
+        } finally {
+            unlock();
+        }
+    }
+
+    protected final void fireScreenModeChangeNotify(ScreenMode desiredScreenMode) {
+        lock();
+        try {
+            for(int i=0; i<listener.size(); i++) {
+                ((ScreenModeListener)listener.get(i)).screenModeChangeNotify(desiredScreenMode);
+            }
+        } finally {
+            unlock();
+        }
+    }
+
+    protected void fireScreenModeChanged(ScreenMode currentScreenMode, boolean success) {
+        lock();
+        try {
+            if(success) {
+                this.currentScreenMode = currentScreenMode;
+            }
+            for(int i=0; i<listener.size(); i++) {
+                ((ScreenModeListener)listener.get(i)).screenModeChanged(currentScreenMode, success);
+            }
+        } finally {
+            unlock();
+        }
+    }
+
+    protected final void lock() throws RuntimeException {
+        lock.lock();
+    }
+
+    protected final void unlock() throws RuntimeException {
+        lock.unlock();
+    }
+
 }
diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java b/src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java
deleted file mode 100644
index e4291496d..000000000
--- a/src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.jogamp.newt.impl;
-
-import java.util.HashMap;
-
-public class ScreensModeState {
-	private static HashMap screenModes = new HashMap();
-	private static Object lock = new Object();
-	
-	public ScreensModeState(){
-		
-	}
-	public synchronized void setScreenModeController(ScreenModeStatus screenModeStatus){
-		synchronized (lock) {
-			screenModes.put(screenModeStatus.getScreenFQN(), screenModeStatus);	
-		}
-	}
-	
-	public synchronized ScreenModeStatus getScreenModeController(String screenFQN){
-		return (ScreenModeStatus) screenModes.get(screenFQN);
-	}
-}
diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
index 631c1b1c0..f9383ea38 100644
--- a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
+++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java
@@ -43,14 +43,16 @@ import com.jogamp.newt.event.*;
 import com.jogamp.common.util.*;
 import javax.media.nativewindow.*;
 import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.newt.ScreenMode;
 
 import java.util.ArrayList;
 import java.lang.reflect.Method;
+import javax.media.nativewindow.util.DimensionReadOnly;
 import javax.media.nativewindow.util.Insets;
 import javax.media.nativewindow.util.Point;
 import javax.media.nativewindow.util.Rectangle;
 
-public abstract class WindowImpl implements Window, NEWTEventConsumer
+public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenModeListener
 {
     public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true);
     
@@ -178,9 +180,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
     private boolean handleDestroyNotify = true;
 
     private final void destroyScreen() {
-        screenReferenced = false;
         if(null!=screen) {
-            screen.removeReference();
+            if(screenReferenced) {
+                screen.removeReference();
+                screenReferenced = false;
+            }
             screen = null;
         }
     }
@@ -208,6 +212,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                 }
                 createNativeImpl();
                 setVisibleImpl(true, x, y, width, height);
+                screen.addScreenModeListener(this);
             }
         } finally {
             if(null!=parentWindow) {
@@ -461,11 +466,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
 
     class VisibleAction implements Runnable {
         boolean visible;
+        long timeOut;
         boolean nativeWindowCreated;
         boolean madeVisible;
 
-        public VisibleAction (boolean visible) {
+        public VisibleAction (boolean visible, long timeOut) {
             this.visible = visible;
+            this.timeOut = timeOut;
             this.nativeWindowCreated = false;
             this.madeVisible = false;
         }
@@ -494,13 +501,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                 if(0==windowHandle && visible) {
                     if( 0<width*height ) {
                         nativeWindowCreated = createNative();
-                        WindowImpl.this.waitForVisible(visible, true);
+                        WindowImpl.this.waitForVisible(visible, true, timeOut);
                         madeVisible = visible;
                     }
                 } else if(WindowImpl.this.visible != visible) {
                     if(0 != windowHandle) {
                         setVisibleImpl(visible, x, y, width, height);
-                        WindowImpl.this.waitForVisible(visible, true);
+                        WindowImpl.this.waitForVisible(visible, true, timeOut);
                         madeVisible = visible;
                     }
                 }
@@ -529,12 +536,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
     }
 
     public void setVisible(boolean visible) {
+        setVisible(visible, TIMEOUT_NATIVEWINDOW);
+
+    }
+
+    protected final void setVisible(boolean visible, long timeOut) {
         if(isValid()) {
             if( 0==windowHandle && visible && 0>=width*height ) {
                 // fast-path: not realized yet, make visible, but zero size
                 return;
             }
-            VisibleAction visibleAction = new VisibleAction(visible);
+            VisibleAction visibleAction = new VisibleAction(visible, timeOut);
             runOnEDTIfAvail(true, visibleAction);
             if( visibleAction.getChanged() ) {
                 sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
@@ -647,6 +659,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                     keyListeners = new ArrayList();
                 }
                 if( null != screen && 0 != windowHandle ) {
+                    screen.removeScreenModeListener(WindowImpl.this);
                     closeNativeImpl();
                 }
                 invalidate(unrecoverable);
@@ -666,7 +679,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                 System.err.println(msg);
                 //Exception ee = new Exception(msg);
                 //ee.printStackTrace();
-            }
+            }            
             DestroyAction destroyAction = new DestroyAction(unrecoverable);
             runOnEDTIfAvail(true, destroyAction);
         }
@@ -932,11 +945,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                             setVisibleImpl(true, x, y, width, height);
                             ok = WindowImpl.this.waitForVisible(true, false);
                             display.dispatchMessagesNative(); // status up2date
-                            if( WindowImpl.this.x != x ||
-                                WindowImpl.this.y != y ||
-                                WindowImpl.this.width != width ||
-                                WindowImpl.this.height != height ) 
+                            if( ok &&
+                                ( WindowImpl.this.x != x ||
+                                  WindowImpl.this.y != y ||
+                                  WindowImpl.this.width != width ||
+                                  WindowImpl.this.height != height ) )
                             {
+                                if(DEBUG_IMPLEMENTATION) {
+                                    System.err.println("Window.reparent (reconfig)");
+                                }
                                 // reset pos/size .. due to some native impl flakyness
                                 reconfigureWindowImpl(x, y, width, height, false, 0, 0);
                                 display.dispatchMessagesNative(); // status up2date
@@ -1343,23 +1360,46 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                         h = nfs_height;
                     }
                     if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
-                        System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen);
+                        System.err.println("Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen);
                     }
 
                     DisplayImpl display = (DisplayImpl) screen.getDisplay();
                     display.dispatchMessagesNative(); // status up2date
                     boolean wasVisible = isVisible();
                     setVisibleImpl(false, x, y, width, height);
-                    WindowImpl.this.waitForVisible(false, true);
+                    WindowImpl.this.waitForVisible(false, true, Screen.SCREEN_MODE_CHANGE_TIMEOUT);
                     display.dispatchMessagesNative(); // status up2date
+
+                    // write back mirrored values, to be able to detect satisfaction
+                    WindowImpl.this.x = x;
+                    WindowImpl.this.y = y;
+                    WindowImpl.this.width = w;
+                    WindowImpl.this.height = h;
                     reconfigureWindowImpl(x, y, w, h, getParentWindowHandle()!=0, fullscreen?1:-1, isUndecorated()?-1:1);
                     display.dispatchMessagesNative(); // status up2date
+
                     if(wasVisible) {
                         setVisibleImpl(true, x, y, width, height);
-                        WindowImpl.this.waitForVisible(true, true);
+                        boolean ok = WindowImpl.this.waitForVisible(true, true, Screen.SCREEN_MODE_CHANGE_TIMEOUT);
                         display.dispatchMessagesNative(); // status up2date
+                        if( ok &&
+                            ( WindowImpl.this.x != x ||
+                              WindowImpl.this.y != y ||
+                              WindowImpl.this.width != w ||
+                              WindowImpl.this.height != h ) )
+                        {
+                            if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+                                System.err.println("Window fs (reconfig): "+x+"/"+y+" "+w+"x"+h+", "+screen);
+                            }
+                            // reset pos/size .. due to some native impl flakyness
+                            reconfigureWindowImpl(x, y, width, height, false, 0, 0);
+                            display.dispatchMessagesNative(); // status up2date
+                        }
                         requestFocusImpl(true);
                         display.dispatchMessagesNative(); // status up2date
+                        if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+                            System.err.println("Window fs done");
+                        }
                     }
                 }
             } finally {
@@ -1377,6 +1417,45 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         return this.fullscreen;
     }
 
+    boolean screenModeChangeVisible;
+    boolean screenModeChangeFullscreen;
+
+    public void screenModeChangeNotify(ScreenMode sm) {
+        if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+            System.err.println("Window.screenModeChangeNotify: "+sm);
+        }
+        screenModeChangeFullscreen = isFullscreen();
+        if(screenModeChangeFullscreen) {
+            setFullscreen(false);
+        }
+        screenModeChangeVisible = isVisible();
+        if(screenModeChangeVisible) {
+            setVisible(false);
+        }
+        windowLock.lock();
+    }
+
+    public void screenModeChanged(ScreenMode sm, boolean success) {
+        if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) {
+            System.err.println("Window.screenModeChanged: "+sm+", success: "+success);
+        }
+        windowLock.unlock();
+
+        if(success) {
+            DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution();
+            if ( getHeight() > screenSize.getHeight()  ||
+                 getWidth() > screenSize.getWidth() ) {
+                setSize(screenSize.getWidth(), screenSize.getHeight());
+            }
+        }
+        if(screenModeChangeFullscreen) {
+            setFullscreen(true);
+        }
+        if(screenModeChangeVisible) {
+            setVisible(true, Screen.SCREEN_MODE_CHANGE_TIMEOUT);
+        }
+    }
+
     //----------------------------------------------------------------------
     // Child Window Management
     // 
@@ -1866,8 +1945,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
     }
 
     private boolean waitForVisible(boolean visible, boolean failFast) {
+        return waitForVisible(visible, failFast, TIMEOUT_NATIVEWINDOW);
+    }
+
+    private boolean waitForVisible(boolean visible, boolean failFast, long timeOut) {
         DisplayImpl display = (DisplayImpl) screen.getDisplay();
-        for(long sleep = TIMEOUT_NATIVEWINDOW; 0<sleep && this.visible != visible; sleep-=10 ) {
+        for(long sleep = timeOut; 0<sleep && this.visible != visible; sleep-=10 ) {
             display.dispatchMessagesNative(); // status up2date
             try {
                 Thread.sleep(10);
@@ -1876,9 +1959,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         }
         if(this.visible != visible) {
             if(failFast) {
-                throw new NativeWindowException("Visibility not reached as requested within "+TIMEOUT_NATIVEWINDOW+"ms : requested "+visible+", is "+this.visible);
+                throw new NativeWindowException("Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible);
             } else if (DEBUG_IMPLEMENTATION) {
-                System.err.println("******* Visibility not reached as requested within "+TIMEOUT_NATIVEWINDOW+"ms : requested "+visible+", is "+this.visible);
+                System.err.println("******* Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible);
             }
         }
         return this.visible == visible;
@@ -1937,16 +2020,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
             // Exception ee = new Exception("Window.windowRepaint: "+" - "+x+"/"+y+" "+width+"x"+height);
             // ee.printStackTrace();
         }
-        if(0>width) {
-            width=this.width;
-        }
-        if(0>height) {
-            height=this.height;
-        }
 
-        NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), 
-                                            new Rectangle(x, y, width, height));
         if(isNativeValid()) {
+            if(0>width) {
+                width=this.width;
+            }
+            if(0>height) {
+                height=this.height;
+            }
+
+            NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(),
+                                                new Rectangle(x, y, width, height));
             doEvent(false, false, e);
         }
     }
diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java
index eaf758b2d..5e097fdc3 100644
--- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java
@@ -62,5 +62,4 @@ public class AWTScreen extends ScreenImpl {
     }
 
     protected void closeNativeImpl() { }
-
 }
diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java
index c5253e142..4abee350f 100644
--- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java
@@ -47,8 +47,8 @@ public class Screen extends com.jogamp.newt.impl.ScreenImpl {
 
     protected void createNativeImpl() {
         AbstractGraphicsDevice adevice = getDisplay().getGraphicsDevice();
-        GetScreenInfo(adevice.getHandle(), idx);
-        aScreen = new DefaultGraphicsScreen(adevice, idx);
+        GetScreenInfo(adevice.getHandle(), screen_idx);
+        aScreen = new DefaultGraphicsScreen(adevice, screen_idx);
     }
 
     protected void closeNativeImpl() { }
diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java
index 21018b2be..f0c388366 100644
--- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java
@@ -46,8 +46,8 @@ public class MacScreen extends ScreenImpl {
     }
 
     protected void createNativeImpl() {
-        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx);
-        setScreenSize(getWidthImpl0(idx), getHeightImpl0(idx));
+        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
+        setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx));
     }
 
     protected void closeNativeImpl() { }
diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java
index 50fdf92e5..144fe5e83 100644
--- a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java
@@ -46,7 +46,7 @@ public class Screen extends com.jogamp.newt.impl.ScreenImpl {
     }
 
     protected void createNativeImpl() {
-        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx);
+        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
         setScreenSize(fixedWidth, fixedHeight);
     }
 
diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java
index a814f15b5..1a73d0e5d 100644
--- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java
@@ -46,7 +46,7 @@ public class KDScreen extends ScreenImpl {
     }
 
     protected void createNativeImpl() {
-        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx);
+        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
     }
 
     protected void closeNativeImpl() { }
diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java
index 04ffbe11d..d35021605 100644
--- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java
@@ -30,182 +30,80 @@
  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  * 
  */
-
 package com.jogamp.newt.impl.windows;
 
+import com.jogamp.common.util.ArrayHashSet;
 import java.util.ArrayList;
 
 import com.jogamp.newt.*;
 import com.jogamp.newt.impl.ScreenImpl;
 import com.jogamp.newt.ScreenMode;
 import com.jogamp.newt.impl.ScreenModeStatus;
+import com.jogamp.newt.util.ScreenModeUtil;
 
 import javax.media.nativewindow.*;
 
 public class WindowsScreen extends ScreenImpl {
+
     static {
         WindowsDisplay.initSingleton();
     }
 
-
     public WindowsScreen() {
     }
 
     protected void createNativeImpl() {
-        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx);
-        setScreenSize(getWidthImpl0(idx), getHeightImpl0(idx));
+        aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx);
+        setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx));
     }
 
-    protected void closeNativeImpl() { }
-    
-    public int getDesktopScreenModeIndex() {
-    	int index = super.getDesktopScreenModeIndex();
-    	if(index == -1) {
-        	/** Set the current screen mode to refering to index zero
-        	 *  dependent on the impl of getScreenModes which saves the 
-        	 *  current screen mode at index 0 which is the original screen mode
-        	 */
-	    	ScreenMode[] screenModes = getScreenModes();
-	    	if(screenModes != null) {
-	    		if(screenModes[0] != null) {
-	    			index = screenModes[0].getIndex();
-	    		}
-	    	}
-    	}
-    	return index;
+    protected void closeNativeImpl() {
     }
-    
-    public void setScreenMode(int modeIndex, short rate) {
-    	ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-    	ScreenMode[] screenModes = sms.getScreenModes();
-    	
-    	short selectedRate = rate;
-    	int selectedMode = modeIndex;
-    	
-    	if(modeIndex < 0 || (modeIndex > screenModes.length)){
-    		selectedMode = sms.getOriginalScreenMode();
-    	}
-    	ScreenMode sm = screenModes[selectedMode];
-    	
-    	if(selectedRate == -1){
-    		selectedRate = sms.getOriginalScreenRate();
-    	}
-    	
-    	boolean rateAvailable = false;
-    	short[] rates = sm.getRates();
-    	for(int i=0;i<rates.length;i++){
-    		if(rates[i] == selectedRate){
-    			rateAvailable = true;
-    			break;
-    		}
-    	}
-    	if(!rateAvailable){
-    		selectedRate = rates[0];
-    	}
-
-    	if(0 == setScreenMode0(idx, sm.getWidth(), sm.getHeight(), sm.getBitsPerPixel(), selectedRate)){	
-    		sms.setCurrentScreenMode(selectedMode);
-    		sms.setCurrentScreenRate(selectedRate);
-    	}
+
+    private int[] getScreenModeIdx(int idx) {
+        int[] modeProps = getScreenMode0(screen_idx, idx);
+        if (null == modeProps) {
+            return null;
+        }
+        if(modeProps.length != ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL + 1) {
+            throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length);
+        }
+        return modeProps;
     }
-    
-    public short getCurrentScreenRate() {
-    	short rate = super.getCurrentScreenRate();
-    	if(rate == -1){
-    		rate = (short)getCurrentScreenRate0(idx);
-    	}
-    	return rate;
-	}
-    
-    public ScreenMode[] getScreenModes() {
-    	ScreenMode[] screenModes = super.getScreenModes();
-    	if(screenModes == null) {
-    		ArrayList smTemp = new ArrayList();
-
-    		int modeID = -1;
-    		ScreenMode mySM = getScreenMode(modeID++);
-    		int currentBitsPerPixel = mySM.getBitsPerPixel();
-    		while(mySM != null){
-    			//filter out modes with diff bits per pixel
-    			if(mySM.getBitsPerPixel() == currentBitsPerPixel) {
-    				smTemp.add(mySM);
-    			}
-    			mySM = getScreenMode(modeID++);
-    		}
-    		int numModes = smTemp.size();
-    		if(numModes > 0) {
-    			screenModes = new ScreenMode[numModes];
-    			for(int i=0;i<numModes;i++) {
-    				ScreenMode sm = (ScreenMode)smTemp.get(i);
-    				sm.setIndex(i);
-    				screenModes[i] = sm;
-        		}
-    		}
-    	}
-    	return screenModes;
+
+    private int nativeModeIdx;
+
+    protected int[] getScreenModeFirstImpl() {
+        nativeModeIdx = 0;
+        return getScreenModeNextImpl();
     }
-    private ScreenMode getScreenMode(int modeIndex) {
-    	int[] modeProp = getScreenMode0(idx, modeIndex); 
-    	if(modeProp == null){
-    		return null;
-    	}
-    	int propIndex = 0;
-    	int width = modeProp[propIndex++];
-    	int height = modeProp[propIndex++];
-    	int bits = modeProp[propIndex++];
-    	short rate = (short)modeProp[propIndex++];
-    	
-    	ScreenMode screenMode = new ScreenMode(modeIndex+1, width, height);
-    	screenMode.setRates(new short[]{rate});
-    	screenMode.setBitsPerPixel(bits);
-    	return screenMode;
+
+    protected int[] getScreenModeNextImpl() {
+        int[] modeProps = getScreenModeIdx(nativeModeIdx);
+        if (null != modeProps) {
+            nativeModeIdx++;
+        }
+        return modeProps;
     }
-    
-    public void setScreenRotation(int rot) {
-    	if(!isRotationValid(rot)){
-			return;
-		}
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		if(0 == setScreenRotation0(idx, rot)) {
-			sms.setCurrentScreenRotation(rot);
-		}
-	}
-    
-    /** Check if this rotation is valid for platform
-	 * @param rot user requested rotation angle
-	 * @return true if is valid
-	 */
-	private boolean isRotationValid(int rot){
-		if((rot == ScreenMode.ROTATE_0) || (rot == ScreenMode.ROTATE_90) || 
-				(rot == ScreenMode.ROTATE_180) || (rot == ScreenMode.ROTATE_270)) {
-			return true;
-		}
-		return false;
-	}
-	
-	public int getCurrentScreenRotation() {
-		int rot = super.getCurrentScreenRotation();
-    	if(rot == -1){
-    		return getCurrentScreenRotation0(idx);		
-    	}
-    	return rot;
-	}
-    
-    // Native calls
 
+    protected ScreenMode getCurrentScreenModeImpl() {
+        return ScreenModeUtil.streamIn(getScreenModeIdx(-1), 0);
+    }
+
+    protected boolean setCurrentScreenModeImpl(ScreenMode sm) {
+        return setScreenMode0(screen_idx, 
+                              sm.getMonitorMode().getSurfaceSize().getResolution().getWidth(),
+                              sm.getMonitorMode().getSurfaceSize().getResolution().getHeight(),
+                              sm.getMonitorMode().getSurfaceSize().getBitsPerPixel(),
+                              sm.getMonitorMode().getRefreshRate(),
+                              sm.getRotation());
+    }
+
+    // Native calls
     private native int getWidthImpl0(int scrn_idx);
+
     private native int getHeightImpl0(int scrn_idx);
-    
-    private native int getCurrentScreenRate0(int scrn_idx);
+
     private native int[] getScreenMode0(int screen_index, int mode_index);
-    
-    /** Change screen mode and return zero if successful
-     */
-    private native int setScreenMode0(int screen_index, int width, int height, int bits, short freq);
-    
-    private native int getCurrentScreenRotation0(int screen_index);
-    
-    /** Change screen mode and return zero if successful
-     */
-    private native int setScreenRotation0(int screen_index, int rot);
+    private native boolean setScreenMode0(int screen_index, int width, int height, int bits, int freq, int rot);
 }
diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java
index 52c80bbe9..a04ce4242 100644
--- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java
+++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java
@@ -30,12 +30,13 @@
  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  * 
  */
-
 package com.jogamp.newt.impl.x11;
 
+import com.jogamp.nativewindow.impl.x11.X11Util;
 import com.jogamp.newt.impl.ScreenImpl;
 import com.jogamp.newt.ScreenMode;
-import com.jogamp.newt.impl.ScreenModeStatus;
+import com.jogamp.newt.util.ScreenModeUtil;
+import java.util.List;
 
 import javax.media.nativewindow.x11.*;
 
@@ -45,153 +46,221 @@ public class X11Screen extends ScreenImpl {
         X11Display.initSingleton();
     }
 
-
     public X11Screen() {
     }
 
     protected void createNativeImpl() {
-        long handle = GetScreen0(display.getHandle(), idx);
-        if (handle == 0 ) {
-            throw new RuntimeException("Error creating screen: "+idx);
+        long handle = GetScreen0(display.getHandle(), screen_idx);
+        if (handle == 0) {
+            throw new RuntimeException("Error creating screen: " + screen_idx);
+        }
+        aScreen = new X11GraphicsScreen((X11GraphicsDevice) getDisplay().getGraphicsDevice(), screen_idx);
+        setScreenSize(getWidth0(display.getHandle(), screen_idx),
+                getHeight0(display.getHandle(), screen_idx));
+    }
+
+    protected void closeNativeImpl() {
+    }
+
+    private int[] nrotations;
+    private int nrotation_index;
+    private int nres_number;
+    private int nres_index;
+    private int[] nrates;
+    private int nrate_index;
+    private int nmode_number;
+
+    protected int[] getScreenModeFirstImpl() {
+        // initialize iterators and static data
+        nrotations = getAvailableScreenModeRotations0(display.getHandle(), screen_idx);
+        if(null==nrotations) {
+            nrotations = new int[1];
+            nrotations[0]=0;
         }
-        aScreen = new X11GraphicsScreen((X11GraphicsDevice)getDisplay().getGraphicsDevice(), idx);
-        setScreenSize(getWidth0(display.getHandle(), idx),
-                      getHeight0(display.getHandle(), idx));
+        nrotation_index = 0;
+
+        nres_number = getNumScreenModeResolutions0(display.getHandle(), screen_idx);
+        nres_index = 0;
+
+        nrates = getScreenModeRates0(display.getHandle(), screen_idx, nres_index);
+        nrate_index = 0;
+
+        nmode_number = 0;
+
+        return getScreenModeNextImpl();
     }
 
-    protected void closeNativeImpl() { }
-    
-    public int getDesktopScreenModeIndex() {
-    	int index = super.getDesktopScreenModeIndex();
-    	if(index == -1){
-    		return getDesktopScreenModeIndex0(display.getHandle(), idx);
-    	}
-    	return index;
+    protected int[] getScreenModeNextImpl() {
+        // assemble: w x h x bpp x f x r        
+
+        /**
+        System.err.println("******** mode: "+nmode_number);
+        System.err.println("rot  "+nrotation_index);
+        System.err.println("rate "+nrate_index);
+        System.err.println("res  "+nres_index); */
+
+        int[] res = getScreenModeResolution0(display.getHandle(), screen_idx, nres_index);
+        if(null == res) {
+            throw new InternalError("null resolution received for res idx "+nres_index+"/"+nres_number);
+        }
+        if(0>=res[0] || 0>=res[1]) {
+            throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_index+"/"+nres_number);
+        }
+        int bpp = 32; // FIXME
+        int rate = nrates[nrate_index];
+        if(0>=rate) {
+            throw new InternalError("invalid rate: "+rate+" at index "+nrate_index+"/"+nrates.length);
+        }
+        int rotation = nrotations[nrotation_index];
+
+        int[] props = new int[ 1 + ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL ];
+        int i = 0;
+        props[i++] = nres_index; // use resolution index, not unique for native -> ScreenMode
+        props[i++] = 0; // set later for verification of iterator
+        props[i++] = res[0]; // width
+        props[i++] = res[1]; // height
+        props[i++] = bpp;    // bpp
+        props[i++] = res[2]; // widthmm
+        props[i++] = res[3]; // heightmm
+        props[i++] = rate;   // rate
+        props[i++] = rotation;
+        props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i - 1; // count without extra element
+
+        nmode_number++;
+
+        // iteration: r -> f -> bpp -> [w x h]
+        nrotation_index++;
+        if(nrotation_index == nrotations.length) {
+            nrotation_index=0;
+            nrate_index++;
+            if(null == nrates || nrate_index == nrates.length){
+                nres_index++;
+                if(nres_index == nres_number) {
+                    // done
+                    nrates=null;
+                    nrotations=null;
+                    return null;
+                }
+
+                nrates = getScreenModeRates0(display.getHandle(), screen_idx, nres_index);
+                nrate_index = 0;
+            }
+        }
+
+        return props;
     }
-    
-    public void setScreenMode(int modeIndex, short rate) {
-    	ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-    	ScreenMode[] screenModes = sms.getScreenModes();
-    	
-    	short selectedRate = rate;
-    	int selectedMode = modeIndex;
-    	
-    	if(modeIndex < 0 || (modeIndex > screenModes.length)){
-    		selectedMode = sms.getOriginalScreenMode();
-    	}
-    	ScreenMode screenMode = screenModes[selectedMode];
-    	
-    	if(selectedRate == -1){
-    		selectedRate = sms.getOriginalScreenRate();
-    	}
-    	
-    	boolean rateAvailable = false;
-    	short[] rates = screenMode.getRates();
-    	for(int i=0;i<rates.length;i++){
-    		if(rates[i] == selectedRate){
-    			rateAvailable = true;
-    			break;
-    		}
-    	}
-    	if(!rateAvailable){
-    		selectedRate = rates[0];
-    	}
-
-    	
-    	setScreenMode0(display.getHandle(), idx, selectedMode, selectedRate, getCurrentScreenRotation());	
-		sms.setCurrentScreenMode(selectedMode);
-    	sms.setCurrentScreenRate(selectedRate);
+
+    protected ScreenMode getCurrentScreenModeImpl() {
+        int resNumber = getNumScreenModeResolutions0(display.getHandle(), screen_idx);
+        int resIdx = getCurrentScreenResolutionIndex0(display.getHandle(), screen_idx);
+        if(0>resIdx || resIdx>=resNumber) {
+            throw new RuntimeException("Invalid resolution index: ! 0 < "+resIdx+" < "+resNumber);
+        }
+        int[] res = getScreenModeResolution0(display.getHandle(), screen_idx, resIdx);
+        if(null == res) {
+            throw new InternalError("null resolution received for res idx "+resIdx+"/"+resNumber);
+        }
+        if(0>=res[0] || 0>=res[1]) {
+            throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+resIdx+"/"+resNumber);
+        }
+        int rate = getCurrentScreenRate0(display.getHandle(), screen_idx);
+        int rot = getCurrentScreenRotation0(display.getHandle(), screen_idx);
+
+        int[] props = new int[ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL];
+        int i = 0;
+        props[i++] = 0; // set later for verification of iterator
+        props[i++] = res[0]; // width
+        props[i++] = res[1]; // height
+        props[i++] = 32;     // FIXME: bpp
+        props[i++] = res[2]; // widthmm
+        props[i++] = res[3]; // heightmm
+        props[i++] = rate;   // rate
+        props[i++] = rot;
+        props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i; // count
+        return ScreenModeUtil.streamIn(props, 0);
     }
-    
-    public short getCurrentScreenRate() {
-    	short rate = super.getCurrentScreenRate();
-    	if(rate == -1){
-    		return getCurrentScreenRate0(display.getHandle(), idx);		
-    	}
-    	return rate;
-	}
-    
-    public ScreenMode[] getScreenModes() {
-    	ScreenMode[] screenModes = super.getScreenModes();
-    	if(screenModes == null){
-    		int numModes = getNumScreenModes0(display.getHandle(), idx);
-    		screenModes = new ScreenMode[numModes];
-	    	for(int i=0; i< numModes; i++){
-	    		screenModes[i] = getScreenMode(i);
-	    	}
-    	}
-    	return screenModes;
+
+    protected boolean setCurrentScreenModeImpl(ScreenMode screenMode) {
+        List screenModes = this.getScreenModesOrig();
+        int screenModeIdx = screenModes.indexOf(screenMode);
+        if(0>screenModeIdx) {
+            throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode);
+        }
+        int resNumber = getNumScreenModeResolutions0(display.getHandle(), screen_idx);
+        int resIdx = getScreenModesIdx2NativeIdx().get(screenModeIdx);
+        if(0>resIdx || resIdx>=resNumber) {
+            throw new RuntimeException("Invalid resolution index: ! 0 < "+resIdx+" < "+resNumber+", screenMode["+screenModeIdx+"] "+screenMode);
+        }
+        String tname = Thread.currentThread()+"-X11Screen.setCurrentScreenModeImpl()";
+        SetScreenModeAction setScreenModeAction = new SetScreenModeAction(screenMode, resIdx);
+        Thread randrTask = new Thread(setScreenModeAction, tname);
+        randrTask.start();
+        int to = SCREEN_MODE_CHANGE_TIMEOUT / 100 ;
+        while(to>0 && randrTask.isAlive()) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) { }
+            to--;
+        }
+        if(0==to && DEBUG) {
+            System.err.println("X11Screen.setCurrentScreenModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+
+                               randrTask+", alive "+randrTask.isAlive());
+        }
+        return setScreenModeAction.getResult();
     }
-    
-    private ScreenMode getScreenMode(int modeIndex){
-    	int[] modeProp = getScreenMode0(display.getHandle(), idx, modeIndex);
-    	
-    	if(modeProp == null){
-    		return null;
-    	}
-    	int propIndex = 0;
-    	int index = modeProp[propIndex++];
-    	int width = modeProp[propIndex++];
-    	int height = modeProp[propIndex++];
-    	
-    	ScreenMode screenMode = new ScreenMode(index, width, height);
-    	
-    	short[] rates = new short[modeProp.length - propIndex];
-    	for(int i= propIndex; i < modeProp.length; i++)
-    	{
-    		rates[i-propIndex] = (short) modeProp[i];
-    	}
-    	screenMode.setRates(rates);
-    	return screenMode;
+
+    class SetScreenModeAction implements Runnable {
+        boolean res;
+        ScreenMode screenMode;
+        int resIdx;
+
+        public SetScreenModeAction(ScreenMode screenMode, int resIdx) {
+            this.screenMode = screenMode;
+            this.resIdx = resIdx;
+            this.res = false;
+        }
+
+        public boolean getResult() {
+            return res;
+        }
+
+        public void run() {
+            long dpy = X11Util.createDisplay(display.getName());
+            if( 0 == dpy ) {
+                throw new RuntimeException("Error creating display: "+display.getName());
+            }
+            try {
+                res = setCurrentScreenMode0(dpy, screen_idx, resIdx,
+                                            screenMode.getMonitorMode().getRefreshRate(), screenMode.getRotation());
+            } finally {
+                X11Util.closeDisplay(dpy);
+            }
+        }
     }
-    
-	public void setScreenRotation(int rot) {
-		if(!isRotationValid(rot)){
-			return;
-		}
-		ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN());
-		setScreenRotation0(display.getHandle(), idx, rot);
-		sms.setCurrentScreenRotation(rot);
-	}
-
-	/** Check if this rotation is valid for platform
-	 * @param rot user requested rotation angle
-	 * @return true if is valid
-	 */
-	private boolean isRotationValid(int rot){
-		if((rot == ScreenMode.ROTATE_0) || (rot == ScreenMode.ROTATE_90) || 
-				(rot == ScreenMode.ROTATE_180) || (rot == ScreenMode.ROTATE_270)) {
-			return true;
-		}
-		return false;
-	}
-	
-	public int getCurrentScreenRotation() {
-		int rotation = super.getCurrentScreenRotation();
-		if(rotation == -1){
-			rotation = getCurrentScreenRotation0(display.getHandle(), idx);
-		}
-		return rotation;
-	}
-    
+
     //----------------------------------------------------------------------
     // Internals only
     //
+    private static native long GetScreen0(long dpy, int scrn_idx);
 
-    private native long GetScreen0(long dpy, int scrn_idx);
-    private native int  getWidth0(long display, int scrn_idx);
-    private native int  getHeight0(long display, int scrn_idx);
-
-    private native int getDesktopScreenModeIndex0(long display, int screen_index);
-    private native short getCurrentScreenRate0(long display, int screen_index);
-    
-    private native int getCurrentScreenRotation0(long display, int screen_index);
-    private native void setScreenRotation0(long display, int screen_index, int rot);
-    
-    private native void setScreenMode0(long display, int screen_index, int mode_index, short freq, int rot);
-    
-    private native int[] getScreenMode0(long display, int screen_index, int mode_index);
-    private native int getNumScreenModes0(long display, int screen_index);
+    private static native int getWidth0(long display, int scrn_idx);
 
-}
+    private static native int getHeight0(long display, int scrn_idx);
 
+    /** @return int[] { rot1, .. } */
+    private static native int[] getAvailableScreenModeRotations0(long display, int screen_index);
+
+    private static native int getNumScreenModeResolutions0(long display, int screen_index);
+
+    /** @return int[] { width, height, widthmm, heightmm } */
+    private static native int[] getScreenModeResolution0(long display, int screen_index, int mode_index);
+
+    private static native int[] getScreenModeRates0(long display, int screen_index, int mode_index);
+
+    private static native int getCurrentScreenResolutionIndex0(long display, int screen_index);
+    private static native int getCurrentScreenRate0(long display, int screen_index);
+    private static native int getCurrentScreenRotation0(long display, int screen_index);
+
+    /** needs own Display connection for XRANDR event handling */
+    private static native boolean setCurrentScreenMode0(long display, int screen_index, int mode_index, int freq, int rot);
+}
diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java
index 06c7dfa99..60af9b9af 100644
--- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java
+++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java
@@ -33,6 +33,7 @@
 
 package com.jogamp.newt.impl.x11;
 
+import com.jogamp.newt.ScreenMode;
 import com.jogamp.newt.impl.WindowImpl;
 import javax.media.nativewindow.*;
 import javax.media.nativewindow.x11.*;
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 50fe3f63a..aef4de92a 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -230,6 +230,14 @@ public class GLWindow implements GLAutoDrawable, Window {
         window.addChild(win);
     }
 
+    public void screenModeChangeNotify(ScreenMode sm) {
+        window.screenModeChangeNotify(sm);
+    }
+
+    public void screenModeChanged(ScreenMode sm, boolean success) {
+        window.screenModeChanged(sm, success);
+    }
+
     //----------------------------------------------------------------------
     // Window.LifecycleHook Implementation
     //
diff --git a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java
new file mode 100644
index 000000000..f24416469
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright 2010 JogAmp Community. 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 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.util;
+
+import javax.media.nativewindow.util.*;
+
+/** Immutable MonitorMode Class, consisting of it's read only components:<br>
+ * <ul>
+ *  <li>{@link javax.media.nativewindow.util.SurfaceSize} surface memory size</li>
+ *  <li>{@link javax.media.nativewindow.util.DimensionReadOnly} size in [mm]</li>
+ *  <li><code>refresh rate</code></li>
+ * </ul>
+ */
+public class MonitorMode  implements Cloneable {
+    SurfaceSize surfaceSize;
+    DimensionReadOnly screenSizeMM; // in [mm]
+    int refreshRate;
+
+    public MonitorMode(SurfaceSize surfaceSize, DimensionReadOnly screenSizeMM, int refreshRate) {
+        if(null==surfaceSize || refreshRate<=0) {
+            throw new IllegalArgumentException("surfaceSize must be set and refreshRate greater 0");
+        }
+        this.surfaceSize=surfaceSize;
+        this.screenSizeMM=screenSizeMM;
+        this.refreshRate=refreshRate;
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException ex) {
+            throw new InternalError();
+        }
+    }
+
+    public final SurfaceSize getSurfaceSize() {
+        return surfaceSize;
+    }
+
+    public final DimensionReadOnly getScreenSizeMM() {
+        return screenSizeMM;
+    }
+
+    public final int getRefreshRate() {
+        return refreshRate;
+    }
+
+    public final String toString() {
+        return new String("MonitorMode["+surfaceSize+" x "+refreshRate+" Hz, "+screenSizeMM+" [mm]x[mm]]");
+    }
+
+    /**
+     * Checks whether two size objects are equal. Two instances
+     * of <code>MonitorMode</code> are equal if the three components
+     * <code>surfaceSize</code>, <code>screenSizeMM</code> and <code>refreshRate</code>
+     * are equal.
+     * @return  <code>true</code> if the two dimensions are equal;
+     *          otherwise <code>false</code>.
+     */
+    public final boolean equals(Object obj) {
+        if (obj instanceof MonitorMode) {
+            MonitorMode p = (MonitorMode)obj;
+            return getSurfaceSize().equals(p.getSurfaceSize()) &&
+                   getScreenSizeMM().equals(p.getScreenSizeMM()) &&
+                   getRefreshRate() == p.getRefreshRate() ;
+        }
+        return false;
+    }
+
+    public final int hashCode() {
+        // 31 * x == (x << 5) - x
+        int hash = 31 + getSurfaceSize().hashCode();
+        hash = ((hash << 5) - hash) + getScreenSizeMM().hashCode();
+        hash = ((hash << 5) - hash) + getRefreshRate();
+        return hash;
+    }
+}
+
diff --git a/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java
new file mode 100644
index 000000000..9cb04c2a1
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java
@@ -0,0 +1,367 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.newt.util;
+
+import com.jogamp.common.util.ArrayHashSet;
+import com.jogamp.newt.ScreenMode;
+import java.util.ArrayList;
+import java.util.List;
+import javax.media.nativewindow.util.Dimension;
+import javax.media.nativewindow.util.DimensionReadOnly;
+import javax.media.nativewindow.util.SurfaceSize;
+
+/**
+ * Convenient {@link com.jogamp.newt.ScreenMode} utility methods,
+ * filters etc.
+ */
+public class ScreenModeUtil {
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation
+     * 2: width and height
+     */
+    public static final int NUM_RESOLUTION_PROPERTIES   = 2;
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation
+     * 1: bpp
+     */
+    public static final int NUM_SURFACE_SIZE_PROPERTIES = 1;
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation
+     * 3: ScreenSizeMM[width, height], refresh-rate
+     */
+    public static final int NUM_MONITOR_MODE_PROPERTIES = 3;
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation
+     * 1: rotation, native_mode_id
+     */
+    public static final int NUM_SCREEN_MODE_PROPERTIES  = 1;
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation
+     * count + all the above
+     */
+    public static final int NUM_SCREEN_MODE_PROPERTIES_ALL = 8;
+
+    public static int getIndex(List/*<ScreenMode>*/ screenModes, ScreenMode search) {
+        return screenModes.indexOf(search);
+    }
+
+    public static int getIndexByHashCode(List/*<ScreenMode>*/ screenModes, ScreenMode search) {
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            if ( search.hashCode() == ((ScreenMode)screenModes.get(i)).hashCode() ) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Validate the given list of {@link com.jogamp.newt.ScreenMode}s, testing on:<br>
+     * <ul>
+     *   <li> unique {@link com.jogamp.newt.ScreenMode}s by equality and hash code
+     * </ul>
+     * This
+     * @param screenModes list of {@link com.jogamp.newt.ScreenMode}s
+     * @param throwException if true and invalid throw IllegalArgumentException
+     * @return true if valid, otherwise false or throw IllegalArgumentException
+     * @throws IllegalArgumentException if invalid
+     */
+    public static boolean validate(List/*<ScreenMode>*/ screenModes, boolean throwException) {
+        for (int j=0; null!=screenModes && j<screenModes.size(); j++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(j);
+            List dups = new ArrayList();
+
+            /*** don't check slow-path 'equals' for now, hash is working
+            for (int i=0; i<screenModes.size(); i++) {
+                ScreenMode sm2 = (ScreenMode)screenModes.get(i);
+                if( i!=j && sm.equals(sm2) ) {
+                    dups.add(new Integer(i));
+                }
+            }
+            if(dups.size()>0) {
+                if(throwException) {
+                    throw new IllegalArgumentException("Element "+sm+" at index "+j+" is not unique (equality), duplicates: "+dups);
+                } else {
+                    return false;
+                }
+            } */
+
+            for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+                ScreenMode sm2 = (ScreenMode)screenModes.get(i);
+                if ( i!=j && sm.hashCode() == sm2.hashCode() ) {
+                    dups.add(new Integer(i));
+                }
+            }
+            if(dups.size()>0) {
+                if(throwException) {
+                    throw new IllegalArgumentException("Element "+sm+" at index "+j+" is not unique (hash), duplicates: "+dups);
+                } else {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @param screenModes
+     * @param resolution
+     * @return modes with nearest resolution, or matching ones
+     */
+    public static List/*<ScreenMode>*/ filterByResolution(List/*<ScreenMode>*/ screenModes, DimensionReadOnly resolution) {
+        List out = new ArrayList();
+        int resolution_sq = resolution.getHeight()*resolution.getWidth();
+        int sm_dsq=resolution_sq, sm_dsq_idx=0;
+
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            DimensionReadOnly res = sm.getMonitorMode().getSurfaceSize().getResolution();
+            int dsq = Math.abs(resolution_sq - res.getHeight()*res.getWidth());
+            if(dsq<sm_dsq) {
+                sm_dsq = dsq;
+                sm_dsq_idx = i;
+            }
+            if(res.equals(resolution)) {
+                out.add(sm);
+            }
+        }
+        if(out.size()>0) {
+            return out;
+        }
+        // nearest ..
+        resolution = ((ScreenMode)screenModes.get(sm_dsq_idx)).getMonitorMode().getSurfaceSize().getResolution();
+        return filterByResolution(screenModes, resolution);
+    }
+
+    public static List/*<ScreenMode>*/ filterBySurfaceSize(List/*<ScreenMode>*/ screenModes, SurfaceSize surfaceSize) {
+        List out = new ArrayList();
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            if(sm.getMonitorMode().getSurfaceSize().equals(surfaceSize)) {
+                out.add(sm);
+            }
+        }
+        return out;
+    }
+
+    public static List/*<ScreenMode>*/ filterByRotation(List/*<ScreenMode>*/ screenModes, int rotation) {
+        List out = new ArrayList();
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            if(sm.getRotation() == rotation) {
+                out.add(sm);
+            }
+        }
+        return out;
+    }
+
+    public static List/*<ScreenMode>*/ filterByBpp(List/*<ScreenMode>*/ screenModes, int bitsPerPixel) {
+        List out = new ArrayList();
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            if(sm.getMonitorMode().getSurfaceSize().getBitsPerPixel() == bitsPerPixel) {
+                out.add(sm);
+            }
+        }
+        return out;
+    }
+
+    /**
+     *
+     * @param screenModes
+     * @param refreshRate
+     * @return modes with nearest refreshRate, or matching ones
+     */
+    public static List/*<ScreenMode>*/ filterByRate(List/*<ScreenMode>*/ screenModes, int refreshRate) {
+        int sm_dr = refreshRate;
+        int sm_dr_idx = -1;
+        List out = new ArrayList();
+        for (int i=0; null!=screenModes && i<screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            int dr = Math.abs(refreshRate - sm.getMonitorMode().getRefreshRate());
+            if(dr<sm_dr) {
+                sm_dr = dr;
+                sm_dr_idx = i;
+            }
+            if(0 == dr) {
+                out.add(sm);
+            }
+        }
+        if(out.size()>0) {
+            return out;
+        }
+        refreshRate = ((ScreenMode)screenModes.get(sm_dr_idx)).getMonitorMode().getRefreshRate();
+        return filterByRate(screenModes, refreshRate);
+    }
+
+    public static List/*<ScreenMode>*/ getHighestAvailableBpp(List/*<ScreenMode>*/ screenModes) {
+        int highest = -1;
+        for (int i=0; null!=screenModes && i < screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            int bpp  = sm.getMonitorMode().getSurfaceSize().getBitsPerPixel();
+            if (bpp > highest) {
+                highest = bpp;
+            }
+        }
+        return filterByBpp(screenModes, highest);
+    }
+
+    public static List/*<ScreenMode>*/ getHighestAvailableRate(List/*<ScreenMode>*/ screenModes) {
+        int highest = -1;
+        for (int i=0; null!=screenModes && i < screenModes.size(); i++) {
+            ScreenMode sm = (ScreenMode)screenModes.get(i);
+            int rate = sm.getMonitorMode().getRefreshRate();
+            if (rate > highest) {
+                highest = rate;
+            }
+        }
+        return filterByRate(screenModes, highest);
+    }
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+    public static DimensionReadOnly streamInResolution(int[] resolutionProperties, int offset) {
+        Dimension resolution = new Dimension(resolutionProperties[offset++], resolutionProperties[offset++]);
+        return resolution;
+    }
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+    public static SurfaceSize streamInSurfaceSize(DimensionReadOnly resolution, int[] sizeProperties, int offset) {
+        SurfaceSize surfaceSize = new SurfaceSize(resolution, sizeProperties[offset++]);
+        return surfaceSize;
+    }
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+    public static MonitorMode streamInMonitorMode(SurfaceSize surfaceSize, DimensionReadOnly screenSizeMM, int[] monitorProperties, int offset) {
+        int refreshRate = monitorProperties[offset++];
+        return new MonitorMode(surfaceSize, screenSizeMM, refreshRate);
+    }
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+    public static ScreenMode streamInScreenMode(MonitorMode monitorMode, int[] modeProperties, int offset) {
+        int rotation = modeProperties[offset++];
+        return new ScreenMode(monitorMode, rotation);
+    }
+
+    /**
+     *  WARNING: must be synchronized with ScreenMode.h, native implementation
+     *
+     * @param modeProperties the input data
+     * @param offset the offset to the input data
+     * @return index of the identical (old or new) ScreenMode element in <code>screenModePool</code>,
+     *         matching the input <code>modeProperties</code>, or -1 if input could not be processed.
+     */
+    public static ScreenMode streamIn(int[] modeProperties, int offset) {
+        return streamInImpl(null, null, null, null, null, modeProperties, offset);
+    }
+
+    /**
+     *  WARNING: must be synchronized with ScreenMode.h, native implementation
+     *
+     * @param resolutionPool hash array of unique DimensionReadOnly resolutions, no duplicates
+     * @param surfaceSizePool hash array of unique SurfaceSize, no duplicates
+     * @param monitorModePool hash array of unique MonitorMode, no duplicates
+     * @param screenModePool hash array of unique ScreenMode, no duplicates
+     * @param modeProperties the input data
+     * @param offset the offset to the input data
+     * @return index of the identical (old or new) ScreenMode element in <code>screenModePool</code>,
+     *         matching the input <code>modeProperties</code>, or -1 if input could not be processed.
+     */
+    public static int streamIn(ArrayHashSet resolutionPool,
+                               ArrayHashSet surfaceSizePool,
+                               ArrayHashSet screenSizeMMPool,
+                               ArrayHashSet monitorModePool,
+                               ArrayHashSet screenModePool,
+                               int[] modeProperties, int offset) {
+        ScreenMode screenMode = streamInImpl(resolutionPool, surfaceSizePool, screenSizeMMPool, monitorModePool, screenModePool,
+                                         modeProperties, offset);
+        return screenModePool.indexOf(screenMode);
+    }
+
+    private static ScreenMode streamInImpl(ArrayHashSet resolutionPool,
+                                       ArrayHashSet surfaceSizePool,
+                                       ArrayHashSet screenSizeMMPool,
+                                       ArrayHashSet monitorModePool,
+                                       ArrayHashSet screenModePool,
+                                       int[] modeProperties, int offset) {
+        int count = modeProperties[offset];
+        if(NUM_SCREEN_MODE_PROPERTIES_ALL != count) {
+            throw new RuntimeException("NUM_SCREEN_MODE_PROPERTIES should be "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+count+", len "+(modeProperties.length-offset));
+        }
+        if(NUM_SCREEN_MODE_PROPERTIES_ALL > modeProperties.length-offset) {
+            throw new RuntimeException("properties array too short, should be >= "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+(modeProperties.length-offset));
+        }
+        offset++;
+        DimensionReadOnly resolution = ScreenModeUtil.streamInResolution(modeProperties, offset);
+        offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
+        if(null!=resolutionPool) {
+            resolution = (DimensionReadOnly) resolutionPool.getOrAdd(resolution);
+        }
+
+        SurfaceSize surfaceSize = ScreenModeUtil.streamInSurfaceSize(resolution, modeProperties, offset);
+        offset += ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES;
+        if(null!=surfaceSizePool) {
+            surfaceSize = (SurfaceSize) surfaceSizePool.getOrAdd(surfaceSize);
+        }
+
+        DimensionReadOnly screenSizeMM = ScreenModeUtil.streamInResolution(modeProperties, offset);
+        offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
+        if(null!=screenSizeMMPool) {
+            screenSizeMM = (DimensionReadOnly) screenSizeMMPool.getOrAdd(screenSizeMM);
+        }
+
+        MonitorMode monitorMode = ScreenModeUtil.streamInMonitorMode(surfaceSize, screenSizeMM, modeProperties, offset);
+        offset += ScreenModeUtil.NUM_MONITOR_MODE_PROPERTIES - ScreenModeUtil.NUM_RESOLUTION_PROPERTIES;
+        if(null!=monitorModePool) {
+            monitorMode = (MonitorMode) monitorModePool.getOrAdd(monitorMode);
+        }
+
+        ScreenMode screenMode = ScreenModeUtil.streamInScreenMode(monitorMode, modeProperties, offset);
+        if(null!=screenModePool) {
+            screenMode = (ScreenMode) screenModePool.getOrAdd(screenMode);
+        }
+        return screenMode;
+    }
+
+    /** WARNING: must be synchronized with ScreenMode.h, native implementation */
+    public static int[] streamOut (ScreenMode screenMode) {
+        int[] data = new int[NUM_SCREEN_MODE_PROPERTIES_ALL];
+        int idx=0;
+        data[idx++] = NUM_SCREEN_MODE_PROPERTIES_ALL;
+        data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getWidth();
+        data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getHeight();
+        data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getBitsPerPixel();
+        data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getWidth();
+        data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getHeight();
+        data[idx++] = screenMode.getMonitorMode().getRefreshRate();
+        data[idx++] = screenMode.getRotation();
+        if(NUM_SCREEN_MODE_PROPERTIES_ALL != idx) {
+            throw new InternalError("wrong number of attributes: got "+idx+" != should "+NUM_SCREEN_MODE_PROPERTIES_ALL);
+        }
+        return data;
+    }
+
+}
-- 
cgit v1.2.3