From 6516a52d3da5cced924db63b64af911d55355325 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Tue, 27 Jan 2015 00:49:51 +0100
Subject: Bug 1120 - Refine HiDPI Support ( Part-2 ) (API CHANGE)

- Use float[2] for pixel-scale.
  Utilize simple integer rounding:
    int-pixel-units = (int) ( int-window-units * pixel-scale + 0.5f )

- Provide minimum and maximum allowed pixel-scale values
  to be set by platform, supporting generic pixel-scale validation.

- Remove 'OSXUtil.GetPixelScale(final RectangleImmutable r, final int[] screenIndexOut)',
  implementation for all platforms would cause huge redundancy of
  Screen and MonitorDevice code (duplication of NEWT).

- instead, add 'float[2] pixelScale' to NEWT's MonitorDevice

- Detect change of pixel-scale and propagate accordingly.
  This allows GLCanvas, GLJPanel and NewtCanvasAWT instances
  to be dragged between monitor devices w/ different pixel-scale.

- OSX: Handle native triggered reshape events off-thread to avoid EDT congestion
       due to locked window when consuming deferred events on EDT.
---
 .../jogamp/nativewindow/SurfaceScaleUtils.java     | 233 +++++++++++----------
 .../jogamp/nativewindow/WrappedSurface.java        |  33 +--
 .../classes/jogamp/nativewindow/jawt/JAWTUtil.java |  67 ++++--
 .../nativewindow/jawt/macosx/MacOSXJAWTWindow.java |  13 +-
 .../jogamp/nativewindow/macosx/OSXUtil.java        |  66 +-----
 5 files changed, 212 insertions(+), 200 deletions(-)

(limited to 'src/nativewindow/classes/jogamp')

diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java
index 73413cf59..70eec7b24 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java
@@ -27,7 +27,6 @@
  */
 package jogamp.nativewindow;
 
-import javax.media.nativewindow.NativeWindowFactory;
 import javax.media.nativewindow.ScalableSurface;
 
 /**
@@ -35,138 +34,162 @@ import javax.media.nativewindow.ScalableSurface;
  */
 public class SurfaceScaleUtils {
 
-    private static final int[] PlatformMaxPixelScale;
-    private static final boolean PlatformUniformPixelScale;
-    private static final boolean PlatformPixelScaleSupported;
+    private static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
 
-    static {
-      if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true) ) {
-          PlatformMaxPixelScale = new int[] { jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE, jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE };
-          PlatformUniformPixelScale = true;
-          PlatformPixelScaleSupported = true;
-      } else {
-          PlatformMaxPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
-          PlatformUniformPixelScale = false;
-          PlatformPixelScaleSupported = false;
-      }
+    private static boolean isZero(final float a) {
+        return Math.abs(a) < EPSILON;
     }
 
     /**
-     * Compute a new valid pixelScale to be used by {@link NativeSurface} implementations,
-     * based on the given request and surface's pixelScale
+     * Returns integer rounded product, i.e. {@code (int) ( a * pixelScale + 0.5f )}
      *
-     * @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 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
+     * @param a the int value
+     * @param pixelScale the float scale factor
+     * @return the integer rounded product
      */
-    public static boolean computePixelScale(final 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] = newPixelScaleSafeX;
-            result[1] = newPixelScaleSafeY;
-        } else {
-            result[0] = ScalableSurface.IDENTITY_PIXELSCALE;
-            result[1] = ScalableSurface.IDENTITY_PIXELSCALE;
-        }
-
-        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;
+    public static int scale(final int a, final float pixelScale) {
+        return (int) ( a * pixelScale + 0.5f );
     }
 
     /**
-     * Validate the given requested pixelScale value pair, i.e. clip it to the
-     * limits of {@link ScalableSurface#AUTOMAX_PIXELSCALE} and {@link #getPlatformMaxPixelScale(int[])}
-     * <p>
-     * To be used by {@link ScalableSurface#setSurfaceScale(int[])} implementations.
-     * </p>
+     * Returns integer rounded product, i.e. {@code (int) ( a / pixelScale + 0.5f )}
      *
-     * @param result int[2] storage for result
-     * @param reqPixelScale requested pixelScale
-     * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix
+     * @param a the int value
+     * @param pixelScale the float scale factor
+     * @return the integer rounded product
      */
-    public static void validateReqPixelScale(final int[] result, final int[] reqPixelScale, final String DEBUG_PREFIX) {
-        final int minPS = Math.min(reqPixelScale[0], reqPixelScale[1]);
-        if( ScalableSurface.AUTOMAX_PIXELSCALE >= minPS ) {
-            result[0] = ScalableSurface.AUTOMAX_PIXELSCALE;
-            result[1] = ScalableSurface.AUTOMAX_PIXELSCALE;
-        } else if( PlatformUniformPixelScale ) {
-            final int maxPS = Math.max(reqPixelScale[0], reqPixelScale[1]);
-            if( maxPS >= PlatformMaxPixelScale[0] ) {
-                result[0] = PlatformMaxPixelScale[0];
-                result[1] = PlatformMaxPixelScale[1];
-            } else {
-                result[0] = maxPS;
-                result[1] = maxPS;
-            }
-        } else {
-            if( reqPixelScale[0] >= PlatformMaxPixelScale[0] ) {
-                result[0] = PlatformMaxPixelScale[0];
-            } else {
-                result[0] = reqPixelScale[0];
-            }
-            if( reqPixelScale[1] >= PlatformMaxPixelScale[1] ) {
-                result[1] = PlatformMaxPixelScale[1];
-            } else {
-                result[1] = reqPixelScale[1];
-            }
-        }
-        if( null != DEBUG_PREFIX ) {
-            System.err.println(DEBUG_PREFIX+".validateReqPixelScale: ["+reqPixelScale[0]+"x"+reqPixelScale[1]+" (req), "+
-                    PlatformMaxPixelScale[0]+"x"+PlatformMaxPixelScale[1]+" (max)] -> "+
-                    result[0]+"x"+result[1]+" (valid)");
-        }
+    public static int scaleInv(final int a, final float pixelScale) {
+        return (int) ( a / pixelScale + 0.5f );
     }
 
     /**
-     * Replaces {@link ScalableSurface#AUTOMAX_PIXELSCALE} with {@link #getPlatformMaxPixelScale(int[])},
-     * for each component.
+     * Returns integer rounded product, i.e. {@code (int) ( a * pixelScale + 0.5f )}
      *
-     * @param pixelScale int[2] value array to be tested and replaced
+     * @param result the int[2] result, may be {@code a} for in-place operation
+     * @param a the int[2] values
+     * @param pixelScale the float[2] scale factors
+     * @return the result for chaining
      */
-    public static void replaceAutoMaxWithPlatformMax(final int[] pixelScale) {
-        if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[0] ) {
-            pixelScale[0] = PlatformMaxPixelScale[0];
-        }
-        if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[1] ) {
-            pixelScale[1] = PlatformMaxPixelScale[1];
-        }
+    public static int[] scale(final int[] result, final int[] a, final float[] pixelScale) {
+        result[0] = (int) ( a[0] * pixelScale[0] + 0.5f );
+        result[1] = (int) ( a[1] * pixelScale[1] + 0.5f );
+        return result;
     }
-
     /**
-     * Returns the maximum platform pixelScale
+     * Returns integer rounded product, i.e. {@code (int) ( a / pixelScale + 0.5f )}
+     *
+     * @param result the int[2] result, may be {@code a} for in-place operation
+     * @param a the int[2] values
+     * @param pixelScale the float[2] scale factors
+     * @return the result for chaining
      */
-    public static int[] getPlatformMaxPixelScale(final int[] result) {
-        System.arraycopy(PlatformMaxPixelScale, 0, result, 0, 2);
+    public static int[] scaleInv(final int[] result, final int[] a, final float[] pixelScale) {
+        result[0] = (int) ( a[0] / pixelScale[0] + 0.5f );
+        result[1] = (int) ( a[1] / pixelScale[1] + 0.5f );
         return result;
     }
 
     /**
-     * Returns true if platform pixelScale is uniform, i.e. same scale factor for x- and y-direction, otherwise false.
+     * Method constrains the given pixel-scale within ]0..{@code maxPixelScale}], as described below.
+     * <p>
+     * Method returns {@link ScalableSurface#IDENTITY_PIXELSCALE IDENTITY_PIXELSCALE} if:
+     * <ul>
+     *   <li>{@code pixelScale} ~= {@link ScalableSurface#IDENTITY_PIXELSCALE IDENTITY_PIXELSCALE}</li>
+     * </ul>
+     * </p>
+     * <p>
+     * Method returns {@code maxPixelScale} if
+     * <ul>
+     *   <li>{@code pixelScale} ~= {@link ScalableSurface#AUTOMAX_PIXELSCALE AUTOMAX_PIXELSCALE}</li>
+     *   <li>{@code pixelScale} &gt; {@code maxPixelScale}</li>
+     *   <li>{@code pixelScale} ~= {@code maxPixelScale}</li>
+     * </ul>
+     * </p>
+     * <p>
+     * Method returns {@code minPixelScale} if
+     * <ul>
+     *   <li>{@code pixelScale} &lt; {@code minPixelScale}</li>
+     *   <li>{@code pixelScale} ~= {@code minPixelScale}</li>
+     * </ul>
+     * </p>
+     * <p>
+     * Otherwise method returns the given {@code pixelScale}.
+     * </p>
+     * <p>
+     * <i>~=</i> denominates a delta &le; {@link FloatUtil#EPSILON}.
+     * </p>
+     * @param pixelScale pixel-scale to be constrained
+     * @param minPixelScale minimum pixel-scale
+     * @param maxPixelScale maximum pixel-scale
+     * @return the constrained pixel-scale
      */
-    public static boolean isPlatformPixelScaleUniform() {
-        return PlatformUniformPixelScale;
+    public static float clampPixelScale(final float pixelScale, final float minPixelScale, final float maxPixelScale) {
+        if( isZero(pixelScale-ScalableSurface.IDENTITY_PIXELSCALE) ) {
+            return ScalableSurface.IDENTITY_PIXELSCALE;
+        } else if( isZero(pixelScale-ScalableSurface.AUTOMAX_PIXELSCALE) ||
+                   pixelScale > maxPixelScale ||
+                   isZero(pixelScale-maxPixelScale)
+                 )
+        {
+            return maxPixelScale;
+        } else if( pixelScale < minPixelScale || isZero(pixelScale-minPixelScale) )
+        {
+            return minPixelScale;
+        } else {
+            return pixelScale;
+        }
     }
 
     /**
-     * Returns whether the platform supports pixelScale
+     * Method {@link #clampPixelScale(float, float, float) constrains} the given float[2] pixel-scale
+     * within ]0..{@code maxPixelScale}], as described in {@link #clampPixelScale(float, float, float)}.
+     *
+     * @param result float[2] storage for result, maybe same as <code>s</code> for in-place
+     * @param pixelScale float[2] pixelScale to be constrained
+     * @param minPixelScale float[2] minimum pixel-scale
+     * @param maxPixelScale float[2] maximum pixel-scale
+     * @return the constrained result for chaining
      */
-    public static boolean isPlatformPixelScaleSupported() {
-        return PlatformPixelScaleSupported;
+    public static float[] clampPixelScale(final float[] result, final float[] pixelScale,
+                                          final float[] minPixelScale, final float[] maxPixelScale) {
+        result[0] = clampPixelScale(pixelScale[0], minPixelScale[0], maxPixelScale[0]);
+        result[1] = clampPixelScale(pixelScale[1], minPixelScale[1], maxPixelScale[1]);
+        return result;
     }
 
+    /**
+     * Method writes the given float[2] requested pixel-scale {@code reqPixelScale}
+     * into {@code result} within its constraints ]0..{@code maxPixelScale}], as described in {@link #clampPixelScale(float, float, float)}.
+     * <p>
+     * Method only differs from {@link #clampPixelScale(float[], float[], float[], float[])}
+     * by returning the whether the value has changed, i.e. different from the given {@code prePixelScale}.
+     * </p>
+     *
+     * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place
+     * @param prePixelScale float[2] previous pixel-scale
+     * @param reqPixelScale float[2] requested pixel-scale, validated via {@link #validateReqPixelScale(float[], float[], String)}.
+     * @param minPixelScale float[2] minimum pixel-scale
+     * @param maxPixelScale float[2] maximum pixel-scale
+     * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix
+     * @param newPixelScaleRaw new raw surface pixel-scale
+     * @return {@code true} if pixel-scale has changed, otherwise {@code false}.
+     */
+    public static boolean setNewPixelScale(final float[] result,
+                                           final float[] prePixelScale, final float[] reqPixelScale,
+                                           final float[] minPixelScale, final float[] maxPixelScale,
+                                           final String DEBUG_PREFIX) {
+        final float resultX = clampPixelScale(reqPixelScale[0], minPixelScale[0], maxPixelScale[0]);
+        final float resultY = clampPixelScale(reqPixelScale[1], minPixelScale[1], maxPixelScale[1]);
+        final boolean changed = resultX != prePixelScale[0] || resultY != prePixelScale[1];
+        if( null != DEBUG_PREFIX ) {
+            System.err.println(DEBUG_PREFIX+".setNewPixelScale: pre["+prePixelScale[0]+", "+prePixelScale[1]+"], req["+
+                    reqPixelScale[0]+", "+reqPixelScale[1]+"], min["+
+                    minPixelScale[0]+", "+minPixelScale[1]+"], max["+
+                    maxPixelScale[0]+", "+maxPixelScale[1]+"] -> result["+
+                    resultX+", "+resultY+"], changed "+changed);
+        }
+        result[0] = resultX;
+        result[1] = resultY;
+        return changed;
+    }
 }
diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
index d3439b53f..cfcca7d05 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
@@ -42,7 +42,7 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
  * @see ProxySurface
  */
 public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface {
-  private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+  private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
   private long surfaceHandle;
 
   /**
@@ -104,27 +104,23 @@ public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface
   /**
    * {@inheritDoc}
    * <p>
-   * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly.
+   * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(float[]) given pixelScale} directly.
    * </p>
    */
   @Override
   public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
-      pixelUnitsAndResult[0] /= hasPixelScale[0];
-      pixelUnitsAndResult[1] /= hasPixelScale[1];
-      return pixelUnitsAndResult;
+      return SurfaceScaleUtils.scaleInv(pixelUnitsAndResult, pixelUnitsAndResult, hasPixelScale);
   }
 
   /**
    * {@inheritDoc}
    * <p>
-   * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly.
+   * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(float[]) given pixelScale} directly.
    * </p>
    */
   @Override
   public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
-      windowUnitsAndResult[0] *= hasPixelScale[0];
-      windowUnitsAndResult[1] *= hasPixelScale[1];
-      return windowUnitsAndResult;
+      return SurfaceScaleUtils.scale(windowUnitsAndResult, windowUnitsAndResult, hasPixelScale);
   }
 
   /**
@@ -147,25 +143,32 @@ public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface
    * </p>
    */
   @Override
-  public final void setSurfaceScale(final int[] pixelScale) {
-      hasPixelScale[0] = pixelScale[0];
-      hasPixelScale[1] = pixelScale[1];
+  public final boolean setSurfaceScale(final float[] pixelScale) {
+      final boolean changed = hasPixelScale[0] != pixelScale[0] || hasPixelScale[1] != pixelScale[1];
+      System.arraycopy(pixelScale, 0, hasPixelScale, 0, 2);
+      return changed;
   }
 
   @Override
-  public final int[] getRequestedSurfaceScale(final int[] result) {
+  public final float[] getRequestedSurfaceScale(final float[] result) {
       System.arraycopy(hasPixelScale, 0, result, 0, 2);
       return result;
   }
 
   @Override
-  public final int[] getCurrentSurfaceScale(final int[] result) {
+  public final float[] getCurrentSurfaceScale(final float[] result) {
       System.arraycopy(hasPixelScale, 0, result, 0, 2);
       return result;
   }
 
   @Override
-  public final int[] getNativeSurfaceScale(final int[] result) {
+  public float[] getMinimumSurfaceScale(final float[] result) {
+      System.arraycopy(hasPixelScale, 0, result, 0, 2);
+      return result;
+  }
+
+  @Override
+  public final float[] getMaximumSurfaceScale(final float[] result) {
       System.arraycopy(hasPixelScale, 0, result, 0, 2);
       return result;
   }
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
index 231a89c26..4fd2b0dca 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
@@ -56,6 +56,7 @@ import javax.media.nativewindow.ToolkitLock;
 import jogamp.common.os.PlatformPropsImpl;
 import jogamp.nativewindow.Debug;
 import jogamp.nativewindow.NWJNILibLoader;
+import jogamp.nativewindow.macosx.OSXUtil;
 
 import com.jogamp.common.os.Platform;
 import com.jogamp.common.util.PropertyAccess;
@@ -93,6 +94,7 @@ public class JAWTUtil {
   private static final ToolkitLock jawtToolkitLock;
 
   private static final Method getScaleFactorMethod;
+  private static final Method getCGDisplayIDMethodOnOSX;
 
   private static class PrivilegedDataBlob1 {
     PrivilegedDataBlob1() {
@@ -101,6 +103,7 @@ public class JAWTUtil {
     Method sunToolkitAWTLockMethod;
     Method sunToolkitAWTUnlockMethod;
     Method getScaleFactorMethod;
+    Method getCGDisplayIDMethodOnOSX;
     boolean ok;
   }
 
@@ -321,6 +324,7 @@ public class JAWTUtil {
         hasSunToolkitAWTLock = false;
         // hasSunToolkitAWTLock = false;
         getScaleFactorMethod = null;
+        getCGDisplayIDMethodOnOSX = null;
     } else {
         // Non-headless case
         JAWTJNILibLoader.initSingleton(); // load libjawt.so
@@ -357,8 +361,13 @@ public class JAWTUtil {
                 }
                 try {
                     final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
-                    d.getScaleFactorMethod = gd.getClass().getDeclaredMethod("getScaleFactor");
+                    final Class<?> gdClass = gd.getClass();
+                    d.getScaleFactorMethod = gdClass.getDeclaredMethod("getScaleFactor");
                     d.getScaleFactorMethod.setAccessible(true);
+                    if( Platform.OSType.MACOS == PlatformPropsImpl.OS_TYPE ) {
+                        d.getCGDisplayIDMethodOnOSX = gdClass.getDeclaredMethod("getCGDisplayID");
+                        d.getCGDisplayIDMethodOnOSX.setAccessible(true);
+                    }
                 } catch (final Throwable t) {}
                 return d;
             }
@@ -366,6 +375,7 @@ public class JAWTUtil {
         sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod;
         sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod;
         getScaleFactorMethod = pdb1.getScaleFactorMethod;
+        getCGDisplayIDMethodOnOSX = pdb1.getCGDisplayIDMethodOnOSX;
 
         boolean _hasSunToolkitAWTLock = false;
         if ( pdb1.ok ) {
@@ -545,20 +555,46 @@ public class JAWTUtil {
    * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays
    * </p>
    * @param device the {@link GraphicsDevice} instance used to query the pixel scale
-   * @return the pixel scale factor
+   * @param minScale current and output min scale values
+   * @param maxScale current and output max scale values
+   * @return {@code true} if the given min and max scale values have changed, otherwise {@code false}.
    */
-  public static final int getPixelScale(final GraphicsDevice device) {
+  public static final boolean getPixelScale(final GraphicsDevice device, final float[] minScale, final float[] maxScale) {
+      // Shall we allow ]0..1[ minimum scale?
+      boolean changed = minScale[0] != 1f || minScale[1] != 1f;
+      minScale[0] = 1f;
+      minScale[1] = 1f;
+      float sx = 1f;
+      float sy = 1f;
       if( !SKIP_AWT_HIDPI ) {
+          if( null != getCGDisplayIDMethodOnOSX ) {
+              // OSX specific, preserving double type
+              try {
+                  final Object res = getCGDisplayIDMethodOnOSX.invoke(device);
+                  if (res instanceof Integer) {
+                      final int displayID = ((Integer)res).intValue();
+                      sx = (float) OSXUtil.GetPixelScaleByDisplayID(displayID);
+                      sy = sx;
+                  }
+              } catch (final Throwable t) {}
+          }
           if( null != getScaleFactorMethod ) {
+              // Generic (?)
               try {
                   final Object res = getScaleFactorMethod.invoke(device);
                   if (res instanceof Integer) {
-                      return ((Integer)res).intValue();
+                      sx = ((Integer)res).floatValue();
+                  } else if ( res instanceof Double) {
+                      sx = ((Double)res).floatValue();
                   }
+                  sy = sx;
               } catch (final Throwable t) {}
           }
       }
-      return 1;
+      changed = maxScale[0] != sx || maxScale[1] != sy;
+      maxScale[0] = sx;
+      maxScale[1] = sy;
+      return changed;
   }
 
   /**
@@ -574,20 +610,23 @@ public class JAWTUtil {
    * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays
    * </p>
    * @param gc the {@link GraphicsConfiguration} instance used to query the pixel scale
-   * @return the pixel scale factor
+   * @param minScale current and output min scale values
+   * @param maxScale current and output max scale values
+   * @return {@code true} if the given min and max scale values have changed, otherwise {@code false}.
    */
-  public static final int getPixelScale(final GraphicsConfiguration gc) {
+  public static final boolean getPixelScale(final GraphicsConfiguration gc, final float[] minScale, final float[] maxScale) {
       final GraphicsDevice device = null != gc ? gc.getDevice() : null;
-      final int ps;
+      boolean changed;
       if( null == device ) {
-          ps = 0;
+          changed = minScale[0] != 1f || minScale[1] != 1f || maxScale[0] != 1f || maxScale[1] != 1f;
+          minScale[0] = 1f;
+          minScale[1] = 1f;
+          maxScale[0] = 1f;
+          maxScale[1] = 1f;
       } else {
-          ps = JAWTUtil.getPixelScale(device);
-      }
-      if( DEBUG ) {
-          System.err.println("JAWTUtil.updatePixelScale: Fetched "+ps);
+          changed = JAWTUtil.getPixelScale(device, minScale, maxScale);
       }
-      return ps;
+      return changed;
   }
 }
 
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
index fae8db52a..1c6c41262 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
@@ -48,7 +48,6 @@ import java.security.PrivilegedAction;
 import javax.media.nativewindow.AbstractGraphicsConfiguration;
 import javax.media.nativewindow.Capabilities;
 import javax.media.nativewindow.NativeSurface;
-import javax.media.nativewindow.NativeWindow;
 import javax.media.nativewindow.NativeWindowException;
 import javax.media.nativewindow.MutableSurface;
 import javax.media.nativewindow.util.Point;
@@ -116,13 +115,10 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
   }
 
   @Override
-  public void setSurfaceScale(final int[] pixelScale) {
+  public boolean setSurfaceScale(final float[] pixelScale) {
       super.setSurfaceScale(pixelScale);
-      if( 0 != getWindowHandle() ) { // locked at least once !
-          final int hadPixelScaleX = getPixelScaleX();
-          updatePixelScale();
-
-          if( hadPixelScaleX != getPixelScaleX() && 0 != getAttachedSurfaceLayer() ) {
+      if( 0 != getWindowHandle() && setReqPixelScale() ) { // locked at least once _and_ updated pixel-scale
+          if( 0 != getAttachedSurfaceLayer() ) {
               OSXUtil.RunOnMainThread(false, false, new Runnable() {
                   @Override
                   public void run() {
@@ -133,6 +129,9 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
                   }
               });
           }
+          return true;
+      } else {
+          return false;
       }
   }
 
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index 9af74d9f5..7cd0439b7 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -31,8 +31,6 @@ import javax.media.nativewindow.NativeWindowException;
 import javax.media.nativewindow.NativeWindowFactory;
 import javax.media.nativewindow.util.Insets;
 import javax.media.nativewindow.util.Point;
-import javax.media.nativewindow.util.Rectangle;
-import javax.media.nativewindow.util.RectangleImmutable;
 
 import com.jogamp.common.util.Function;
 import com.jogamp.common.util.FunctionTask;
@@ -109,64 +107,14 @@ public class OSXUtil implements ToolkitProperties {
       return (Insets) GetInsets0(windowOrView);
     }
 
-    /**
-     * Returns the pixel-scale of the NSScreen, with the highest
-     * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of the given rectangle in window units.
-     * <p>
-     * If no coverage is detected the pixel-scale of the first NSScreen is returned.
-     * </p>
-     * @param r arbitrary rectangle in window units
-     * @param screenIndexOut storage returning the native screen index containing the given rectangle
-     */
-    public static double GetPixelScale(final RectangleImmutable r, final int[] screenIndexOut) {
-        if( DEBUG ) {
-            System.err.printf("GetPixelScale covering %s%n", r.toString());
-        }
-        final int screenCount;
-        final RectangleImmutable[] screenBounds;
-        final double[] pixelScales;
-        {
-            final double[] sd = GetScreenData0();
-            if( 0 != sd.length % 5 ) {
-                throw new InternalError("GetScreenData0 didn't return multiple of 5 but "+sd.length);
-            }
-            screenCount = sd.length / 5;
-            screenBounds = new RectangleImmutable[screenCount];
-            pixelScales = new double[screenCount] ;
-            for(int i=0; i<screenCount; i++) {
-                final int j = i*5;
-                pixelScales[i] = sd[j+0];
-                screenBounds[i] = new Rectangle((int)sd[j+1], (int)sd[j+2], (int)sd[j+3], (int)sd[j+4]);
-                if( DEBUG ) {
-                    System.err.printf("GetPixelScale.Screen[%d]: scale %f, bounds[%f / %f  %f x %f]%n",
-                            i, pixelScales[i], sd[j+1], sd[j+2], sd[j+3], sd[j+4]);
-                }
-            }
-        }
-        double pixelScale = pixelScales[0];
-        screenIndexOut[0] = 0;
-        float maxCoverage = Float.MIN_VALUE;
-        for(int i=screenCount-1; i>=0; i--) {
-            final RectangleImmutable sb = screenBounds[i];
-            final float coverage = sb.coverage(r);
-            if( coverage > maxCoverage ) {
-                maxCoverage = coverage;
-                screenIndexOut[0] = i;
-                pixelScale = pixelScales[i];
-            }
-        }
-        if( DEBUG ) {
-            System.err.printf("GetPixelScale Result: screen %d, scale %f%n%n", screenIndexOut[0], pixelScale);
-        }
-        return pixelScale;
-    }
-
-    public static double GetPixelScale(final int screenIndex) {
+    public static double GetPixelScaleByScreenIdx(final int screenIndex) {
       return GetPixelScale0(screenIndex);
     }
-
+    public static double GetPixelScaleByDisplayID(final int displayID) {
+      return GetPixelScale1(displayID);
+    }
     public static double GetPixelScale(final long windowOrView) {
-      return GetPixelScale1(windowOrView);
+      return GetPixelScale2(windowOrView);
     }
 
     public static long CreateNSWindow(final int x, final int y, final int width, final int height) {
@@ -447,9 +395,9 @@ public class OSXUtil implements ToolkitProperties {
     private static native boolean isNSWindow0(long object);
     private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y);
     private static native Object GetInsets0(long windowOrView);
-    private static native double[] GetScreenData0();
     private static native double GetPixelScale0(int screenIndex);
-    private static native double GetPixelScale1(long windowOrView);
+    private static native double GetPixelScale1(int displayID);
+    private static native double GetPixelScale2(long windowOrView);
     private static native long CreateNSWindow0(int x, int y, int width, int height);
     private static native void DestroyNSWindow0(long nsWindow);
     private static native long GetNSView0(long nsWindow);
-- 
cgit v1.2.3