Jogamp
Bug 741 HiDPI: Add ScalableSurface.getNativeSurfaceScale(..) to compute surface DPI...
authorSven Gothel <sgothel@jausoft.com>
Mon, 9 Jun 2014 01:58:37 +0000 (03:58 +0200)
committerSven Gothel <sgothel@jausoft.com>
Mon, 9 Jun 2014 01:58:37 +0000 (03:58 +0200)
With HiDPI and surface scale, we need knowledge of the native surface's pixel-scale
matching the monitor's pixel-per-millimeter value.

Preserving the queried native pixel-scale and exposing it via
ScalableSurface.getNativeSurfaceScale(..) to compute surface DPI.

Add NEWT Window.getPixelsPerMM(..) to query surface DPI.

Surface DPI is demonstrated in GraphUI's GPUUISceneGLListener0A .. and TestRulerNEWT01, etc ..

22 files changed:
make/scripts/tests.sh
src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java
src/nativewindow/classes/javax/media/nativewindow/util/Dimension.java
src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java
src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
src/newt/classes/com/jogamp/newt/MonitorDevice.java
src/newt/classes/com/jogamp/newt/Window.java
src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
src/newt/classes/jogamp/newt/WindowImpl.java
src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
src/newt/native/NewtMacWindow.m
src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java
src/test/com/jogamp/opengl/test/junit/graph/TextRendererGLELBase.java
src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java
src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java
src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestRulerNEWT01.java

index 3c79ebb..9069532 100644 (file)
@@ -363,7 +363,10 @@ function testawtswt() {
 #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
 #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $*
 #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $*
-testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestRulerNEWT01 $*
+#testawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtCanvasAWTDemo $*
+#testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $*
 #testawt com.jogamp.opengl.test.junit.jogl.awt.ManualHiDPIBufferedImage01AWT $*
 
 #
index 12db864..9086d1a 100644 (file)
@@ -170,7 +170,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
   private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
   private volatile GLContextImpl context; // volatile: avoid locking for read-only access
   private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
-  private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
   final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
 
   // copy of the cstr args, mainly for recreation
@@ -692,6 +693,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
       return result;
   }
 
+  @Override
+  public int[] getNativeSurfaceScale(final int[] result) {
+      System.arraycopy(nativePixelScale, 0, result, 0, 2);
+      return result;
+  }
+
   private void createJAWTDrawableAndContext() {
     if ( !Beans.isDesignTime() ) {
         jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig);
@@ -702,6 +709,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
             drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
             createContextImpl(drawable);
             jawtWindow.getCurrentSurfaceScale(hasPixelScale);
+            jawtWindow.getNativeSurfaceScale(nativePixelScale);
         } finally {
             jawtWindow.unlockSurface();
         }
@@ -1307,6 +1315,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
         }
         hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
         hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+        nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+        nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
 
         if(null != awtConfig) {
             final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration();
index 223badf..21ca0c7 100644 (file)
@@ -247,8 +247,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
   private boolean handleReshape = false;
   private boolean sendReshape = true;
 
-  private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
-  private volatile int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+  private final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
 
   // For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width
   private int reshapeWidth;
@@ -488,6 +489,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
     }
     hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
     hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+    nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+    nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
 
     if(DEBUG) {
         System.err.println(getThreadName()+": GLJPanel.dispose() - stop");
@@ -568,14 +571,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
       SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null);
       final Backend b = backend;
       if ( isInitialized && null != b ) {
-          final int[] pixelScaleInt;
-          {
-              final int ps = JAWTUtil.getPixelScale(getGraphicsConfiguration());
-              pixelScaleInt = new int[] { ps, ps };
-          }
           final int hadPixelScaleX = hasPixelScale[0];
           final int hadPixelScaleY = hasPixelScale[1];
-          SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
+          SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null);
           if( hadPixelScaleX != hasPixelScale[0] || hadPixelScaleY != hasPixelScale[1] ) {
               updateWrappedSurfaceScale(b.getDrawable());
               reshapeImpl(getWidth(), getHeight());
@@ -596,6 +594,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
       return result;
   }
 
+  @Override
+  public int[] getNativeSurfaceScale(final int[] result) {
+      System.arraycopy(nativePixelScale, 0, result, 0, 2);
+      return result;
+  }
+
   /** Overridden to track when this component is added to a container.
       Subclasses which override this method must call
       super.addNotify() in their addNotify() method in order to
@@ -608,12 +612,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
     awtWindowClosingProtocol.addClosingListener();
 
     // HiDPI support
-    final int[] pixelScaleInt;
     {
         final int ps = JAWTUtil.getPixelScale(getGraphicsConfiguration());
-        pixelScaleInt = new int[] { ps, ps };
+        nativePixelScale[0] = ps;
+        nativePixelScale[1] = ps;
     }
-    SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
+    SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null);
 
     if (DEBUG) {
         System.err.println(getThreadName()+": GLJPanel.addNotify()");
index 1cc8fdb..6271083 100644 (file)
@@ -101,7 +101,8 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
   protected Insets insets;
   private volatile long offscreenSurfaceLayer;
 
-  private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
   protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
 
   private long drawable_old;
@@ -266,6 +267,8 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
     insets = new Insets();
     hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
     hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+    nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+    nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
   }
   protected abstract void invalidateNative();
 
@@ -293,6 +296,12 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
       return result;
   }
 
+  @Override
+  public final int[] getNativeSurfaceScale(final int[] result) {
+      System.arraycopy(nativePixelScale, 0, result, 0, 2);
+      return result;
+  }
+
   /**
    * Updates bounds and pixelScale
    * @return true if bounds or pixelScale has changed, otherwise false
@@ -312,6 +321,11 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
             insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
         }
     }
+    {
+        final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
+        nativePixelScale[0] = ps;
+        nativePixelScale[1] = ps;
+    }
 
     return updatePixelScale() || changedBounds;
   }
@@ -321,12 +335,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
    * @return true if pixelScale has changed, otherwise false
    */
   protected final boolean updatePixelScale() {
-    final int[] pixelScaleInt;
-    {
-        final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
-        pixelScaleInt = new int[] { ps, ps };
-    }
-    return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
+    return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null);
   }
 
   /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */
index de6ba51..ffd5c22 100644 (file)
@@ -65,7 +65,7 @@ public interface ScalableSurface {
    * Returns the requested pixel scale of the associated {@link NativeSurface}.
    *
    * @param result int[2] storage for the result
-   * @return the passed storage containing the requested pixelSize for chaining
+   * @return the passed storage containing the requested pixelScale for chaining
    */
   int[] getRequestedSurfaceScale(final int[] result);
 
@@ -73,8 +73,25 @@ public interface ScalableSurface {
    * Returns the current pixel scale of the associated {@link NativeSurface}.
    *
    * @param result int[2] storage for the result
-   * @return the passed storage containing the current pixelSize for chaining
+   * @return the passed storage containing the current pixelScale for chaining
    */
   public int[] getCurrentSurfaceScale(final int[] result);
+
+  /**
+   * Returns the native pixel scale of the associated {@link NativeSurface}
+   * reflecting it's currently bound <i>monitor surface resolution in pixels</i>.
+   * <p>
+   * The native pixel scale maybe used to determine the proper <i>dpi</i>
+   * value of this {@link NativeSurface}:
+   * <pre>
+   *    surfacePpMM = monitorPpMM * currentSurfaceScale / nativeSurfaceScale,
+   *    with PpMM == pixel per millimeter
+   * </pre>
+   * </p>
+   *
+   * @param result int[2] storage for the result
+   * @return the passed storage containing the native pixelScale for chaining
+   */
+  public int[] getNativeSurfaceScale(final int[] result);
 }
 
index 24ccc83..5c9dc27 100644 (file)
@@ -37,7 +37,11 @@ public class Dimension implements Cloneable, DimensionImmutable {
         this(0, 0);
     }
 
-    public Dimension(int width, int height) {
+    public Dimension(final int[] size) {
+        this(size[0], size[1]);
+    }
+
+    public Dimension(final int width, final int height) {
         if(width<0 || height<0) {
             throw new IllegalArgumentException("width and height must be within: ["+0+".."+Integer.MAX_VALUE+"]");
         }
index 22e67ec..3aea588 100644 (file)
@@ -58,37 +58,34 @@ public class SurfaceScaleUtils {
      * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place
      * @param prePixelScale previous pixelScale
      * @param reqPixelScale requested pixelScale, validated via {@link #validateReqPixelScale(int[], int, String)}.
-     * @param surfPixelScaleRaw raw surface pixelScale
+     * @param newPixelScaleRaw new raw surface pixelScale
      * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix
      * @return true if pixelScale has changed, otherwise false
      */
-    public static boolean computePixelScale(int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] surfPixelScaleRaw, final String DEBUG_PREFIX) {
-        final int surfPixelScaleSafeX = 0 < surfPixelScaleRaw[0] ? surfPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE;
-        final int surfPixelScaleSafeY = 0 < surfPixelScaleRaw[1] ? surfPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE;
+    public static boolean computePixelScale(int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] newPixelScaleRaw, final String DEBUG_PREFIX) {
+        final int newPixelScaleSafeX = 0 < newPixelScaleRaw[0] ? newPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE;
+        final int newPixelScaleSafeY = 0 < newPixelScaleRaw[1] ? newPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE;
         final boolean useHiDPI = ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[0] || ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[1];
         final int prePixelScaleX = prePixelScale[0];
         final int prePixelScaleY = prePixelScale[1];
 
         if( useHiDPI ) {
-            result[0] = surfPixelScaleSafeX;
-            result[1] = surfPixelScaleSafeY;
+            result[0] = newPixelScaleSafeX;
+            result[1] = newPixelScaleSafeY;
         } else {
             result[0] = ScalableSurface.IDENTITY_PIXELSCALE;
             result[1] = ScalableSurface.IDENTITY_PIXELSCALE;
         }
 
-        if( result[0] != prePixelScaleX || result[1] != prePixelScaleY ) {
-            if( null != DEBUG_PREFIX ) {
-                System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+
-                        reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+
-                        surfPixelScaleRaw[0]+"x"+surfPixelScaleRaw[1]+" (raw) -> "+
-                        surfPixelScaleSafeX+"x"+surfPixelScaleSafeY+" (safe) -> "+
-                        result[0]+"x"+result[1]+" (use)");
-            }
-            return true;
-        } else {
-            return false;
+        final boolean changed = result[0] != prePixelScaleX || result[1] != prePixelScaleY;
+        if( null != DEBUG_PREFIX ) {
+            System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+
+                    reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+
+                    newPixelScaleRaw[0]+"x"+newPixelScaleRaw[1]+" (raw) -> "+
+                    newPixelScaleSafeX+"x"+newPixelScaleSafeY+" (safe) -> "+
+                    result[0]+"x"+result[1]+" (use), changed "+changed);
         }
+        return changed;
     }
 
     /**
index 8f93791..752057a 100644 (file)
@@ -164,4 +164,10 @@ public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface
       return result;
   }
 
+  @Override
+  public final int[] getNativeSurfaceScale(final int[] result) {
+      System.arraycopy(hasPixelScale, 0, result, 0, 2);
+      return result;
+  }
+
 }
\ No newline at end of file
index 8e5d305..a656752 100644 (file)
@@ -34,6 +34,7 @@ import javax.media.nativewindow.util.DimensionImmutable;
 import javax.media.nativewindow.util.Rectangle;
 import javax.media.nativewindow.util.RectangleImmutable;
 import javax.media.nativewindow.util.SurfaceSize;
+
 import com.jogamp.common.util.ArrayHashSet;
 
 /**
@@ -124,29 +125,34 @@ public abstract class MonitorDevice {
     }
 
     /**
-     * Stores the <i>pixels per millimeter</i> value according to <i>current</i> {@link MonitorMode}
-     * {@link SurfaceSize#getResolution() SurfaceSize's resolution} in the given storage <code>ppmmStore</code>.
+     * Returns the <i>pixels per millimeter</i> value according to the <i>current</i> {@link MonitorMode mode}'s
+     * {@link SurfaceSize#getResolution() surface resolution}.
      * <p>
      * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
      * </p>
+     * @param ppmmStore float[2] storage for the ppmm result
+     * @return the passed storage containing the ppmm for chaining
      */
-    public final void getPixelsPerMM(final float[] ppmmStore) {
-        final MonitorMode mode = getCurrentMode();
-        getPixelsPerMM(mode, ppmmStore);
+    public final float[] getPixelsPerMM(final float[] ppmmStore) {
+        return getPixelsPerMM(getCurrentMode(), ppmmStore);
     }
 
     /**
-     * Stores the <i>pixels per millimeter</i> value according to the given {@link MonitorMode}
-     * {@link SurfaceSize#getResolution() SurfaceSize's resolution} in the given storage <code>ppmmStore</code>.
+     * Returns the <i>pixels per millimeter</i> value according to the given {@link MonitorMode mode}'s
+     * {@link SurfaceSize#getResolution() surface resolution}.
      * <p>
      * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
      * </p>
+     * @param mode
+     * @param ppmmStore float[2] storage for the ppmm result
+     * @return the passed storage containing the ppmm for chaining
      */
-    public final void getPixelsPerMM(final MonitorMode mode, final float[] ppmmStore) {
+    public final float[] getPixelsPerMM(final MonitorMode mode, final float[] ppmmStore) {
         final DimensionImmutable sdim = getSizeMM();
         final DimensionImmutable spix = mode.getSurfaceSize().getResolution();
         ppmmStore[0] = (float)spix.getWidth() / (float)sdim.getWidth();
         ppmmStore[1] = (float)spix.getHeight() / (float)sdim.getHeight();
+        return ppmmStore;
     }
 
     /**
index 08236ae..600ecee 100644 (file)
@@ -49,6 +49,7 @@ import javax.media.nativewindow.ScalableSurface;
 import javax.media.nativewindow.WindowClosingProtocol;
 import javax.media.nativewindow.util.Rectangle;
 import javax.media.nativewindow.util.RectangleImmutable;
+import javax.media.nativewindow.util.SurfaceSize;
 
 /**
  * Specifying NEWT's Window functionality:
@@ -254,6 +255,26 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur
     Rectangle getBounds();
 
     /**
+     * Returns the <i>pixels per millimeter</i> of this window's {@link NativeSurface}
+     * according to the {@link #getMainMonitor() main monitor}'s <i>current</i> {@link MonitorMode mode}'s
+     * {@link SurfaceSize#getResolution() surface resolution}.
+     * <p>
+     * Method takes the {@link #getCurrentSurfaceScale(int[]) current surface-scale} and {@link #getNativeSurfaceScale(int[]) native surface-scale}
+     * into account, i.e.:
+     * <pre>
+     *    surfacePpMM = monitorPpMM * currentSurfaceScale / nativeSurfaceScale,
+     *    with PpMM == pixel per millimeter
+     * </pre>
+     * </p>
+     * <p>
+     * To convert the result to <i>dpi</i>, i.e. dots-per-inch, multiply both components with <code>25.4f</code>.
+     * </p>
+     * @param ppmmStore float[2] storage for the ppmm result
+     * @return the passed storage containing the ppmm for chaining
+     */
+    float[] getPixelsPerMM(final float[] ppmmStore);
+
+    /**
      * Sets the size of the window's client area in window units, excluding decorations.
      *
      * <p>
index 2991bb9..cdc4f12 100644 (file)
@@ -404,6 +404,16 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
     }
 
     @Override
+    public final int[] getNativeSurfaceScale(final int[] result) {
+        return window.getNativeSurfaceScale(result);
+    }
+
+    @Override
+    public final float[] getPixelsPerMM(final float[] ppmmStore) {
+        return window.getPixelsPerMM(ppmmStore);
+    }
+
+    @Override
     public final void setPosition(int x, int y) {
         window.setPosition(x, y);
     }
index 0501f6a..61fa7af 100644 (file)
@@ -152,8 +152,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
     private volatile boolean hasFocus = false;
     private volatile int pixWidth = 128, pixHeight = 128; // client-area size w/o insets in pixel units, default: may be overwritten by user
     private volatile int winWidth = 128, winHeight = 128; // client-area size w/o insets in window units, default: may be overwritten by user
-    protected int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
-    protected int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+    protected final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+    protected final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+    protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
 
     private volatile int x = 64, y = 64; // client-area pos w/o insets in window units
     private volatile Insets insets = new Insets(); // insets of decoration (if top-level && decorated)
@@ -1092,7 +1093,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         setSize(width - getInsets().getTotalWidth(), height - getInsets().getTotalHeight());
     }
 
-    private class DestroyAction implements Runnable {
+    private final Runnable destroyAction = new Runnable() {
         @Override
         public final void run() {
             boolean animatorPaused = false;
@@ -1164,6 +1165,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                 fullscreenUseMainMonitor = true;
                 hasFocus = false;
                 parentWindowHandle = 0;
+                hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+                hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+                nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+                nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
 
                 _lock.unlock();
             }
@@ -1187,9 +1192,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
             windowListeners = null;
             parentWindow = null;
             */
-        }
-    }
-    private final DestroyAction destroyAction = new DestroyAction();
+        } };
 
     @Override
     public void destroy() {
@@ -1567,7 +1570,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         }
     }
 
-    private class ReparentActionRecreate implements Runnable {
+    private final Runnable reparentActionRecreate = new Runnable() {
         @Override
         public final void run() {
             final RecursiveLock _lock = windowLock;
@@ -1581,9 +1584,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
             } finally {
                 _lock.unlock();
             }
-        }
-    }
-    private final ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate();
+        } };
 
     @Override
     public final ReparentOperation reparentWindow(NativeWindow newParent, int x, int y, int hints) {
@@ -1958,6 +1959,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         return result;
     }
 
+    @Override
+    public final int[] getNativeSurfaceScale(final int[] result) {
+        System.arraycopy(nativePixelScale, 0, result, 0, 2);
+        return result;
+    }
+
+    @Override
+    public final float[] getPixelsPerMM(final float[] ppmmStore) {
+        getMainMonitor().getPixelsPerMM(ppmmStore);
+        ppmmStore[0] *= (float)hasPixelScale[0] / (float)nativePixelScale[0];
+        ppmmStore[1] *= (float)hasPixelScale[1] / (float)nativePixelScale[1];
+        return ppmmStore;
+    }
+
     protected final boolean autoPosition() { return autoPosition; }
 
     /** Sets the position fields {@link #x} and {@link #y} in window units to the given values and {@link #autoPosition} to false. */
index 4985566..b44c2a3 100644 (file)
@@ -67,14 +67,18 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
     public WindowDriver() {
     }
 
-    private boolean updatePixelScale(final boolean sendEvent, final boolean defer, final float pixelScaleRaw) {
-        final int[] pixelScaleInt;
+    private boolean updatePixelScale(final boolean sendEvent, final boolean defer, final float newPixelScaleRaw, final float nativePixelScaleRaw) {
+        final int[] newPixelScale = new int[2];
         {
-            final int ps = FloatUtil.isZero(pixelScaleRaw, FloatUtil.EPSILON) ? 1 : (int) pixelScaleRaw;
-            pixelScaleInt = new int[] { ps, ps };
+            final int _newPixelScale = FloatUtil.isZero(newPixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : (int) newPixelScaleRaw;
+            newPixelScale[0]= _newPixelScale;
+            newPixelScale[1]= _newPixelScale;
+            final int _nativePixelScale = FloatUtil.isZero(nativePixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : (int) nativePixelScaleRaw;
+            nativePixelScale[0]= _nativePixelScale;
+            nativePixelScale[1]= _nativePixelScale;
         }
 
-        if( SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG_IMPLEMENTATION ? getClass().getName() : null) ) {
+        if( SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, newPixelScale, DEBUG_IMPLEMENTATION ? getClass().getName() : null) ) {
             if( sendEvent ) {
                 super.sizeChanged(defer, getWidth(), getHeight(), true);
             } else {
@@ -87,34 +91,34 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
     }
 
     private boolean updatePixelScaleByScreenIdx(final boolean sendEvent) {
-        final float newPixelScaleRaw = (float) OSXUtil.GetPixelScale(getScreen().getIndex());
+        final float nativePixelScaleRaw = (float) OSXUtil.GetPixelScale(getScreen().getIndex());
         if( DEBUG_IMPLEMENTATION ) {
-            System.err.println("WindowDriver.updatePixelScale.1: "+hasPixelScale[0]+" -> "+newPixelScaleRaw);
+            System.err.println("WindowDriver.updatePixelScale.1: "+hasPixelScale[0]+", "+nativePixelScaleRaw+" (native)");
         }
-        return updatePixelScale(sendEvent, true /* defer */, newPixelScaleRaw);
+        return updatePixelScale(sendEvent, true /* defer */, nativePixelScaleRaw, nativePixelScaleRaw);
     }
 
     private boolean updatePixelScaleByWindowHandle(final boolean sendEvent) {
         final long handle = getWindowHandle();
         if( 0 != handle ) {
-            final float newPixelScaleRaw = (float)OSXUtil.GetPixelScale(handle);
+            final float nativePixelScaleRaw = (float)OSXUtil.GetPixelScale(handle);
             if( DEBUG_IMPLEMENTATION ) {
-                System.err.println("WindowDriver.updatePixelScale.2: "+hasPixelScale[0]+" -> "+newPixelScaleRaw);
+                System.err.println("WindowDriver.updatePixelScale.2: "+hasPixelScale[0]+", "+nativePixelScaleRaw+" (native)");
             }
-            return updatePixelScale(sendEvent, true /* defer */, newPixelScaleRaw);
+            return updatePixelScale(sendEvent, true /* defer */, nativePixelScaleRaw, nativePixelScaleRaw);
         } else {
             return false;
         }
     }
 
     /** Called from native code */
-    protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw) {
+    protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw, final float nativePixelScaleRaw) {
         final long handle = getWindowHandle();
         if( DEBUG_IMPLEMENTATION ) {
-            System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (raw), drop "+(0==handle));
+            System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (raw), "+nativePixelScaleRaw+" (native), drop "+(0==handle));
         }
         if( 0 != handle ) {
-            updatePixelScale(true /* sendEvent*/, defer, newPixelScaleRaw);
+            updatePixelScale(true /* sendEvent*/, defer, newPixelScaleRaw, nativePixelScaleRaw);
         }
     }
 
@@ -146,11 +150,12 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
                     final ScalableSurface sSurf = (ScalableSurface)pWin;
                     sSurf.setSurfaceScale(reqPixelScale);
                     final int[] pPixelScale = sSurf.getCurrentSurfaceScale(new int[2]);
-                    updatePixelScale(true /* sendEvent */, true /* defer */, pPixelScale[0]); // HiDPI: uniformPixelScale
+                    sSurf.getNativeSurfaceScale(nativePixelScale);
+                    updatePixelScale(true /* sendEvent */, true /* defer */, pPixelScale[0], nativePixelScale[0]); // HiDPI: uniformPixelScale
                 } else {
                     // just notify updated pixelScale if offscreen
                     SurfaceScaleUtils.replaceAutoMaxWithPlatformMax(reqPixelScale);
-                    updatePixelScale(true /* sendEvent */, true /* defer */, reqPixelScale[0]); // HiDPI: uniformPixelScale
+                    updatePixelScale(true /* sendEvent */, true /* defer */, reqPixelScale[0], nativePixelScale[0]); // HiDPI: uniformPixelScale
                 }
             } else {
                 // set pixelScale in native code, will issue an update PixelScale
index fe76183..5a19631 100644 (file)
@@ -780,9 +780,9 @@ static jmethodID windowRepaintID = NULL;
 
     // HiDPI scaling
     BOOL useHiDPI = [self wantsBestResolutionOpenGLSurface];
-    CGFloat pixelScaleRaw = [[self window] backingScaleFactor];
-    CGFloat pixelScaleUse = useHiDPI ? pixelScaleRaw : 1.0;
-    DBG_PRINT("viewDidChangeBackingProperties: PixelScale: HiDPI %d, raw %f -> use %f\n", useHiDPI, (float)pixelScaleRaw, (float)pixelScaleUse);
+    CGFloat pixelScaleNative = [[self window] backingScaleFactor];
+    CGFloat pixelScaleUse = useHiDPI ? pixelScaleNative : 1.0;
+    DBG_PRINT("viewDidChangeBackingProperties: PixelScale: HiDPI %d, native %f -> use %f\n", useHiDPI, (float)pixelScaleNative, (float)pixelScaleUse);
     [[self layer] setContentsScale: pixelScaleUse];
 
     if (javaWindowObject == NULL) {
@@ -796,7 +796,7 @@ static jmethodID windowRepaintID = NULL;
         return;
     }
 
-    (*env)->CallVoidMethod(env, javaWindowObject, updatePixelScaleID, JNI_TRUE, (jfloat)pixelScaleUse); // defer 
+    (*env)->CallVoidMethod(env, javaWindowObject, updatePixelScaleID, JNI_TRUE, (jfloat)pixelScaleUse, (jfloat)pixelScaleNative); // defer 
 
     // detaching thread not required - daemon
     // NewtCommon_ReleaseJNIEnv(shallBeDetached);
@@ -812,7 +812,7 @@ static jmethodID windowRepaintID = NULL;
     enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZSIIISF)V");
     enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZSISCC)V");
     sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V");
-    updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZF)V");
+    updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZFF)V");
     visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V");
     insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V");
     positionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V");
index ad95b35..2e0be5b 100644 (file)
@@ -53,7 +53,6 @@ import com.jogamp.graph.curve.opengl.RenderState;
 import com.jogamp.graph.font.Font;
 import com.jogamp.graph.font.FontFactory;
 import com.jogamp.graph.geom.SVertex;
-import com.jogamp.newt.MonitorDevice;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.opengl.GLWindow;
 import com.jogamp.opengl.test.junit.util.MiscUtils;
@@ -312,9 +311,7 @@ public class TestTextRendererNEWT00 extends UITestCase {
             t0 = Platform.currentTimeMillis();
 
             final Window win = (Window)drawable.getUpstreamWidget();
-            final MonitorDevice monitor = win.getMainMonitor();
-            final float[] pixelsPerMM = new float[2];
-            monitor.getPixelsPerMM(pixelsPerMM);
+            final float[] pixelsPerMM = win.getPixelsPerMM(new float[2]);
             final float[] dotsPerInch = new float[] { pixelsPerMM[0]*25.4f, pixelsPerMM[1]*25.4f };
             dpiH = dotsPerInch[1];
             System.err.println(getFontInfo());
index f948b9b..1c4a20b 100644 (file)
@@ -145,8 +145,7 @@ public abstract class TextRendererGLELBase implements GLEventListener {
 
         final Object upObj = drawable.getUpstreamWidget();
         if( upObj instanceof Window ) {
-            final float[] pixelsPerMM = new float[2];
-            ((Window)upObj).getMainMonitor().getPixelsPerMM(pixelsPerMM);
+            final float[] pixelsPerMM = ((Window)upObj).getPixelsPerMM(new float[2]);
             dpiH = pixelsPerMM[1]*25.4f;
         }
     }
index 89aa4d0..76bcfd0 100644 (file)
@@ -166,7 +166,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
         final Object upObj = drawable.getUpstreamWidget();
         if( upObj instanceof Window ) {
             final float[] pixelsPerMM = new float[2];
-            ((Window)upObj).getMainMonitor().getPixelsPerMM(pixelsPerMM);
+            ((Window)upObj).getPixelsPerMM(pixelsPerMM);
             dpiH = pixelsPerMM[1]*25.4f;
         }
         fontNameBox = font.getMetricBounds(fontName, font.getPixelSize(fontSizeFName, dpiH));
index 6a1f60d..fbb29d6 100644 (file)
@@ -8,6 +8,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import javax.media.nativewindow.util.Dimension;
 import javax.media.opengl.GL;
 import javax.media.opengl.GL2ES2;
 import javax.media.opengl.GLAnimatorControl;
@@ -86,7 +87,7 @@ public class GPUUISceneGLListener0A implements GLEventListener {
      * @see #GPUUISceneGLListener0A(float)
      * @see #GPUUISceneGLListener0A(float, boolean, boolean)
      */
-    public static final float DefaultNoAADPIThreshold = 180f;
+    public static final float DefaultNoAADPIThreshold = 200f;
 
     private int currentText = 0;
 
@@ -624,12 +625,16 @@ public class GPUUISceneGLListener0A implements GLEventListener {
     public void init(GLAutoDrawable drawable) {
         final Object upObj = drawable.getUpstreamWidget();
         if( upObj instanceof Window ) {
-            final float[] pixelsPerMM = new float[2];
-            final MonitorDevice mm = ((Window)upObj).getMainMonitor();
-            mm.getPixelsPerMM(pixelsPerMM);
-            dpiH = pixelsPerMM[1]*25.4f;
+            final Window upWin = (Window)upObj;
+            final MonitorDevice mm = upWin.getMainMonitor();
+            final float[] monitorPixelsPerMM = mm.getPixelsPerMM(new float[2]);
+            final float monitorDpiH = monitorPixelsPerMM[1]*25.4f;
+            final float[] surfacePixelsPerMM = upWin.getPixelsPerMM(new float[2]);
+            dpiH = surfacePixelsPerMM[1]*25.4f;
             System.err.println("Monitor detected: "+mm);
-            System.err.println("Using monitor's DPI of "+(pixelsPerMM[0]*25.4f)+" x "+dpiH+" -> "+dpiH);
+            System.err.println("Monitor dpi: "+monitorDpiH);
+            System.err.println("Surface scale: native "+new Dimension(upWin.getNativeSurfaceScale(new int[2]))+", current "+new Dimension(upWin.getCurrentSurfaceScale(new int[2])));
+            System.err.println("Surface dpi: "+dpiH);
         } else {
             System.err.println("Using default DPI of "+dpiH);
         }
@@ -818,7 +823,6 @@ public class GPUUISceneGLListener0A implements GLEventListener {
 
         final float dz = 0f;
         final float dyTop = dh * relTop;
-        final float dxMiddle = dw * relMiddle;
         final float dxLeft = dw * relLeft;
         final float dxRight = dw;
 
index a80b708..011b20c 100644 (file)
@@ -4,6 +4,7 @@ import java.awt.Component;
 import java.awt.Frame;
 import java.lang.reflect.InvocationTargetException;
 
+import javax.media.nativewindow.ScalableSurface;
 import javax.media.nativewindow.util.Dimension;
 import javax.media.nativewindow.util.DimensionImmutable;
 import javax.media.opengl.GLCapabilities;
@@ -29,6 +30,8 @@ public class GPUUISceneNewtCanvasAWTDemo {
     static boolean GraphMSAAMode = false;
     static float GraphAutoMode = GPUUISceneGLListener0A.DefaultNoAADPIThreshold;
 
+    static int[] reqSurfacePixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+
     static void setComponentSize(final Component comp, final DimensionImmutable new_sz) {
         try {
             javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
@@ -80,6 +83,11 @@ public class GPUUISceneNewtCanvasAWTDemo {
                 } else if(args[i].equals("-y")) {
                     i++;
                     y = MiscUtils.atoi(args[i], y);
+                } else if(args[i].equals("-pixelScale")) {
+                    i++;
+                    final int pS = MiscUtils.atoi(args[i], reqSurfacePixelScale[0]);
+                    reqSurfacePixelScale[0] = pS;
+                    reqSurfacePixelScale[1] = pS;
                 }
             }
         }
@@ -114,6 +122,8 @@ public class GPUUISceneNewtCanvasAWTDemo {
         window.setPosition(x, y);
         window.setSize(width, height);
         window.setTitle("GraphUI Newt Demo: graph["+Region.getRenderModeString(rmode)+"], msaa "+SceneMSAASamples);
+        window.setSurfaceScale(reqSurfacePixelScale);
+        final int[] valReqSurfacePixelScale = window.getRequestedSurfaceScale(new int[2]);
 
         GPUUISceneGLListener0A sceneGLListener = 0 < GraphAutoMode ? new GPUUISceneGLListener0A(GraphAutoMode, DEBUG, TRACE) :
                                                                      new GPUUISceneGLListener0A(rmode, DEBUG, TRACE);
@@ -142,6 +152,10 @@ public class GPUUISceneNewtCanvasAWTDemo {
                frame.setVisible(true);
            }
         });
+        final int[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new int[2]);
+        System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+
+                           valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+
+                           hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)");
         animator.start();
     }
 }
index 3e78360..f2fdcb3 100644 (file)
@@ -122,7 +122,10 @@ public class TestGearsES2NEWT extends UITestCase {
 
     private void setTitle(final Window win, final GLCapabilitiesImmutable caps) {
         final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl";
-        win.setTitle("GLWindow["+capsA+"], swapI "+swapInterval+", win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight());
+        final float[] sDPI = win.getPixelsPerMM(new float[2]);
+        sDPI[0] *= 25.4f;
+        sDPI[1] *= 25.4f;
+        win.setTitle("GLWindow["+capsA+"], swapI "+swapInterval+", win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]);
     }
     protected void runTestGL(final GLCapabilitiesImmutable caps, boolean undecorated) throws InterruptedException {
         System.err.println("requested: vsync "+swapInterval+", "+caps);
@@ -141,7 +144,6 @@ public class TestGearsES2NEWT extends UITestCase {
         glWindow.setFullscreen(fullscreen);
         glWindow.setPointerVisible(mouseVisible);
         glWindow.confinePointer(mouseConfined);
-        setTitle(glWindow, caps);
 
         final GearsES2 demo = new GearsES2(swapInterval);
         demo.setPMVUseBackingArray(pmvUseBackingArray);
index 694efea..08c81c5 100644 (file)
@@ -181,7 +181,10 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
             final java.awt.Rectangle b = glc.getBounds();
             frame.setTitle("NewtCanvasAWT["+capsA+"], swapI "+swapInterval+", win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getNativeWindow().getSurfaceWidth()+"x"+glc.getNativeWindow().getSurfaceHeight());
         }
-        win.setTitle("GLWindow["+capsA+"], swapI "+swapInterval+", win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight());
+        final float[] sDPI = win.getPixelsPerMM(new float[2]);
+        sDPI[0] *= 25.4f;
+        sDPI[1] *= 25.4f;
+        win.setTitle("GLWindow["+capsA+"], swapI "+swapInterval+", win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]);
     }
 
     // public enum ResizeBy { GLWindow, Component, Frame };
index 0384765..b9d77ac 100644 (file)
 package com.jogamp.opengl.test.junit.jogl.glsl;
 
 import com.jogamp.common.nio.Buffers;
-import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.KeyAdapter;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.opengl.GLWindow;
 import com.jogamp.opengl.util.GLArrayDataServer;
 import com.jogamp.opengl.util.PMVMatrix;
 import com.jogamp.opengl.util.glsl.ShaderCode;
@@ -36,16 +39,18 @@ import com.jogamp.opengl.util.glsl.ShaderProgram;
 import com.jogamp.opengl.util.glsl.ShaderState;
 import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2;
 import com.jogamp.opengl.test.junit.util.MiscUtils;
-import com.jogamp.opengl.test.junit.util.NEWTGLContext;
 import com.jogamp.opengl.test.junit.util.UITestCase;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.nio.FloatBuffer;
 
+import javax.media.nativewindow.ScalableSurface;
 import javax.media.opengl.GL;
 import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
 import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLEventListener;
 import javax.media.opengl.GLProfile;
 import javax.media.opengl.GLUniformData;
 
@@ -56,120 +61,178 @@ import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class TestRulerNEWT01 extends UITestCase {
-    static long durationPerTest = 10; // ms
+    static long durationPerTest = 500; // ms
+    static int[] reqSurfacePixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+    static boolean manualTest = false;
 
-    @Test
-    public void test01() throws InterruptedException {
-        long t0 = System.nanoTime();
-        GLProfile.initSingleton();
-        long t1 = System.nanoTime();
-        // preset ..
-        final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow(
-                new GLCapabilities(GLProfile.getGL2ES2()), 640, 480, true);
-        final GLDrawable drawable = winctx.context.getGLDrawable();
-        final GL2ES2 gl = winctx.context.getGL().getGL2ES2();
-        System.err.println(winctx.context);
-
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-        // test code ..
-        final ShaderState st = new ShaderState();
-
-        final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, RedSquareES2.class, "shader",
-                "shader/bin", "default", true);
-        final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, RedSquareES2.class, "shader",
-                "shader/bin", "ruler", true);
-        vp0.defaultShaderCustomization(gl, true, true);
-        fp0.defaultShaderCustomization(gl, true, true);
-
-        final ShaderProgram sp0 = new ShaderProgram();
-        sp0.add(gl, vp0, System.err);
-        sp0.add(gl, fp0, System.err);
-        Assert.assertTrue(0 != sp0.program());
-        Assert.assertTrue(!sp0.inUse());
-        Assert.assertTrue(!sp0.linked());
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
-        st.attachShaderProgram(gl, sp0, true);
-
-        final PMVMatrix pmvMatrix = new PMVMatrix();
-        final GLUniformData pmvMatrixUniform = new GLUniformData("gcu_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-        st.ownUniform(pmvMatrixUniform);
-        st.uniform(gl, pmvMatrixUniform);
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
-        final GLUniformData rulerColor= new GLUniformData("gcu_RulerColor", 3, Buffers.newDirectFloatBuffer(3));
-        final FloatBuffer rulerColorV = (FloatBuffer) rulerColor.getBuffer();
-        rulerColorV.put(0, 0.5f);
-        rulerColorV.put(1, 0.5f);
-        rulerColorV.put(2, 0.5f);
-        st.ownUniform(rulerColor);
-        st.uniform(gl, rulerColor);
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
-        Assert.assertNotNull(winctx);
-        Assert.assertNotNull(winctx.window);
-        Assert.assertNotNull(winctx.window.getScreen());
-        final float[] ppmmStore = { 0f, 0f };
-        {
-            final MonitorDevice monitor = winctx.window.getMainMonitor();
-            Assert.assertNotNull(monitor);
-            System.err.println(monitor);
-            monitor.getPixelsPerMM(ppmmStore);
-        }
-        final GLUniformData rulerPixFreq = new GLUniformData("gcu_RulerPixFreq", 2, Buffers.newDirectFloatBuffer(2));
-        final FloatBuffer rulerPixFreqV = (FloatBuffer) rulerPixFreq.getBuffer();
-        rulerPixFreqV.put(0, ppmmStore[0] * 10.0f);
-        rulerPixFreqV.put(1, ppmmStore[1] * 10.0f);
-        st.ownUniform(rulerPixFreq);
-        st.uniform(gl, rulerPixFreq);
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-        System.err.println("Screen pixel/cm "+rulerPixFreqV.get(0)+", "+rulerPixFreqV.get(1));
-
-        final GLArrayDataServer vertices0 = GLArrayDataServer.createGLSL("gca_Vertices", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
-        vertices0.putf(0); vertices0.putf(1);  vertices0.putf(0);
-        vertices0.putf(1);  vertices0.putf(1);  vertices0.putf(0);
-        vertices0.putf(0); vertices0.putf(0); vertices0.putf(0);
-        vertices0.putf(1);  vertices0.putf(0); vertices0.putf(0);
-        vertices0.seal(gl, true);
-        st.ownAttribute(vertices0, true);
-
-        // misc GL setup
-        gl.glClearColor(1, 1, 1, 1);
-        gl.glEnable(GL2ES2.GL_DEPTH_TEST);
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
-        // reshape
-        pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION);
-        pmvMatrix.glLoadIdentity();
-        pmvMatrix.glOrthof(0f, 1f, 0f, 1f, -10f, 10f);
-        // pmvMatrix.gluPerspective(45.0F, (float) drawable.getWidth() / (float) drawable.getHeight(), 1.0F, 100.0F);
-        pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW);
-        pmvMatrix.glLoadIdentity();
-        // pmvMatrix.glTranslatef(0, 0, -6);
-        // pmvMatrix.glRotatef(45f, 1f, 0f, 0f);
-        st.uniform(gl, pmvMatrixUniform);
-        gl.glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
-        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
-        for(int i=0; i<10; i++) {
-            vertices0.enableBuffer(gl, true);
-            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
-            gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
-            vertices0.enableBuffer(gl, false);
-            drawable.swapBuffers();
-            Thread.sleep(durationPerTest/10);
-        }
+    private void setTitle(final Window win) {
+        final float[] sDPI = win.getPixelsPerMM(new float[2]);
+        sDPI[0] *= 25.4f;
+        sDPI[1] *= 25.4f;
+        win.setTitle("GLWindow: win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]);
+    }
+
+    private void runTestGL() throws InterruptedException {
+        final GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getGL2ES2()));
+        Assert.assertNotNull(glWindow);
+        glWindow.setSurfaceScale(reqSurfacePixelScale);
+        final int[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new int[2]);
+        glWindow.setSize(640, 480);
+
+        glWindow.addGLEventListener(new GLEventListener() {
+            final ShaderState st = new ShaderState();
+            final PMVMatrix pmvMatrix = new PMVMatrix();
+            final GLUniformData pmvMatrixUniform = new GLUniformData("gcu_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
+            final GLArrayDataServer vertices0 = GLArrayDataServer.createGLSL("gca_Vertices", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
+            final GLUniformData rulerPixFreq = new GLUniformData("gcu_RulerPixFreq", 2, Buffers.newDirectFloatBuffer(2));
+
+            @Override
+            public void init(GLAutoDrawable drawable) {
+                final GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+
+                final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, RedSquareES2.class, "shader",
+                        "shader/bin", "default", true);
+                final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, RedSquareES2.class, "shader",
+                        "shader/bin", "ruler", true);
+                vp0.defaultShaderCustomization(gl, true, true);
+                fp0.defaultShaderCustomization(gl, true, true);
+
+                final ShaderProgram sp0 = new ShaderProgram();
+                sp0.add(gl, vp0, System.err);
+                sp0.add(gl, fp0, System.err);
+                Assert.assertTrue(0 != sp0.program());
+                Assert.assertTrue(!sp0.inUse());
+                Assert.assertTrue(!sp0.linked());
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+
+                st.attachShaderProgram(gl, sp0, true);
+
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+                st.ownUniform(pmvMatrixUniform);
+                st.uniform(gl, pmvMatrixUniform);
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+
+                final GLUniformData rulerColor= new GLUniformData("gcu_RulerColor", 3, Buffers.newDirectFloatBuffer(3));
+                final FloatBuffer rulerColorV = (FloatBuffer) rulerColor.getBuffer();
+                rulerColorV.put(0, 0.5f);
+                rulerColorV.put(1, 0.5f);
+                rulerColorV.put(2, 0.5f);
+                st.ownUniform(rulerColor);
+                st.uniform(gl, rulerColor);
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+
+                st.ownUniform(rulerPixFreq);
+
+                vertices0.putf(0); vertices0.putf(1);  vertices0.putf(0);
+                vertices0.putf(1);  vertices0.putf(1);  vertices0.putf(0);
+                vertices0.putf(0); vertices0.putf(0); vertices0.putf(0);
+                vertices0.putf(1);  vertices0.putf(0); vertices0.putf(0);
+                vertices0.seal(gl, true);
+                st.ownAttribute(vertices0, true);
+
+                // misc GL setup
+                gl.glClearColor(1, 1, 1, 1);
+                gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+                Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
+            }
 
-        long t2 = System.nanoTime();
+            @Override
+            public void dispose(GLAutoDrawable drawable) {
+            }
+
+            @Override
+            public void display(GLAutoDrawable drawable) {
+                final GL2ES2 gl = drawable.getGL().getGL2ES2();
+                vertices0.enableBuffer(gl, true);
+                gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+                gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
+                vertices0.enableBuffer(gl, false);
+            }
+
+            @Override
+            public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+                final GL2ES2 gl = drawable.getGL().getGL2ES2();
+                pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION);
+                pmvMatrix.glLoadIdentity();
+                pmvMatrix.glOrthof(0f, 1f, 0f, 1f, -10f, 10f);
+                // pmvMatrix.gluPerspective(45.0F, (float) drawable.getWidth() / (float) drawable.getHeight(), 1.0F, 100.0F);
+                pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW);
+                pmvMatrix.glLoadIdentity();
+                // pmvMatrix.glTranslatef(0, 0, -6);
+                // pmvMatrix.glRotatef(45f, 1f, 0f, 0f);
+                st.uniform(gl, pmvMatrixUniform);
+
+                final float[] ppmmStore = glWindow.getPixelsPerMM(new float[2]);
+                final FloatBuffer rulerPixFreqV = (FloatBuffer) rulerPixFreq.getBuffer();
+                rulerPixFreqV.put(0, ppmmStore[0] * 10.0f);
+                rulerPixFreqV.put(1, ppmmStore[1] * 10.0f);
+                st.uniform(gl, rulerPixFreq);
+                System.err.println("Screen pixel/cm "+rulerPixFreqV.get(0)+", "+rulerPixFreqV.get(1));
+            }
+
+        });
+        final SnapshotGLEventListener snap = new SnapshotGLEventListener();
+        glWindow.addGLEventListener(snap);
+        glWindow.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(final KeyEvent e) {
+                if( e.isAutoRepeat() ) {
+                    return;
+                }
+                if(e.getKeyChar()=='x') {
+                    final int[] hadSurfacePixelScale = glWindow.getCurrentSurfaceScale(new int[2]);
+                    final int[] reqSurfacePixelScale;
+                    if( hadSurfacePixelScale[0] == ScalableSurface.IDENTITY_PIXELSCALE ) {
+                        reqSurfacePixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+                    } else {
+                        reqSurfacePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+                    }
+                    System.err.println("[set PixelScale pre]: had "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" -> req "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]);
+                    snap.setMakeSnapshot();
+                    glWindow.setSurfaceScale(reqSurfacePixelScale);
+                    final int[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new int[2]);
+                    final int[] hasSurfacePixelScale = glWindow.getCurrentSurfaceScale(new int[2]);
+                    final int[] nativeSurfacePixelScale = glWindow.getNativeSurfaceScale(new int[2]);
+                    System.err.println("[set PixelScale post]: "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" (had) -> "+
+                                       reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+
+                                       valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+
+                                       hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+" (has), "+
+                                       nativeSurfacePixelScale[0]+"x"+nativeSurfacePixelScale[1]+" (native)");
+                    setTitle(glWindow);
+                }
+            }
+        });
+
+        glWindow.setVisible(true);
 
-        NEWTGLContext.destroyWindow(winctx);
+        final int[] hasSurfacePixelScale1 = glWindow.getCurrentSurfaceScale(new int[2]);
+        System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+
+                           valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+
+                           hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)");
+        setTitle(glWindow);
 
-        long t3 = System.nanoTime();
+        snap.setMakeSnapshot();
+        glWindow.display();
 
-        System.err.println("t1-t0: "+ (t1-t0)/1e6 +"ms");
-        System.err.println("t3-t0: "+ (t3-t0)/1e6 +"ms");
-        System.err.println("t3-t2: "+ (t3-t2)/1e6 +"ms");
+        Thread.sleep(durationPerTest);
+
+        glWindow.destroy();
+
+    }
+
+    @Test
+    public void test01_PSA() throws InterruptedException {
+        runTestGL();
+    }
+
+    @Test
+    public void test99_PS1() throws InterruptedException, InvocationTargetException {
+        if(manualTest) return;
+        reqSurfacePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+        reqSurfacePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+        runTestGL();
     }
 
     public static void main(String args[]) throws IOException {
@@ -177,6 +240,13 @@ public class TestRulerNEWT01 extends UITestCase {
         for(int i=0; i<args.length; i++) {
             if(args[i].equals("-time")) {
                 durationPerTest = MiscUtils.atoi(args[++i], (int)durationPerTest);
+            } else if(args[i].equals("-pixelScale")) {
+                i++;
+                final int pS = MiscUtils.atoi(args[i], reqSurfacePixelScale[0]);
+                reqSurfacePixelScale[0] = pS;
+                reqSurfacePixelScale[1] = pS;
+            } else if(args[i].equals("-manual")) {
+                manualTest = true;
             }
         }
         String tstname = TestRulerNEWT01.class.getName();
http://JogAmp.org git info: FAQ, tutorial and man pages.