11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.stage;
27
28 import java.security.AllPermission;
29 import java.security.AccessControlContext;
30 import java.security.AccessController;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35
36 import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
37 import javafx.beans.property.DoubleProperty;
38 import javafx.beans.property.DoublePropertyBase;
39 import javafx.beans.property.ObjectProperty;
40 import javafx.beans.property.ObjectPropertyBase;
41 import javafx.beans.property.ReadOnlyBooleanProperty;
42 import javafx.beans.property.ReadOnlyBooleanWrapper;
43 import javafx.beans.property.ReadOnlyObjectProperty;
44 import javafx.beans.property.ReadOnlyObjectWrapper;
45 import javafx.beans.property.ReadOnlyDoubleProperty;
46 import javafx.beans.property.ReadOnlyDoubleWrapper;
47 import javafx.beans.property.SimpleObjectProperty;
48 import javafx.collections.FXCollections;
49 import javafx.collections.ObservableList;
50 import javafx.collections.ObservableMap;
51 import javafx.event.Event;
52 import javafx.event.EventDispatchChain;
53 import javafx.event.EventDispatcher;
54 import javafx.event.EventHandler;
55 import javafx.event.EventTarget;
56 import javafx.event.EventType;
57 import javafx.geometry.Rectangle2D;
58 import javafx.scene.Scene;
59
60 import com.sun.javafx.util.Utils;
61 import com.sun.javafx.util.WeakReferenceQueue;
62 import com.sun.javafx.css.StyleManager;
63 import com.sun.javafx.stage.WindowEventDispatcher;
64 import com.sun.javafx.stage.WindowHelper;
65 import com.sun.javafx.stage.WindowPeerListener;
66 import com.sun.javafx.tk.TKPulseListener;
67 import com.sun.javafx.tk.TKScene;
68 import com.sun.javafx.tk.TKStage;
69 import com.sun.javafx.tk.Toolkit;
70
71
72 /**
73 * <p>
74 * A top level window within which a scene is hosted, and with which the user
75 * interacts. A Window might be a {@link Stage}, {@link PopupWindow}, or other
76 * such top level. A Window is used also for browser plug-in based deployments.
77 * </p>
78 *
79 * @since JavaFX 2.0
80 */
81 public class Window implements EventTarget {
82
83 /**
84 * A list of all the currently _showing_ windows. This is publicly accessible via the unmodifiableWindows wrapper.
85 */
86 private static ObservableList<Window> windows = FXCollections.observableArrayList();
87 private static ObservableList<Window> unmodifiableWindows = FXCollections.unmodifiableObservableList(windows);
88
89 static {
91 new WindowHelper.WindowAccessor() {
92 /**
93 * Allow window peer listeners to directly change reported
94 * window location and size without changing the xExplicit,
95 * yExplicit, widthExplicit and heightExplicit values.
96 */
97 @Override
98 public void notifyLocationChanged(
99 Window window, double x, double y) {
100 window.notifyLocationChanged(x, y);
101 }
102
103 @Override
104 public void notifySizeChanged(Window window,
105 double width,
106 double height) {
107 window.notifySizeChanged(width, height);
108 }
109
110 @Override
111 public void notifyScreenChanged(Window window,
112 Object from,
113 Object to) {
114 window.notifyScreenChanged(from, to);
115 }
116
117 @Override
118 public float getUIScale(Window window) {
119 TKStage peer = window.impl_peer;
120 return peer == null ? 1.0f : peer.getUIScale();
121 }
122
123 @Override
124 public float getRenderScale(Window window) {
125 TKStage peer = window.impl_peer;
126 return peer == null ? 1.0f : peer.getRenderScale();
127 }
128
129 @Override
130 public ReadOnlyObjectProperty<Screen> screenProperty(Window window) {
131 return window.screenProperty();
132 }
133
134 @Override
135 public AccessControlContext getAccessControlContext(Window window) {
136 return window.acc;
137 }
138 });
139 }
140
141 /**
142 * Returns a list containing a reference to the currently showing JavaFX windows. The list is unmodifiable -
143 * attempting to modify this list will result in an {@link UnsupportedOperationException} being thrown at runtime.
144 *
145 * @return A list containing all windows that are currently showing.
146 * @since 9
272 xExplicit = false;
273 yExplicit = false;
274 if (impl_peer != null) {
275 Rectangle2D bounds = getWindowScreen().getVisualBounds();
276 double centerX =
277 bounds.getMinX() + (bounds.getWidth() - getWidth())
278 * CENTER_ON_SCREEN_X_FRACTION;
279 double centerY =
280 bounds.getMinY() + (bounds.getHeight() - getHeight())
281 * CENTER_ON_SCREEN_Y_FRACTION;
282
283 x.set(centerX);
284 y.set(centerY);
285 peerBoundsConfigurator.setLocation(centerX, centerY,
286 CENTER_ON_SCREEN_X_FRACTION,
287 CENTER_ON_SCREEN_Y_FRACTION);
288 applyBounds();
289 }
290 }
291
292 private boolean xExplicit = false;
293 /**
294 * The horizontal location of this {@code Stage} on the screen. Changing
295 * this attribute will move the {@code Stage} horizontally. Changing this
296 * attribute will not visually affect a {@code Stage} while
297 * {@code fullScreen} is true, but will be honored by the {@code Stage} once
298 * {@code fullScreen} becomes false.
299 */
300 private ReadOnlyDoubleWrapper x =
301 new ReadOnlyDoubleWrapper(this, "x", Double.NaN);
302
303 public final void setX(double value) {
304 setXInternal(value);
305 }
306 public final double getX() { return x.get(); }
307 public final ReadOnlyDoubleProperty xProperty() { return x.getReadOnlyProperty(); }
308
309 void setXInternal(double value) {
310 x.set(value);
311 peerBoundsConfigurator.setX(value, 0);
825 fireEvent(new WindowEvent(Window.this, WindowEvent.WINDOW_HIDING));
826 }
827
828 oldVisible = newVisible;
829 impl_visibleChanging(newVisible);
830 if (newVisible) {
831 hasBeenVisible = true;
832 windows.add(Window.this);
833 } else {
834 windows.remove(Window.this);
835 }
836 Toolkit tk = Toolkit.getToolkit();
837 if (impl_peer != null) {
838 if (newVisible) {
839 if (peerListener == null) {
840 peerListener = new WindowPeerListener(Window.this);
841 }
842
843 // Setup listener for changes coming back from peer
844 impl_peer.setTKStageListener(peerListener);
845 // Register pulse listener
846 tk.addStageTkPulseListener(peerBoundsConfigurator);
847
848 if (getScene() != null) {
849 getScene().impl_initPeer();
850 impl_peer.setScene(getScene().impl_getPeer());
851 getScene().impl_preferredSize();
852 }
853
854 // Set peer bounds
855 if ((getScene() != null) && (!widthExplicit || !heightExplicit)) {
856 adjustSize(true);
857 } else {
858 peerBoundsConfigurator.setSize(
859 getWidth(), getHeight(), -1, -1);
860 }
861
862 if (!xExplicit && !yExplicit) {
863 centerOnScreen();
864 } else {
1188 }
1189
1190 window = window.getWindowOwner();
1191 } while (window != null);
1192
1193 return Screen.getPrimary();
1194 }
1195
1196 private final ReadOnlyObjectWrapper<Screen> screen = new ReadOnlyObjectWrapper<>(Screen.getPrimary());
1197 private ReadOnlyObjectProperty<Screen> screenProperty() { return screen.getReadOnlyProperty(); }
1198
1199 private void notifyScreenChanged(Object from, Object to) {
1200 screen.set(Screen.getScreenForNative(to));
1201 }
1202
1203 /**
1204 * Caches all requested bounds settings and applies them at once during
1205 * the next pulse.
1206 */
1207 private final class TKBoundsConfigurator implements TKPulseListener {
1208 private double x;
1209 private double y;
1210 private float xGravity;
1211 private float yGravity;
1212 private double windowWidth;
1213 private double windowHeight;
1214 private double clientWidth;
1215 private double clientHeight;
1216
1217 private boolean dirty;
1218
1219 public TKBoundsConfigurator() {
1220 reset();
1221 }
1222
1223 public void setX(final double x, final float xGravity) {
1224 this.x = x;
1225 this.xGravity = xGravity;
1226 setDirty();
1227 }
1228
1229 public void setY(final double y, final float yGravity) {
1230 this.y = y;
1231 this.yGravity = yGravity;
1232 setDirty();
1233 }
1234
1235 public void setWindowWidth(final double windowWidth) {
1236 this.windowWidth = windowWidth;
1237 setDirty();
1238 }
1239
1240 public void setWindowHeight(final double windowHeight) {
1241 this.windowHeight = windowHeight;
1242 setDirty();
1259 this.x = x;
1260 this.y = y;
1261 this.xGravity = xGravity;
1262 this.yGravity = yGravity;
1263 setDirty();
1264 }
1265
1266 public void setSize(final double windowWidth,
1267 final double windowHeight,
1268 final double clientWidth,
1269 final double clientHeight) {
1270 this.windowWidth = windowWidth;
1271 this.windowHeight = windowHeight;
1272 this.clientWidth = clientWidth;
1273 this.clientHeight = clientHeight;
1274 setDirty();
1275 }
1276
1277 public void apply() {
1278 if (dirty) {
1279 impl_peer.setBounds((float) (Double.isNaN(x) ? 0 : x),
1280 (float) (Double.isNaN(y) ? 0 : y),
1281 !Double.isNaN(x),
1282 !Double.isNaN(y),
1283 (float) windowWidth,
1284 (float) windowHeight,
1285 (float) clientWidth,
1286 (float) clientHeight,
1287 xGravity, yGravity);
1288
1289 reset();
1290 }
1291 }
1292
1293 @Override
1294 public void pulse() {
1295 apply();
1296 }
1297
1298 private void reset() {
1299 x = Double.NaN;
1300 y = Double.NaN;
1301 xGravity = 0;
1302 yGravity = 0;
1303 windowWidth = -1;
1304 windowHeight = -1;
1305 clientWidth = -1;
1306 clientHeight = -1;
1307 dirty = false;
1308 }
1309
1310 private void setDirty() {
1311 if (!dirty) {
1312 Toolkit.getToolkit().requestNextPulse();
1313 dirty = true;
1314 }
1315 }
1316 }
1317 }
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.stage;
27
28 import java.security.AllPermission;
29 import java.security.AccessControlContext;
30 import java.security.AccessController;
31 import java.util.HashMap;
32
33 import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
34 import javafx.beans.property.DoubleProperty;
35 import javafx.beans.property.DoublePropertyBase;
36 import javafx.beans.property.ObjectProperty;
37 import javafx.beans.property.ObjectPropertyBase;
38 import javafx.beans.property.ReadOnlyBooleanProperty;
39 import javafx.beans.property.ReadOnlyBooleanWrapper;
40 import javafx.beans.property.ReadOnlyObjectProperty;
41 import javafx.beans.property.ReadOnlyObjectWrapper;
42 import javafx.beans.property.ReadOnlyDoubleProperty;
43 import javafx.beans.property.ReadOnlyDoubleWrapper;
44 import javafx.beans.property.SimpleObjectProperty;
45 import javafx.beans.property.SimpleDoubleProperty;
46 import javafx.collections.FXCollections;
47 import javafx.collections.ObservableList;
48 import javafx.collections.ObservableMap;
49 import javafx.event.Event;
50 import javafx.event.EventDispatchChain;
51 import javafx.event.EventDispatcher;
52 import javafx.event.EventHandler;
53 import javafx.event.EventTarget;
54 import javafx.event.EventType;
55 import javafx.geometry.Rectangle2D;
56 import javafx.scene.Scene;
57
58 import com.sun.javafx.util.Utils;
59 import com.sun.javafx.css.StyleManager;
60 import com.sun.javafx.stage.WindowEventDispatcher;
61 import com.sun.javafx.stage.WindowHelper;
62 import com.sun.javafx.stage.WindowPeerListener;
63 import com.sun.javafx.tk.TKPulseListener;
64 import com.sun.javafx.tk.TKScene;
65 import com.sun.javafx.tk.TKStage;
66 import com.sun.javafx.tk.Toolkit;
67 import javafx.beans.property.BooleanProperty;
68 import javafx.beans.property.SimpleBooleanProperty;
69
70
71 /**
72 * <p>
73 * A top level window within which a scene is hosted, and with which the user
74 * interacts. A Window might be a {@link Stage}, {@link PopupWindow}, or other
75 * such top level. A Window is used also for browser plug-in based deployments.
76 * </p>
77 *
78 * @since JavaFX 2.0
79 */
80 public class Window implements EventTarget {
81
82 /**
83 * A list of all the currently _showing_ windows. This is publicly accessible via the unmodifiableWindows wrapper.
84 */
85 private static ObservableList<Window> windows = FXCollections.observableArrayList();
86 private static ObservableList<Window> unmodifiableWindows = FXCollections.unmodifiableObservableList(windows);
87
88 static {
90 new WindowHelper.WindowAccessor() {
91 /**
92 * Allow window peer listeners to directly change reported
93 * window location and size without changing the xExplicit,
94 * yExplicit, widthExplicit and heightExplicit values.
95 */
96 @Override
97 public void notifyLocationChanged(
98 Window window, double x, double y) {
99 window.notifyLocationChanged(x, y);
100 }
101
102 @Override
103 public void notifySizeChanged(Window window,
104 double width,
105 double height) {
106 window.notifySizeChanged(width, height);
107 }
108
109 @Override
110 public void notifyScaleChanged(Window window,
111 double newOutputScaleX,
112 double newOutputScaleY) {
113 window.updateOutputScales(newOutputScaleX, newOutputScaleY);
114 }
115
116 @Override
117 public void notifyScreenChanged(Window window,
118 Object from,
119 Object to) {
120 window.notifyScreenChanged(from, to);
121 }
122
123 @Override
124 public float getPlatformScaleX(Window window) {
125 TKStage peer = window.impl_peer;
126 return peer == null ? 1.0f : peer.getPlatformScaleX();
127 }
128
129 @Override
130 public float getPlatformScaleY(Window window) {
131 TKStage peer = window.impl_peer;
132 return peer == null ? 1.0f : peer.getPlatformScaleY();
133 }
134
135 @Override
136 public ReadOnlyObjectProperty<Screen> screenProperty(Window window) {
137 return window.screenProperty();
138 }
139
140 @Override
141 public AccessControlContext getAccessControlContext(Window window) {
142 return window.acc;
143 }
144 });
145 }
146
147 /**
148 * Returns a list containing a reference to the currently showing JavaFX windows. The list is unmodifiable -
149 * attempting to modify this list will result in an {@link UnsupportedOperationException} being thrown at runtime.
150 *
151 * @return A list containing all windows that are currently showing.
152 * @since 9
278 xExplicit = false;
279 yExplicit = false;
280 if (impl_peer != null) {
281 Rectangle2D bounds = getWindowScreen().getVisualBounds();
282 double centerX =
283 bounds.getMinX() + (bounds.getWidth() - getWidth())
284 * CENTER_ON_SCREEN_X_FRACTION;
285 double centerY =
286 bounds.getMinY() + (bounds.getHeight() - getHeight())
287 * CENTER_ON_SCREEN_Y_FRACTION;
288
289 x.set(centerX);
290 y.set(centerY);
291 peerBoundsConfigurator.setLocation(centerX, centerY,
292 CENTER_ON_SCREEN_X_FRACTION,
293 CENTER_ON_SCREEN_Y_FRACTION);
294 applyBounds();
295 }
296 }
297
298 private void updateOutputScales(double sx, double sy) {
299 // We call updateRenderScales() before updating the property
300 // values so that an application can listen to the properties
301 // and set their own values overriding the default values we set.
302 updateRenderScales(sx, sy);
303 // Now set the properties and trigger any potential listeners.
304 outputScaleX.set(sx);
305 outputScaleY.set(sy);
306 }
307
308 void updateRenderScales(double sx, double sy) {
309 boolean forceInt = forceIntegerRenderScale.get();
310 if (!renderScaleX.isBound()) {
311 renderScaleX.set(forceInt ? Math.ceil(sx) : sx);
312 }
313 if (!renderScaleY.isBound()) {
314 renderScaleY.set(forceInt ? Math.ceil(sy) : sy);
315 }
316 }
317
318 /**
319 * The scale that the {@code Window} will apply to horizontal scene
320 * coordinates in all stages of rendering and compositing the output
321 * to the screen or other destination device.
322 * This property is updated asynchronously by the system at various
323 * times including:
324 * <ul>
325 * <li>Window creation
326 * <li>At some point during moving a window to a new {@code Screen}
327 * which may be before or after the {@link Screen} property is updated.
328 * <li>In response to a change in user preferences for output scaling.
329 * </ul>
330 * @see outputScaleThreshold
331 */
332 private ReadOnlyDoubleWrapper outputScaleX =
333 new ReadOnlyDoubleWrapper(this, "outputScaleX", 1.0);
334 public final double getOutputScaleX() {
335 return outputScaleX.get();
336 }
337 public final ReadOnlyDoubleProperty outputScaleXProperty() {
338 return outputScaleX.getReadOnlyProperty();
339 }
340
341 /**
342 * The scale that the {@code Window} will apply to vertical scene
343 * coordinates in all stages of rendering and compositing the output
344 * to the screen or other destination device.
345 * This property is updated asynchronously by the system at various
346 * times including:
347 * <ul>
348 * <li>Window creation
349 * <li>At some point during moving a window to a new {@code Screen}
350 * which may be before or after the {@link Screen} property is updated.
351 * <li>In response to a change in user preferences for output scaling.
352 * </ul>
353 * @see outputScaleThreshold
354 */
355 private ReadOnlyDoubleWrapper outputScaleY =
356 new ReadOnlyDoubleWrapper(this, "outputScaleY", 1.0);
357 public final double getOutputScaleY() {
358 return outputScaleY.get();
359 }
360 public final ReadOnlyDoubleProperty outputScaleYProperty() {
361 return outputScaleY.getReadOnlyProperty();
362 }
363
364 /**
365 * Boolean property that controls whether only integer render scales
366 * are set by default by the system when there is a change in the
367 * associated output scale.
368 * The {@code renderScale} properties will be updated directly and
369 * simultaneously with any changes in the associated {@code outputScale}
370 * properties, but the values can be overridden by subsequent calls to
371 * the {@code setRenderScale} setters or through appropriate use of
372 * binding.
373 * This property will not prevent setting non-integer scales
374 * directly using the {@code renderScale} property object or the
375 * convenience setter method.
376 */
377 private BooleanProperty forceIntegerRenderScale =
378 new SimpleBooleanProperty(this, "forceIntegerRenderScale", false) {
379 @Override
380 protected void invalidated() {
381 updateRenderScales(getOutputScaleX(),
382 getOutputScaleY());
383 }
384 };
385 public final void setForceIntegerRenderScale(boolean forced) {
386 forceIntegerRenderScale.set(forced);
387 }
388 public final boolean isForceIntegerRenderScale() {
389 return forceIntegerRenderScale.get();
390 }
391 public final BooleanProperty forceIntegerRenderScaleProperty() {
392 return forceIntegerRenderScale;
393 }
394
395 /**
396 * The horizontal scale that the {@code Window} will use when rendering
397 * its {@code Scene} to the rendering buffer.
398 * This property is automatically updated whenever there is a change in
399 * the {@link outputScaleX} property and can be overridden either by
400 * calling {@code setRenderScaleX()} in response to a listener on the
401 * {@code outputScaleX} property or by binding it appropriately.
402 */
403 private DoubleProperty renderScaleX =
404 new SimpleDoubleProperty(this, "renderScaleX", 1.0) {
405 @Override
406 protected void invalidated() {
407 peerBoundsConfigurator.setRenderScaleX(get());
408 }
409 };
410 public final void setRenderScaleX(double scale) {
411 renderScaleX.set(scale);
412 }
413 public final double getRenderScaleX() {
414 return renderScaleX.get();
415 }
416 public final DoubleProperty renderScaleXProperty() {
417 return renderScaleX;
418 }
419
420 /**
421 * The vertical scale that the {@code Window} will use when rendering
422 * its {@code Scene} to the rendering buffer.
423 * This property is automatically updated whenever there is a change in
424 * the {@link outputScaleY} property and can be overridden either by
425 * calling {@code setRenderScaleY()} in response to a listener on the
426 * {@code outputScaleY} property or by binding it appropriately.
427 */
428 private DoubleProperty renderScaleY =
429 new SimpleDoubleProperty(this, "renderScaleY", 1.0) {
430 @Override
431 protected void invalidated() {
432 peerBoundsConfigurator.setRenderScaleY(get());
433 }
434 };
435 public final void setRenderScaleY(double scale) {
436 renderScaleY.set(scale);
437 }
438 public final double getRenderScaleY() {
439 return renderScaleY.get();
440 }
441 public final DoubleProperty renderScaleYProperty() {
442 return renderScaleY;
443 }
444
445 private boolean xExplicit = false;
446 /**
447 * The horizontal location of this {@code Stage} on the screen. Changing
448 * this attribute will move the {@code Stage} horizontally. Changing this
449 * attribute will not visually affect a {@code Stage} while
450 * {@code fullScreen} is true, but will be honored by the {@code Stage} once
451 * {@code fullScreen} becomes false.
452 */
453 private ReadOnlyDoubleWrapper x =
454 new ReadOnlyDoubleWrapper(this, "x", Double.NaN);
455
456 public final void setX(double value) {
457 setXInternal(value);
458 }
459 public final double getX() { return x.get(); }
460 public final ReadOnlyDoubleProperty xProperty() { return x.getReadOnlyProperty(); }
461
462 void setXInternal(double value) {
463 x.set(value);
464 peerBoundsConfigurator.setX(value, 0);
978 fireEvent(new WindowEvent(Window.this, WindowEvent.WINDOW_HIDING));
979 }
980
981 oldVisible = newVisible;
982 impl_visibleChanging(newVisible);
983 if (newVisible) {
984 hasBeenVisible = true;
985 windows.add(Window.this);
986 } else {
987 windows.remove(Window.this);
988 }
989 Toolkit tk = Toolkit.getToolkit();
990 if (impl_peer != null) {
991 if (newVisible) {
992 if (peerListener == null) {
993 peerListener = new WindowPeerListener(Window.this);
994 }
995
996 // Setup listener for changes coming back from peer
997 impl_peer.setTKStageListener(peerListener);
998 updateOutputScales(impl_peer.getOutputScaleX(), impl_peer.getOutputScaleY());
999 // Register pulse listener
1000 tk.addStageTkPulseListener(peerBoundsConfigurator);
1001
1002 if (getScene() != null) {
1003 getScene().impl_initPeer();
1004 impl_peer.setScene(getScene().impl_getPeer());
1005 getScene().impl_preferredSize();
1006 }
1007
1008 // Set peer bounds
1009 if ((getScene() != null) && (!widthExplicit || !heightExplicit)) {
1010 adjustSize(true);
1011 } else {
1012 peerBoundsConfigurator.setSize(
1013 getWidth(), getHeight(), -1, -1);
1014 }
1015
1016 if (!xExplicit && !yExplicit) {
1017 centerOnScreen();
1018 } else {
1342 }
1343
1344 window = window.getWindowOwner();
1345 } while (window != null);
1346
1347 return Screen.getPrimary();
1348 }
1349
1350 private final ReadOnlyObjectWrapper<Screen> screen = new ReadOnlyObjectWrapper<>(Screen.getPrimary());
1351 private ReadOnlyObjectProperty<Screen> screenProperty() { return screen.getReadOnlyProperty(); }
1352
1353 private void notifyScreenChanged(Object from, Object to) {
1354 screen.set(Screen.getScreenForNative(to));
1355 }
1356
1357 /**
1358 * Caches all requested bounds settings and applies them at once during
1359 * the next pulse.
1360 */
1361 private final class TKBoundsConfigurator implements TKPulseListener {
1362 private double renderScaleX;
1363 private double renderScaleY;
1364 private double x;
1365 private double y;
1366 private float xGravity;
1367 private float yGravity;
1368 private double windowWidth;
1369 private double windowHeight;
1370 private double clientWidth;
1371 private double clientHeight;
1372
1373 private boolean dirty;
1374
1375 public TKBoundsConfigurator() {
1376 reset();
1377 }
1378
1379 public void setRenderScaleX(final double renderScaleX) {
1380 this.renderScaleX = renderScaleX;
1381 setDirty();
1382 }
1383
1384 public void setRenderScaleY(final double renderScaleY) {
1385 this.renderScaleY = renderScaleY;
1386 setDirty();
1387 }
1388
1389 public void setX(final double x, final float xGravity) {
1390 this.x = x;
1391 this.xGravity = xGravity;
1392 setDirty();
1393 }
1394
1395 public void setY(final double y, final float yGravity) {
1396 this.y = y;
1397 this.yGravity = yGravity;
1398 setDirty();
1399 }
1400
1401 public void setWindowWidth(final double windowWidth) {
1402 this.windowWidth = windowWidth;
1403 setDirty();
1404 }
1405
1406 public void setWindowHeight(final double windowHeight) {
1407 this.windowHeight = windowHeight;
1408 setDirty();
1425 this.x = x;
1426 this.y = y;
1427 this.xGravity = xGravity;
1428 this.yGravity = yGravity;
1429 setDirty();
1430 }
1431
1432 public void setSize(final double windowWidth,
1433 final double windowHeight,
1434 final double clientWidth,
1435 final double clientHeight) {
1436 this.windowWidth = windowWidth;
1437 this.windowHeight = windowHeight;
1438 this.clientWidth = clientWidth;
1439 this.clientHeight = clientHeight;
1440 setDirty();
1441 }
1442
1443 public void apply() {
1444 if (dirty) {
1445 // Snapshot values and then reset() before we call down
1446 // as we may end up with recursive calls back up with
1447 // new values that must be recorded as dirty.
1448 boolean xSet = !Double.isNaN(x);
1449 float newX = xSet ? (float) x : 0f;
1450 boolean ySet = !Double.isNaN(y);
1451 float newY = ySet ? (float) y : 0f;
1452 float newWW = (float) windowWidth;
1453 float newWH = (float) windowHeight;
1454 float newCW = (float) clientWidth;
1455 float newCH = (float) clientHeight;
1456 float newXG = xGravity;
1457 float newYG = yGravity;
1458 float newRX = (float) renderScaleX;
1459 float newRY = (float) renderScaleY;
1460 reset();
1461 impl_peer.setBounds(newX, newY, xSet, ySet,
1462 newWW, newWH, newCW, newCH,
1463 newXG, newYG,
1464 newRX, newRY);
1465 }
1466 }
1467
1468 @Override
1469 public void pulse() {
1470 apply();
1471 }
1472
1473 private void reset() {
1474 renderScaleX = 0.0;
1475 renderScaleY = 0.0;
1476 x = Double.NaN;
1477 y = Double.NaN;
1478 xGravity = 0;
1479 yGravity = 0;
1480 windowWidth = -1;
1481 windowHeight = -1;
1482 clientWidth = -1;
1483 clientHeight = -1;
1484 dirty = false;
1485 }
1486
1487 private void setDirty() {
1488 if (!dirty) {
1489 Toolkit.getToolkit().requestNextPulse();
1490 dirty = true;
1491 }
1492 }
1493 }
1494 }
|