modules/graphics/src/main/java/javafx/stage/Window.java

Print this page

        

*** 26,39 **** package javafx.stage; import java.security.AllPermission; import java.security.AccessControlContext; import java.security.AccessController; - import java.util.ArrayList; import java.util.HashMap; - import java.util.Iterator; - import java.util.List; import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection; import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoublePropertyBase; import javafx.beans.property.ObjectProperty; --- 26,36 ----
*** 43,52 **** --- 40,50 ---- import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.SimpleObjectProperty; + import javafx.beans.property.SimpleDoubleProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; import javafx.event.Event; import javafx.event.EventDispatchChain;
*** 56,74 **** import javafx.event.EventType; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import com.sun.javafx.util.Utils; - import com.sun.javafx.util.WeakReferenceQueue; import com.sun.javafx.css.StyleManager; import com.sun.javafx.stage.WindowEventDispatcher; import com.sun.javafx.stage.WindowHelper; import com.sun.javafx.stage.WindowPeerListener; import com.sun.javafx.tk.TKPulseListener; import com.sun.javafx.tk.TKScene; import com.sun.javafx.tk.TKStage; import com.sun.javafx.tk.Toolkit; /** * <p> * A top level window within which a scene is hosted, and with which the user --- 54,73 ---- import javafx.event.EventType; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import com.sun.javafx.util.Utils; import com.sun.javafx.css.StyleManager; import com.sun.javafx.stage.WindowEventDispatcher; import com.sun.javafx.stage.WindowHelper; import com.sun.javafx.stage.WindowPeerListener; import com.sun.javafx.tk.TKPulseListener; import com.sun.javafx.tk.TKScene; import com.sun.javafx.tk.TKStage; import com.sun.javafx.tk.Toolkit; + import javafx.beans.property.BooleanProperty; + import javafx.beans.property.SimpleBooleanProperty; /** * <p> * A top level window within which a scene is hosted, and with which the user
*** 106,134 **** double height) { window.notifySizeChanged(width, height); } @Override public void notifyScreenChanged(Window window, Object from, Object to) { window.notifyScreenChanged(from, to); } @Override - public float getUIScale(Window window) { - TKStage peer = window.impl_peer; - return peer == null ? 1.0f : peer.getUIScale(); - } - - @Override - public float getRenderScale(Window window) { - TKStage peer = window.impl_peer; - return peer == null ? 1.0f : peer.getRenderScale(); - } - - @Override public ReadOnlyObjectProperty<Screen> screenProperty(Window window) { return window.screenProperty(); } @Override --- 105,128 ---- double height) { window.notifySizeChanged(width, height); } @Override + public void notifyScaleChanged(Window window, + double newOutputScaleX, + double newOutputScaleY) { + window.updateOutputScales(newOutputScaleX, newOutputScaleY); + } + + @Override public void notifyScreenChanged(Window window, Object from, Object to) { window.notifyScreenChanged(from, to); } @Override public ReadOnlyObjectProperty<Screen> screenProperty(Window window) { return window.screenProperty(); } @Override
*** 287,296 **** --- 281,437 ---- CENTER_ON_SCREEN_Y_FRACTION); applyBounds(); } } + private void updateOutputScales(double sx, double sy) { + // We call updateRenderScales() before updating the property + // values so that an application can listen to the properties + // and set their own values overriding the default values we set. + updateRenderScales(sx, sy); + // Now set the properties and trigger any potential listeners. + outputScaleX.set(sx); + outputScaleY.set(sy); + } + + void updateRenderScales(double sx, double sy) { + boolean forceInt = forceIntegerRenderScale.get(); + if (!renderScaleX.isBound()) { + renderScaleX.set(forceInt ? Math.ceil(sx) : sx); + } + if (!renderScaleY.isBound()) { + renderScaleY.set(forceInt ? Math.ceil(sy) : sy); + } + } + + /** + * The scale that the {@code Window} will apply to horizontal scene + * coordinates in all stages of rendering and compositing the output + * to the screen or other destination device. + * This property is updated asynchronously by the system at various + * times including: + * <ul> + * <li>Window creation + * <li>At some point during moving a window to a new {@code Screen} + * which may be before or after the {@link Screen} property is updated. + * <li>In response to a change in user preferences for output scaling. + * </ul> + * @see outputScaleThreshold + */ + private ReadOnlyDoubleWrapper outputScaleX = + new ReadOnlyDoubleWrapper(this, "outputScaleX", 1.0); + public final double getOutputScaleX() { + return outputScaleX.get(); + } + public final ReadOnlyDoubleProperty outputScaleXProperty() { + return outputScaleX.getReadOnlyProperty(); + } + + /** + * The scale that the {@code Window} will apply to vertical scene + * coordinates in all stages of rendering and compositing the output + * to the screen or other destination device. + * This property is updated asynchronously by the system at various + * times including: + * <ul> + * <li>Window creation + * <li>At some point during moving a window to a new {@code Screen} + * which may be before or after the {@link Screen} property is updated. + * <li>In response to a change in user preferences for output scaling. + * </ul> + * @see outputScaleThreshold + */ + private ReadOnlyDoubleWrapper outputScaleY = + new ReadOnlyDoubleWrapper(this, "outputScaleY", 1.0); + public final double getOutputScaleY() { + return outputScaleY.get(); + } + public final ReadOnlyDoubleProperty outputScaleYProperty() { + return outputScaleY.getReadOnlyProperty(); + } + + /** + * Boolean property that controls whether only integer render scales + * are set by default by the system when there is a change in the + * associated output scale. + * The {@code renderScale} properties will be updated directly and + * simultaneously with any changes in the associated {@code outputScale} + * properties, but the values can be overridden by subsequent calls to + * the {@code setRenderScale} setters or through appropriate use of + * binding. + * This property will not prevent setting non-integer scales + * directly using the {@code renderScale} property object or the + * convenience setter method. + */ + private BooleanProperty forceIntegerRenderScale = + new SimpleBooleanProperty(this, "forceIntegerRenderScale", false) { + @Override + protected void invalidated() { + updateRenderScales(getOutputScaleX(), + getOutputScaleY()); + } + }; + public final void setForceIntegerRenderScale(boolean forced) { + forceIntegerRenderScale.set(forced); + } + public final boolean isForceIntegerRenderScale() { + return forceIntegerRenderScale.get(); + } + public final BooleanProperty forceIntegerRenderScaleProperty() { + return forceIntegerRenderScale; + } + + /** + * The horizontal scale that the {@code Window} will use when rendering + * its {@code Scene} to the rendering buffer. + * This property is automatically updated whenever there is a change in + * the {@link outputScaleX} property and can be overridden either by + * calling {@code setRenderScaleX()} in response to a listener on the + * {@code outputScaleX} property or by binding it appropriately. + */ + private DoubleProperty renderScaleX = + new SimpleDoubleProperty(this, "renderScaleX", 1.0) { + @Override + protected void invalidated() { + peerBoundsConfigurator.setRenderScaleX(get()); + } + }; + public final void setRenderScaleX(double scale) { + renderScaleX.set(scale); + } + public final double getRenderScaleX() { + return renderScaleX.get(); + } + public final DoubleProperty renderScaleXProperty() { + return renderScaleX; + } + + /** + * The vertical scale that the {@code Window} will use when rendering + * its {@code Scene} to the rendering buffer. + * This property is automatically updated whenever there is a change in + * the {@link outputScaleY} property and can be overridden either by + * calling {@code setRenderScaleY()} in response to a listener on the + * {@code outputScaleY} property or by binding it appropriately. + */ + private DoubleProperty renderScaleY = + new SimpleDoubleProperty(this, "renderScaleY", 1.0) { + @Override + protected void invalidated() { + peerBoundsConfigurator.setRenderScaleY(get()); + } + }; + public final void setRenderScaleY(double scale) { + renderScaleY.set(scale); + } + public final double getRenderScaleY() { + return renderScaleY.get(); + } + public final DoubleProperty renderScaleYProperty() { + return renderScaleY; + } + private boolean xExplicit = false; /** * The horizontal location of this {@code Stage} on the screen. Changing * this attribute will move the {@code Stage} horizontally. Changing this * attribute will not visually affect a {@code Stage} while
*** 840,849 **** --- 981,991 ---- peerListener = new WindowPeerListener(Window.this); } // Setup listener for changes coming back from peer impl_peer.setTKStageListener(peerListener); + updateOutputScales(impl_peer.getOutputScaleX(), impl_peer.getOutputScaleY()); // Register pulse listener tk.addStageTkPulseListener(peerBoundsConfigurator); if (getScene() != null) { getScene().impl_initPeer();
*** 1203,1212 **** --- 1345,1356 ---- /** * Caches all requested bounds settings and applies them at once during * the next pulse. */ private final class TKBoundsConfigurator implements TKPulseListener { + private double renderScaleX; + private double renderScaleY; private double x; private double y; private float xGravity; private float yGravity; private double windowWidth;
*** 1218,1227 **** --- 1362,1381 ---- public TKBoundsConfigurator() { reset(); } + public void setRenderScaleX(final double renderScaleX) { + this.renderScaleX = renderScaleX; + setDirty(); + } + + public void setRenderScaleY(final double renderScaleY) { + this.renderScaleY = renderScaleY; + setDirty(); + } + public void setX(final double x, final float xGravity) { this.x = x; this.xGravity = xGravity; setDirty(); }
*** 1274,1303 **** setDirty(); } public void apply() { if (dirty) { ! impl_peer.setBounds((float) (Double.isNaN(x) ? 0 : x), ! (float) (Double.isNaN(y) ? 0 : y), ! !Double.isNaN(x), ! !Double.isNaN(y), ! (float) windowWidth, ! (float) windowHeight, ! (float) clientWidth, ! (float) clientHeight, ! xGravity, yGravity); ! reset(); } } @Override public void pulse() { apply(); } private void reset() { x = Double.NaN; y = Double.NaN; xGravity = 0; yGravity = 0; windowWidth = -1; --- 1428,1468 ---- setDirty(); } public void apply() { if (dirty) { ! // Snapshot values and then reset() before we call down ! // as we may end up with recursive calls back up with ! // new values that must be recorded as dirty. ! boolean xSet = !Double.isNaN(x); ! float newX = xSet ? (float) x : 0f; ! boolean ySet = !Double.isNaN(y); ! float newY = ySet ? (float) y : 0f; ! float newWW = (float) windowWidth; ! float newWH = (float) windowHeight; ! float newCW = (float) clientWidth; ! float newCH = (float) clientHeight; ! float newXG = xGravity; ! float newYG = yGravity; ! float newRX = (float) renderScaleX; ! float newRY = (float) renderScaleY; reset(); + impl_peer.setBounds(newX, newY, xSet, ySet, + newWW, newWH, newCW, newCH, + newXG, newYG, + newRX, newRY); } } @Override public void pulse() { apply(); } private void reset() { + renderScaleX = 0.0; + renderScaleY = 0.0; x = Double.NaN; y = Double.NaN; xGravity = 0; yGravity = 0; windowWidth = -1;