diff options
Diffstat (limited to 'src/nativewindow/classes')
9 files changed, 361 insertions, 260 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 32e4add75..97dba9598 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -47,6 +47,8 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; +import java.awt.EventQueue; +import java.awt.GraphicsConfiguration; import java.awt.Window; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; @@ -103,10 +105,11 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected Insets insets; private volatile long offscreenSurfaceLayer; - 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 final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + private volatile boolean hasPixelScaleChanged = false; private long drawable_old; /** @@ -269,38 +272,41 @@ 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; + minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; + maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScaleChanged = false; } protected abstract void invalidateNative(); - /** - * {@inheritDoc} - * <p> - * Per default impl. only works for not yet {@link #isRealized() realized} instances, - * current exception OSX. - * </p> - */ @Override - public void setSurfaceScale(final int[] pixelScale) { - SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null); + public boolean setSurfaceScale(final float[] pixelScale) { + System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2); + return false; } @Override - public final int[] getRequestedSurfaceScale(final int[] result) { + public final float[] getRequestedSurfaceScale(final float[] result) { System.arraycopy(reqPixelScale, 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) { - System.arraycopy(nativePixelScale, 0, result, 0, 2); + public float[] getMinimumSurfaceScale(final float[] result) { + System.arraycopy(minPixelScale, 0, result, 0, 2); + return result; + } + + @Override + public final float[] getMaximumSurfaceScale(final float[] result) { + System.arraycopy(maxPixelScale, 0, result, 0, 2); return result; } @@ -323,31 +329,75 @@ 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; + updatePixelScale(false); + return hasPixelScaleChanged || changedBounds; + } + + /** + * Updates the minimum and maximum pixel-scale values + * and returns {@code true} if they were updated. + * @param clearFlag if {@code true}, the {@code hasPixelScaleChanged} flag will be cleared + * @return {@code true} if values were updated, otherwise {@code false}. + * @see #hasPixelScaleChanged() + */ + public final boolean updatePixelScale(final boolean clearFlag) { + // Using GraphicsConfiguration from component, which may change by moving to diff monitor + if( EventQueue.isDispatchThread() || Thread.holdsLock(component.getTreeLock()) ) { + if( JAWTUtil.getPixelScale(component.getGraphicsConfiguration(), minPixelScale, maxPixelScale) ) { + hasPixelScaleChanged = true; + if( DEBUG ) { + System.err.println("JAWTWindow.updatePixelScale: updated req["+ + reqPixelScale[0]+", "+reqPixelScale[1]+"], min["+ + minPixelScale[0]+", "+minPixelScale[1]+"], max["+ + maxPixelScale[0]+", "+maxPixelScale[1]+"], has["+ + hasPixelScale[0]+", "+hasPixelScale[1]+"]"); + } + } + } + if( clearFlag ) { + final boolean r = hasPixelScaleChanged; + hasPixelScaleChanged = false; + return r; + } else { + return hasPixelScaleChanged; + } + } + + /** + * Returns and clears the {@code hasPixelScaleChanged} flag, as set via {@link #lockSurface()}. + * <p> + * {@code hasPixelScaleChanged} is {@code true}, + * if the {@link #getMinimumSurfaceScale(float[]) minimum} or {@link #getMaximumSurfaceScale(float[]) maximum} + * pixel scale has changed. + * User needs to {@link #setSurfaceScale(float[]) set the current pixel scale} in this case + * using the {@link #getRequestedSurfaceScale(float[]) requested pixel scale} + * to update the surface pixel scale. + * </p> + */ + public final boolean hasPixelScaleChanged() { + final boolean v = hasPixelScaleChanged; + hasPixelScaleChanged = false; + return v; } /** - * Update pixelScale + * set requested pixelScale * @return true if pixelScale has changed, otherwise false */ - protected final boolean updatePixelScale() { - return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null); + protected final boolean setReqPixelScale() { + updatePixelScale(true); + return SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null); } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */ - protected final int getPixelScaleX() { return hasPixelScale[0]; } + protected final float getPixelScaleX() { return hasPixelScale[0]; } /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */ - protected final int getPixelScaleY() { return hasPixelScale[1]; } + protected final float getPixelScaleY() { return hasPixelScale[1]; } @Override public final InsetsImmutable getInsets() { return insets; } @@ -671,26 +721,22 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final int getSurfaceWidth() { - return getWidth() * getPixelScaleX(); + return SurfaceScaleUtils.scale(getWidth(), getPixelScaleX()); } @Override public final int getSurfaceHeight() { - return getHeight() * getPixelScaleY(); + return SurfaceScaleUtils.scale(getHeight(), getPixelScaleY()); } @Override public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { - pixelUnitsAndResult[0] /= getPixelScaleX(); - pixelUnitsAndResult[1] /= getPixelScaleY(); - return pixelUnitsAndResult; + return SurfaceScaleUtils.scaleInv(pixelUnitsAndResult, pixelUnitsAndResult, hasPixelScale); } @Override public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { - windowUnitsAndResult[0] *= getPixelScaleX(); - windowUnitsAndResult[1] *= getPixelScaleY(); - return windowUnitsAndResult; + return SurfaceScaleUtils.scale(windowUnitsAndResult, windowUnitsAndResult, hasPixelScale); } @Override @@ -874,7 +920,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, ", bounds "+bounds+", insets "+insets ); sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+ - "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ + "], pixels[scale "+getPixelScaleX()+", "+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ ", visible "+component.isVisible()); sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ ",\n\tconfig "+config+ diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index 4d764dc4f..d5ac56178 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java @@ -198,6 +198,7 @@ public interface NativeSurface extends SurfaceUpdatedListener { * @param pixelUnitsAndResult int[2] storage holding the pixel units for the x- and y-coord to convert * and the resulting values. * @return result int[2] storage pixelUnitsAndResult for chaining holding the converted values + * @see ScalableSurface */ public int[] convertToWindowUnits(final int[] pixelUnitsAndResult); @@ -206,6 +207,7 @@ public interface NativeSurface extends SurfaceUpdatedListener { * @param windowUnitsAndResult int[2] storage holding the window units for the x- and y-coord to convert * and the resulting values. * @return result int[2] storage windowUnitsAndResult for chaining holding the converted values + * @see ScalableSurface */ public int[] convertToPixelUnits(final int[] windowUnitsAndResult); diff --git a/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java index ffd5c224c..0cd2c7961 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java @@ -30,16 +30,17 @@ package javax.media.nativewindow; /** * Adding mutable surface pixel scale property to implementing class, usually to a {@link NativeSurface} implementation, - * see {@link #setSurfaceScale(int[])}. + * see {@link #setSurfaceScale(float[])}. */ public interface ScalableSurface { /** Setting surface-pixel-scale of {@value}, results in same pixel- and window-units. */ - public static final int IDENTITY_PIXELSCALE = 1; + public static final float IDENTITY_PIXELSCALE = 1f; /** Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale, i.e. pixel-units >> window-units where available. */ - public static final int AUTOMAX_PIXELSCALE = 0; + public static final float AUTOMAX_PIXELSCALE = 0f; /** - * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}. + * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}, + * where {@code size_in_pixel_units = pixel_scale * size_in_window_units}. * <p> * Default pixel scale request for both directions is {@link #AUTOMAX_PIXELSCALE}. * </p> @@ -50,48 +51,57 @@ public interface ScalableSurface { * <p> * The <i>requested</i> pixel scale will be validated against platform limits before native scale-setup, * i.e. clipped to {@link #IDENTITY_PIXELSCALE} if not supported or clipped to the platform maximum. - * It can be queried via {@link #getRequestedSurfaceScale(int[])}. + * It can be queried via {@link #getRequestedSurfaceScale(float[])}. * </p> * <p> * The actual <i>realized</i> pixel scale values of the {@link NativeSurface} - * can be queried via {@link #getCurrentSurfaceScale(int[])} or + * can be queried via {@link #getCurrentSurfaceScale(float[])} or * computed via <code>surface.{@link NativeSurface#convertToPixelUnits(int[]) convertToPixelUnits}(new int[] { 1, 1 })</code> * </p> - * @param pixelScale <i>requested</i> surface pixel scale int[2] values for x- and y-direction. + * @param pixelScale <i>requested</i> surface pixel scale float[2] values for x- and y-direction. + * @return {@code true} if the {@link #getCurrentSurfaceScale(float[]) current pixel scale} has changed, otherwise {@code false}. + * @see #getRequestedSurfaceScale(float[]) */ - public void setSurfaceScale(final int[] pixelScale); + public boolean setSurfaceScale(final float[] pixelScale); /** - * Returns the requested pixel scale of the associated {@link NativeSurface}. + * Returns the {@link #setSurfaceScale(float[]) requested} pixel scale of the associated {@link NativeSurface}. * - * @param result int[2] storage for the result - * @return the passed storage containing the requested pixelScale for chaining + * @param result float[2] storage for the result + * @return the passed storage containing the current pixelScale for chaining + * @see #setSurfaceScale(float[]) */ - int[] getRequestedSurfaceScale(final int[] result); + public float[] getRequestedSurfaceScale(final float[] result); /** * Returns the current pixel scale of the associated {@link NativeSurface}. * - * @param result int[2] storage for the result + * @param result float[2] storage for the result * @return the passed storage containing the current pixelScale for chaining */ - public int[] getCurrentSurfaceScale(final int[] result); + public float[] getCurrentSurfaceScale(final float[] result); + + /** + * Returns the minimum pixel scale of the associated {@link NativeSurface}. + * @param result float[2] storage for the result + * @return the passed storage containing the minimum pixelScale for chaining + */ + public float[] getMinimumSurfaceScale(final float[] result); /** - * Returns the native pixel scale of the associated {@link NativeSurface} - * reflecting it's currently bound <i>monitor surface resolution in pixels</i>. + * Returns the maximum pixel scale of the associated {@link NativeSurface}. * <p> - * The native pixel scale maybe used to determine the proper <i>dpi</i> - * value of this {@link NativeSurface}: + * The maximum pixel scale maybe used to determine the proper <i>dpi</i> + * value of the monitor displaying 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 + * @param result float[2] storage for the result + * @return the passed storage containing the maximum pixelScale for chaining */ - public int[] getNativeSurfaceScale(final int[] result); + public float[] getMaximumSurfaceScale(final float[] result); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/Point.java b/src/nativewindow/classes/javax/media/nativewindow/util/Point.java index 3576a7dd0..3d416d2f5 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/Point.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/Point.java @@ -145,6 +145,22 @@ public class Point implements Cloneable, PointImmutable { } /** + * Scale this instance's x- and y-components, + * i.e. multiply them by the given scale factors. + * <p> + * The product is rounded back to integer. + * </p> + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Point scale(final float sx, final float sy) { + x = (int)(x * sx + 0.5f); + y = (int)(y * sy + 0.5f); + return this; + } + + /** * Inverse scale this instance's x- and y-components, * i.e. divide them by the given scale factors. * @param sx inverse scale factor for x @@ -156,4 +172,19 @@ public class Point implements Cloneable, PointImmutable { y /= sy ; return this; } + /** + * Inverse scale this instance's x- and y-components, + * i.e. divide them by the given scale factors. + * <p> + * The product is rounded back to integer. + * </p> + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Point scaleInv(final float sx, final float sy) { + x = (int)(x / sx + 0.5f); + y = (int)(y / sy + 0.5f); + return this; + } } 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} > {@code maxPixelScale}</li> + * <li>{@code pixelScale} ~= {@code maxPixelScale}</li> + * </ul> + * </p> + * <p> + * Method returns {@code minPixelScale} if + * <ul> + * <li>{@code pixelScale} < {@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 ≤ {@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); |