1 /*
   2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  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.util.ArrayList;
  29 import java.util.List;
  30 
  31 import javafx.beans.property.BooleanProperty;
  32 import javafx.beans.property.BooleanPropertyBase;
  33 import javafx.beans.property.SimpleBooleanProperty;
  34 import javafx.beans.property.StringProperty;
  35 import javafx.beans.property.StringPropertyBase;
  36 import javafx.collections.FXCollections;
  37 import javafx.collections.ListChangeListener.Change;
  38 import javafx.collections.ObservableList;
  39 import javafx.geometry.NodeOrientation;
  40 import javafx.scene.Scene;
  41 import javafx.scene.image.Image;
  42 import javafx.scene.input.KeyCombination;
  43 
  44 import com.sun.javafx.beans.annotations.Default;
  45 import com.sun.javafx.collections.TrackableObservableList;
  46 import com.sun.javafx.robot.impl.FXRobotHelper;
  47 import com.sun.javafx.scene.SceneHelper;
  48 import com.sun.javafx.stage.StageHelper;
  49 import com.sun.javafx.stage.StagePeerListener;
  50 import com.sun.javafx.tk.TKPulseListener;
  51 import com.sun.javafx.tk.TKStage;
  52 import com.sun.javafx.tk.Toolkit;
  53 import java.security.AllPermission;
  54 import javafx.beans.property.DoubleProperty;
  55 import javafx.beans.property.DoublePropertyBase;
  56 import javafx.beans.property.ObjectProperty;
  57 import javafx.beans.property.Property;
  58 import javafx.beans.property.ReadOnlyBooleanProperty;
  59 import javafx.beans.property.ReadOnlyBooleanWrapper;
  60 import javafx.beans.property.SimpleObjectProperty;
  61 import javafx.beans.value.ObservableValue;
  62 
  63 /**
  64  * The JavaFX {@code Stage} class is the top level JavaFX container.
  65  * The primary Stage is constructed by the platform. Additional Stage
  66  * objects may be constructed by the application.
  67  *
  68  * <p>
  69  * Stage objects must be constructed and modified on the
  70  * JavaFX Application Thread.
  71  * </p>
  72  * <p>
  73  * Many of the {@code Stage} properties are read only because they can
  74  * be changed externally by the underlying platform and therefore must
  75  * not be bindable.
  76  * </p>
  77  * 
  78  * <p><b>Style</b></p>
  79  * <p>
  80  * A stage has one of the following styles:
  81  * <ul>
  82  * <li>{@link StageStyle#DECORATED} - a stage with a solid white background and
  83  * platform decorations.</li>
  84  * <li>{@link StageStyle#UNDECORATED} - a stage with a solid white background
  85  * and no decorations.</li>
  86  * <li>{@link StageStyle#TRANSPARENT} - a stage with a transparent background
  87  * and no decorations.</li>
  88  * <li>{@link StageStyle#UTILITY} - a stage with a solid white background and
  89  * minimal platform decorations.</li>
  90  * </ul>
  91  * <p>The style must be initialized before the stage is made visible.</p>
  92  * <p>On some platforms decorations might not be available. For example, on
  93  * some mobile or embedded devices. In these cases a request for a DECORATED or
  94  * UTILITY window will be accepted, but no decorations will be shown. </p>
  95  * 
  96  * <p><b>Owner</b></p>
  97  * <p>
  98  * A stage can optionally have an owner Window.
  99  * When a window is a stage's owner, it is said to be the parent of that stage.
 100  * When a parent window is closed, all its descendant windows are closed. 
 101  * The same chained behavior applied for a parent window that is iconified. 
 102  * A stage will always be on top of its parent window.
 103  * The owner must be initialized before the stage is made visible.
 104  *
 105  * <p><b>Modality</b></p>
 106  * <p>
 107  * A stage has one of the following modalities:
 108  * <ul>
 109  * <li>{@link Modality#NONE} - a stage that does not block any other window.</li>
 110  * <li>{@link Modality#WINDOW_MODAL} - a stage that blocks input events from 
 111  * being delivered to all windows from its owner (parent) to its root.
 112  * Its root is the closest ancestor window without an owner.</li>
 113  * <li>{@link Modality#APPLICATION_MODAL} - a stage that blocks input events from 
 114  * being delivered to all windows from the same application, except for those
 115  * from its child hierarchy.</li>
 116  * </ul> 
 117  * 
 118  * <p>When a window is blocked by a modal stage its Z-order relative to its ancestors
 119  * is preserved, and it receives no input events and no window activation events,
 120  * but continues to animate and render normally.
 121  * Note that showing a modal stage does not necessarily block the caller. The
 122  * {@link #show} method returns immediately regardless of the modality of the stage.
 123  * Use the {@link #showAndWait} method if you need to block the caller until
 124  * the modal stage is hidden (closed).
 125  * The modality must be initialized before the stage is made visible.</p> 
 126  *
 127  * <p><b>Example:</b></p>
 128  *
 129  *
 130 <pre><code>
 131 import javafx.application.Application;
 132 import javafx.scene.Group;
 133 import javafx.scene.Scene;
 134 import javafx.scene.text.Font;
 135 import javafx.scene.text.Text;
 136 import javafx.stage.Stage;
 137 
 138 public class HelloWorld extends Application {
 139 
 140     &#64;Override public void start(Stage stage) {
 141         Text text = new Text(10, 40, "Hello World!");
 142         text.setFont(new Font(40));
 143         Scene scene = new Scene(new Group(text));
 144 
 145         stage.setTitle("Welcome to JavaFX!"); 
 146         stage.setScene(scene); 
 147         stage.sizeToScene(); 
 148         stage.show(); 
 149     }
 150 
 151     public static void main(String[] args) {
 152         Application.launch(args);
 153     }
 154 }
 155 
 156  * </code></pre>
 157  * <p>produces the following on Windows:</p>
 158  * <p><img src="doc-files/Stage-win.png"/></p>
 159  *
 160  * <p>produces the following on Mac OSX:</p>
 161  * <p><img src="doc-files/Stage-mac.png"/></p>
 162  *
 163  * <p>produces the following on Linux:</p>
 164  * <p><img src="doc-files/Stage-linux.png"/></p>
 165  * @since JavaFX 2.0
 166  */
 167 public class Stage extends Window {
 168 
 169     private boolean inNestedEventLoop = false;
 170 
 171     private static ObservableList<Stage> stages = FXCollections.<Stage>observableArrayList();
 172 
 173     static {
 174         FXRobotHelper.setStageAccessor(new FXRobotHelper.FXRobotStageAccessor() {
 175             @Override public ObservableList<Stage> getStages() {
 176                 return stages;
 177             }
 178         });
 179         StageHelper.setStageAccessor(new StageHelper.StageAccessor() {
 180             @Override public ObservableList<Stage> getStages() {
 181                 return stages;
 182             }
 183             @Override public void initSecurityDialog(Stage stage, boolean securityDialog) {
 184                 stage.initSecurityDialog(securityDialog);
 185             }
 186         });
 187     }
 188     
 189     private static final StagePeerListener.StageAccessor STAGE_ACCESSOR = new StagePeerListener.StageAccessor() {
 190 
 191         @Override
 192         public void setIconified(Stage stage, boolean iconified) {
 193             stage.iconifiedPropertyImpl().set(iconified);
 194         }
 195 
 196         @Override
 197         public void setMaximized(Stage stage, boolean maximized) {
 198             stage.maximizedPropertyImpl().set(maximized);
 199         }
 200 
 201         @Override
 202         public void setResizable(Stage stage, boolean resizable) {
 203             ((ResizableProperty)stage.resizableProperty()).setNoInvalidate(resizable);
 204         }
 205 
 206         @Override
 207         public void setFullScreen(Stage stage, boolean fs) {
 208             stage.fullScreenPropertyImpl().set(fs);
 209         }
 210 
 211         @Override
 212         public void setAlwaysOnTop(Stage stage, boolean aot) {
 213             stage.alwaysOnTopPropertyImpl().set(aot);
 214         }
 215     };
 216 
 217     /**
 218      * Creates a new instance of decorated {@code Stage}.
 219      *
 220      * @throws IllegalStateException if this constructor is called on a thread
 221      * other than the JavaFX Application Thread.
 222      */
 223     public Stage() {
 224         this(StageStyle.DECORATED);
 225     }
 226 
 227     /**
 228      * Creates a new instance of {@code Stage}.
 229      *
 230      * @param style The style of the {@code Stage}
 231      *
 232      * @throws IllegalStateException if this constructor is called on a thread
 233      * other than the JavaFX Application Thread.
 234      */
 235     public Stage(@Default("javafx.stage.StageStyle.DECORATED") StageStyle style) {
 236         super();
 237 
 238         Toolkit.getToolkit().checkFxUserThread();
 239 
 240         // Set the style
 241         initStyle(style);
 242     }
 243     
 244     /**
 245      * Specify the scene to be used on this stage.
 246      */
 247     @Override final public void setScene(Scene value) {
 248         Toolkit.getToolkit().checkFxUserThread();
 249         super.setScene(value);
 250     }
 251 
 252     /**
 253      * @inheritDoc
 254      */
 255     @Override public final void show() {
 256         super.show();
 257     }
 258     
 259     private boolean primary = false;
 260 
 261     ////////////////////////////////////////////////////////////////////
 262 
 263     // Flag indicating that this stage is being used to show a security dialog
 264     private boolean securityDialog = false;
 265 
 266     /**
 267      * Sets a flag indicating that this stage is used for a security dialog and
 268      * must always be on top. If set, this will cause the window to be always
 269      * on top, regardless of the setting of the alwaysOnTop property, and
 270      * whether or not all permissions are granted when the dialog is shown.
 271      * NOTE: this flag must be set prior to showing the stage the first time.
 272      *
 273      * @param securityDialog flag indicating that this Stage is being used to
 274      * show a security dialog that should be always-on-top
 275      *
 276      * @throws IllegalStateException if this property is set after the stage
 277      * has ever been made visible.
 278      *
 279      * @defaultValue false
 280      */
 281     final void initSecurityDialog(boolean securityDialog) {
 282         if (hasBeenVisible) {
 283             throw new IllegalStateException("Cannot set securityDialog once stage has been set visible");
 284         }
 285 
 286         this.securityDialog = securityDialog;
 287     }
 288 
 289     /**
 290      * Returns the state of the securityDialog flag.
 291      *
 292      * @return a flag indicating whether or not this is a security dialog
 293      */
 294     final boolean isSecurityDialog() {
 295         return securityDialog;
 296     }
 297 
 298     /**
 299      * sets this stage to be the primary stage.
 300      * When run as an applet, this stage will appear in the broswer
 301      * @treatAsPrivate implementation detail
 302      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 303      */
 304     @Deprecated
 305     public void impl_setPrimary(boolean primary) {
 306         this.primary = primary;
 307     }
 308 
 309     /**
 310      * Returns whether this stage is the primary stage.
 311      * When run as an applet, the primary stage will appear in the broswer
 312      *
 313      * @return true if this stage is the primary stage for the application.
 314      */
 315     boolean isPrimary() {
 316         return primary;
 317     }
 318     
 319     /**
 320      * @treatAsPrivate implementation detail
 321      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 322      */
 323     @Deprecated
 324     @Override
 325     public String impl_getMXWindowType() {
 326         return (primary) ? "PrimaryStage" : getClass().getSimpleName();
 327     }
 328 
 329     private boolean important = true;
 330 
 331     /**
 332      * Sets a flag indicating whether this stage is an "important" window for
 333      * the purpose of determining whether the application is idle and should
 334      * exit. The application is considered finished when the last important
 335      * window is closed.
 336      * @treatAsPrivate implementation detail
 337      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 338      */
 339     @Deprecated
 340     public void impl_setImportant(boolean important) {
 341         this.important = important;
 342     }
 343 
 344     private boolean isImportant() {
 345         return important;
 346     }
 347 
 348     /**
 349      * Shows this stage and waits for it to be hidden (closed) before returning
 350      * to the caller. This method temporarily blocks processing of the current
 351      * event, and starts a nested event loop to handle other events.
 352      * This method must be called on the FX Application thread.
 353      * <p>
 354      * A Stage is hidden (closed) by one of the following means:
 355      * <ul>
 356      * <li>the application calls the {@link #hide} or {@link #close} method on
 357      * this stage</li>
 358      * <li>this stage has a non-null owner window, and its owner is closed</li>
 359      * <li>the user closes the window via the window system (for example,
 360      * by pressing the close button in the window decoration)</li>
 361      * </ul>
 362      * </p>
 363      *
 364      * <p>
 365      * After the Stage is hidden, and the application has returned from the
 366      * event handler to the event loop, the nested event loop terminates
 367      * and this method returns to the caller.
 368      * </p>
 369      * <p>
 370      * For example, consider the following sequence of operations for different
 371      * event handlers, assumed to execute in the order shown below:
 372      * <pre>void evtHander1(...) {
 373      *     stage1.showAndWait();
 374      *     doSomethingAfterStage1Closed(...)
 375      * }
 376      *
 377      * void evtHander2(...) {
 378      *     stage1.hide();
 379      *     doSomethingElseHere(...)
 380      * }</pre>
 381      * evtHandler1 will block at the call to showAndWait. It will resume execution
 382      * after stage1 is hidden and the current event handler, in this case evtHandler2,
 383      * returns to the event loop. This means that doSomethingElseHere will
 384      * execute before doSomethingAfterStage1Closed.
 385      * </p>
 386      *
 387      * <p>
 388      * More than one stage may be shown with showAndWait. Each call
 389      * will start a new nested event loop. The stages may be hidden in any order,
 390      * but a particular nested event loop (and thus the showAndWait method
 391      * for the associated stage) will only terminate after all inner event loops
 392      * have also terminated.
 393      * </p>
 394      * <p>
 395      * For example, consider the following sequence of operations for different
 396      * event handlers, assumed to execute in the order shown below:
 397      * <ul>
 398      * <pre>void evtHander1() {
 399      *     stage1.showAndWait();
 400      *     doSomethingAfterStage1Closed(...)
 401      * }
 402      *
 403      * void evtHander2() {
 404      *     stage2.showAndWait();
 405      *     doSomethingAfterStage2Closed(...)
 406      * }
 407      *
 408      * void evtHander3() {
 409      *     stage1.hide();
 410      *     doSomethingElseHere(...)
 411      * }
 412      *
 413      * void evtHander4() {
 414      *     stage2.hide();
 415      *     doSomethingElseHereToo(...)
 416      * }</pre>
 417      * </ul>
 418      * evtHandler1 will block at the call to stage1.showAndWait, starting up
 419      * a nested event loop just like in the previous example. evtHandler2 will
 420      * then block at the call to stage2.showAndWait, starting up another (inner)
 421      * nested event loop. The first call to stage1.showAndWait will resume execution
 422      * after stage1 is hidden, but only after the inner nested event loop started
 423      * by stage2.showAndWait has terminated. This means that the call to
 424      * stage1.showAndWait won't return until after evtHandler2 has returned.
 425      * The order of execution is: stage1.showAndWait, stage2.showAndWait,
 426      * stage1.hide, doSomethingElseHere, stage2.hide, doSomethingElseHereToo,
 427      * doSomethingAfterStage2Closed, doSomethingAfterStage1Closed.
 428      * </p>
 429      *
 430      * <p>
 431      * This method must not be called on the primary stage or on a stage that
 432      * is already visible.
 433      * </p>
 434      *
 435      * @throws IllegalStateException if this method is called on a thread
 436      *     other than the JavaFX Application Thread.
 437      * @throws java.lang.IllegalStateException if this method is called outside of
 438      *     event handler. This includes animation callbacks, properties handlers and layout processing.
 439      * @throws IllegalStateException if this method is called on the
 440      *     primary stage.
 441      * @throws IllegalStateException if this stage is already showing.
 442      * @since JavaFX 2.2
 443      */
 444     public void showAndWait() {
 445 
 446         Toolkit.getToolkit().checkFxUserThread();
 447 
 448         if (isPrimary()) {
 449             throw new IllegalStateException("Cannot call this method on primary stage");
 450         }
 451 
 452         if (isShowing()) {
 453             throw new IllegalStateException("Stage already visible");
 454         }
 455 
 456         // TODO: file a new bug; the following assertion can fail if this
 457         // method is called from an event handler that is listening to a
 458         // WindowEvent.WINDOW_HIDING event.
 459         assert !inNestedEventLoop;
 460 
 461         show();
 462         inNestedEventLoop = true;
 463         Toolkit.getToolkit().enterNestedEventLoop(this);
 464     }
 465 
 466     private StageStyle style; // default is set in constructor
 467 
 468     /**
 469      * Specifies the style for this stage. This must be done prior to making
 470      * the stage visible. The style is one of: StageStyle.DECORATED,
 471      * StageStyle.UNDECORATED, StageStyle.TRANSPARENT, or StageStyle.UTILITY.
 472      *
 473      * @param style the style for this stage.
 474      *
 475      * @throws IllegalStateException if this property is set after the stage
 476      * has ever been made visible.
 477      *
 478      * @defaultValue StageStyle.DECORATED
 479      */
 480     public final void initStyle(StageStyle style) {
 481         if (hasBeenVisible) {
 482             throw new IllegalStateException("Cannot set style once stage has been set visible");
 483         }
 484         this.style = style;
 485     }
 486 
 487     /**
 488      * Retrieves the style attribute for this stage.
 489      *
 490      * @return the stage style.
 491      */
 492     public final StageStyle getStyle() {
 493         return style;
 494     }
 495 
 496     private Modality modality = Modality.NONE;
 497 
 498     /**
 499      * Specifies the modality for this stage. This must be done prior to making
 500      * the stage visible. The modality is one of: Modality.NONE,
 501      * Modality.WINDOW_MODAL, or Modality.APPLICATION_MODAL.
 502      *
 503      * @param modality the modality for this stage.
 504      *
 505      * @throws IllegalStateException if this property is set after the stage
 506      * has ever been made visible.
 507      *
 508      * @throws IllegalStateException if this stage is the primary stage.
 509      *
 510      * @defaultValue Modality.NONE
 511      */
 512     public final void initModality(Modality modality) {
 513         if (hasBeenVisible) {
 514             throw new IllegalStateException("Cannot set modality once stage has been set visible");
 515         }
 516 
 517         if (isPrimary()) {
 518             throw new IllegalStateException("Cannot set modality for the primary stage");
 519         }
 520 
 521         this.modality = modality;
 522     }
 523 
 524     /**
 525      * Retrieves the modality attribute for this stage.
 526      *
 527      * @return the modality.
 528      */
 529     public final Modality getModality() {
 530         return modality;
 531     }
 532 
 533     private Window owner = null;
 534 
 535     /**
 536      * Specifies the owner Window for this stage, or null for a top-level,
 537      * unowned stage. This must be done prior to making the stage visible.
 538      *
 539      * @param owner the owner for this stage.
 540      *
 541      * @throws IllegalStateException if this property is set after the stage
 542      * has ever been made visible.
 543      *
 544      * @throws IllegalStateException if this stage is the primary stage.
 545      *
 546      * @defaultValue null
 547      */
 548     public final void initOwner(Window owner) {
 549         if (hasBeenVisible) {
 550             throw new IllegalStateException("Cannot set owner once stage has been set visible");
 551         }
 552 
 553         if (isPrimary()) {
 554             throw new IllegalStateException("Cannot set owner for the primary stage");
 555         }
 556 
 557         final Scene sceneValue = getScene();
 558         if (sceneValue != null) {
 559             this.owner = owner;
 560             SceneHelper.parentEffectiveOrientationInvalidated(sceneValue);
 561         }
 562     }
 563 
 564     /**
 565      * Retrieves the owner Window for this stage, or null for an unowned stage.
 566      *
 567      * @return the owner Window.
 568      */
 569     public final Window getOwner() {
 570         return owner;
 571     }
 572 
 573     /**
 574      * Specifies whether this {@code Stage} should be a full-screen,
 575      * undecorated window.
 576      * <p>
 577      * The implementation of full-screen mode is platform and profile-dependent.
 578      * </p>
 579      * <p>
 580      * When set to {@code true}, the {@code Stage} will attempt to enter
 581      * full-screen mode when visible. Set to {@code false} to return {@code Stage}
 582      * to windowed mode.
 583      * An {@link IllegalStateException} is thrown if this property is set
 584      * on a thread other than the JavaFX Application Thread.
 585      * </p>
 586      * <p>
 587      * The full-screen mode will be exited (and the {@code fullScreen} attribute
 588      * will be set to {@code false}) if the full-screen
 589      * {@code Stage} loses focus or if another {@code Stage} enters
 590      * full-screen mode on the same {@link Screen}. Note that a {@code Stage}
 591      * in full-screen mode can become invisible without losing its
 592      * full-screen status and will again enter full-screen mode when the
 593      * {@code Stage} becomes visible.
 594      * </p>
 595      * If the platform supports multiple screens an application can control
 596      * which {@code Screen} the Stage will enter full-screen mode on by
 597      * setting its position to be within the bounds of that {@code Screen}
 598      * prior to entering full-screen mode.
 599      * <p>
 600      * However once in full-screen mode, {@code Stage}'s {@code x}, {@code y},
 601      * {@code width}, and {@code height} variables will continue to represent
 602      * the non-full-screen position and size of the window; the same for
 603      * {@code iconified}, {@code resizable}, {@code style}, and {@code
 604      * opacity}. If changes are made to any of these attributes while in
 605      * full-screen mode, upon exiting full-screen mode the {@code Stage} will
 606      * assume those attributes.
 607      * </p>
 608      * <p>
 609      * In case that more {@code Stage} modes are set simultaneously their order
 610      * of importance is {@code iconified}, fullScreen, {@code maximized} (from
 611      * strongest to weakest).
 612      * </p>
 613      * <p>
 614      * The property is read only because it can be changed externally
 615      * by the underlying platform and therefore must not be bindable.
 616      * </p>
 617      *
 618      * Notes regarding desktop profile implementation.
 619      * <p>
 620      * For desktop profile the runtime will attempt to enter full-screen
 621      * exclusive mode (FSEM) if such is supported by the platform and it is
 622      * allowed for this application. If either is not the case a
 623      * simulated full-screen window will be used instead; the window will be
 624      * maximized, made undecorated if possible, and moved to the front.
 625      * </p>
 626      * For desktop profile the user can unconditionally exit full-screen mode
 627      * at any time by pressing {@code ESC}.
 628      * <p>
 629      * There are differences in behavior between applications if a security 
 630      * manager is present. Applications with permissions are allowed to enter 
 631      * full-screen exclusive mode unrestricted. Applications without the proper 
 632      * permissions will have the following restrictions:
 633      * </p>
 634      * <ul>
 635      *  <li>Applications can only enter FSEM in response
 636      *   to user input. More specifically, entering is allowed from mouse
 637      *   ({@code Node.mousePressed/mouseReleased/mouseClicked}) or keyboard
 638      *   ({@code Node.keyPressed/keyReleased/keyTyped}) event handlers. It is
 639      *   not allowed to enter FSEM in response to {@code ESC}
 640      *   key. Attempting to enter FSEM from any other context will result in
 641      *   emulated full-screen mode.
 642      *   <p>
 643      *   If {@code Stage} was constructed as full-screen but not visible
 644      *   it will enter full-screen mode upon becoming visible, with the same
 645      *   limitations to when this is allowed to happen as when setting
 646      *   {@code fullScreen} to {@code true}.
 647      *   </p>
 648      *  </li>
 649      *  <li> If the application was allowed to enter FSEM
 650      *   it will have limited keyboard input. It will only receive KEY_PRESSED
 651      *   and KEY_RELEASED events from the following keys:
 652      *   {@code UP, DOWN, LEFT, RIGHT, SPACE, TAB, PAGE_UP, PAGE_DOWN, HOME, END, ENTER}
 653      *  </li>
 654      * </ul>
 655      * @defaultValue false
 656      */
 657     private ReadOnlyBooleanWrapper fullScreen;
 658 
 659     public final void setFullScreen(boolean value) {
 660         Toolkit.getToolkit().checkFxUserThread();
 661         fullScreenPropertyImpl().set(value);
 662         if (impl_peer != null)
 663             impl_peer.setFullScreen(value);
 664     }
 665 
 666     public final boolean isFullScreen() {
 667         return fullScreen == null ? false : fullScreen.get();
 668     }
 669 
 670     public final ReadOnlyBooleanProperty fullScreenProperty() {
 671         return fullScreenPropertyImpl().getReadOnlyProperty();
 672     }
 673 
 674     private ReadOnlyBooleanWrapper fullScreenPropertyImpl () {
 675         if (fullScreen == null) {
 676             fullScreen = new ReadOnlyBooleanWrapper(Stage.this, "fullScreen");
 677         }
 678         return fullScreen;
 679     }
 680 
 681     /**
 682      * Defines the icon images to be used in the window decorations and when
 683      * minimized. The images should be different sizes of the same image and
 684      * the best size will be chosen, eg. 16x16, 32,32.
 685      *
 686      * @defaultValue empty
 687      */
 688     private ObservableList<Image> icons = new TrackableObservableList<Image>() {
 689         @Override protected void onChanged(Change<Image> c) {
 690             List<Object> platformImages = new ArrayList<Object>();
 691             for (Image icon : icons) {
 692                 platformImages.add(icon.impl_getPlatformImage());
 693             }
 694             if (impl_peer != null) {
 695                 impl_peer.setIcons(platformImages);
 696             }
 697         }
 698     };
 699 
 700     /**
 701      * Gets the icon images to be used in the window decorations and when
 702      * minimized. The images should be different sizes of the same image and
 703      * the best size will be chosen, eg. 16x16, 32,32.
 704      * @return An observable list of icons of this window
 705      */
 706     public final ObservableList<Image> getIcons() {
 707         return icons;
 708     }
 709 
 710     /**
 711      * Defines the title of the {@code Stage}.
 712      *
 713      * @defaultValue empty string
 714      */
 715     private StringProperty title;
 716 
 717     public final void setTitle(String value) {
 718         titleProperty().set(value);
 719     }
 720 
 721     public final String getTitle() {
 722         return title == null ? null : title.get();
 723     }
 724 
 725     public final StringProperty titleProperty() {
 726         if (title == null) {
 727             title = new StringPropertyBase() {
 728 
 729                 @Override
 730                 protected void invalidated() {
 731                     if (impl_peer != null) {
 732                         impl_peer.setTitle(get());
 733                     }
 734                 }
 735 
 736                 @Override
 737                 public Object getBean() {
 738                     return Stage.this;
 739                 }
 740 
 741                 @Override
 742                 public String getName() {
 743                     return "title";
 744                 }
 745             };
 746         }
 747         return title;
 748     }
 749 
 750     /**
 751      * Defines whether the {@code Stage} is iconified or not.
 752      * <p>
 753      * In case that more {@code Stage} modes are set simultaneously their order
 754      * of importance is iconified} {@code fullScreen}, {@code maximized} (from
 755      * strongest to weakest).
 756      * </p>
 757      * <p>
 758      * On some mobile and embedded platforms setting this property to true will
 759      * hide the {@code Stage} but not show an icon for it.
 760      * </p>
 761      * <p>
 762      * The property is read only because it can be changed externally
 763      * by the underlying platform and therefore must not be bindable.
 764      * </p>
 765      *
 766      * @defaultValue false
 767      */
 768     private ReadOnlyBooleanWrapper iconified;
 769 
 770     public final void setIconified(boolean value) {
 771         iconifiedPropertyImpl().set(value);
 772         if (impl_peer != null)
 773             impl_peer.setIconified(value);
 774     }
 775 
 776     public final boolean isIconified() {
 777         return iconified == null ? false : iconified.get();
 778     }
 779 
 780     public final ReadOnlyBooleanProperty iconifiedProperty() {
 781         return iconifiedPropertyImpl().getReadOnlyProperty();
 782     }
 783 
 784     private final ReadOnlyBooleanWrapper iconifiedPropertyImpl() {
 785         if (iconified == null) {
 786             iconified = new ReadOnlyBooleanWrapper(Stage.this, "iconified");
 787         }
 788         return iconified;
 789     }
 790 
 791     /**
 792      * Defines whether the {@code Stage} is maximized or not.
 793      * <p>
 794      * In case that more {@code Stage} modes are set simultaneously their order
 795      * of importance is {@code iconified}, {@code fullScreen}, maximized (from
 796      * strongest to weakest).
 797      * </p>
 798      * <p>
 799      * The property is read only because it can be changed externally
 800      * by the underlying platform and therefore must not be bindable.
 801      * </p>
 802      *
 803      * @defaultValue false
 804      * @since JavaFX 8.0
 805      */
 806     private ReadOnlyBooleanWrapper maximized;
 807 
 808     public final void setMaximized(boolean value) {
 809         maximizedPropertyImpl().set(value);
 810         if (impl_peer != null)
 811             impl_peer.setMaximized(value);
 812     }
 813 
 814     public final boolean isMaximized() {
 815         return maximized == null ? false : maximized.get();
 816     }
 817 
 818     public final ReadOnlyBooleanProperty maximizedProperty() {
 819         return maximizedPropertyImpl().getReadOnlyProperty();
 820     }
 821 
 822     private final ReadOnlyBooleanWrapper maximizedPropertyImpl() {
 823         if (maximized == null) {
 824             maximized = new ReadOnlyBooleanWrapper(Stage.this, "maximized");
 825         }
 826         return maximized;
 827     }
 828     
 829     /**
 830      * Defines whether this {@code Stage} is kept on top of other windows.
 831      * <p>
 832      * If some other window is already always-on-top then the
 833      * relative order between these windows is unspecified (depends on
 834      * platform).
 835      * </p>
 836      * <p>
 837      * There are differences in behavior between applications if a security 
 838      * manager is present. Applications with permissions are allowed to set
 839      * "always on top" flag on a Stage. In applications without the proper 
 840      * permissions, an attempt to set the flag will be ignored and the property
 841      * value will be restored to "false".
 842      * </p>
 843      * <p>
 844      * The property is read only because it can be changed externally
 845      * by the underlying platform and therefore must not be bindable.
 846      * </p>
 847      * 
 848      * @defaultValue false
 849      * @since JavaFX 8u20
 850      */
 851     private ReadOnlyBooleanWrapper alwaysOnTop;
 852     
 853     public final void setAlwaysOnTop(boolean value) {
 854         alwaysOnTopPropertyImpl().set(value);
 855         if (impl_peer != null) {
 856             impl_peer.setAlwaysOnTop(value);
 857         }
 858     }
 859 
 860     public final boolean isAlwaysOnTop() {
 861         return alwaysOnTop == null ? false : alwaysOnTop.get();
 862     }
 863 
 864     public final ReadOnlyBooleanProperty alwaysOnTopProperty() {
 865         return alwaysOnTopPropertyImpl().getReadOnlyProperty();
 866     }
 867 
 868     private ReadOnlyBooleanWrapper alwaysOnTopPropertyImpl() {
 869         if (alwaysOnTop == null) {
 870             alwaysOnTop = new ReadOnlyBooleanWrapper(Stage.this, "alwaysOnTop");
 871         }
 872         return alwaysOnTop;
 873     }
 874 
 875     /**
 876      * Defines whether the {@code Stage} is resizable or not by the user.
 877      * Programatically you may still change the size of the Stage. This is
 878      * a hint which allows the implementation to optionally make the Stage
 879      * resizable by the user.
 880      * <p>
 881      * <b>Warning:</b> Since 8.0 the property cannot be bound and will throw
 882      * {@code RuntimeException} on an attempt to do so. This is because
 883      * the setting of resizable is asynchronous on some systems or generally
 884      * might be set by the system / window manager.
 885      * <br>
 886      * Bidirectional binds are still allowed, as they don't block setting of the
 887      * property by the system.
 888      * 
 889      * @defaultValue true
 890      */
 891     private BooleanProperty resizable;
 892 
 893     public final void setResizable(boolean value) {
 894         resizableProperty().set(value);
 895     }
 896 
 897     public final boolean isResizable() {
 898         return resizable == null ? true : resizable.get();
 899     }
 900 
 901     public final BooleanProperty resizableProperty() {
 902         if (resizable == null) {
 903             resizable = new ResizableProperty();
 904         }
 905         return resizable;
 906     }
 907 
 908     //We cannot return ReadOnlyProperty in resizable, as this would be
 909     // backward incompatible. All we can do is to create this custom property
 910     // implementation that disallows binds
 911     private class ResizableProperty extends SimpleBooleanProperty {
 912         private boolean noInvalidate;
 913 
 914         public ResizableProperty() {
 915             super(Stage.this, "resizable", true);
 916         }
 917 
 918         void setNoInvalidate(boolean value) {
 919             noInvalidate = true;
 920             set(value);
 921             noInvalidate = false;
 922         }
 923 
 924         @Override
 925         protected void invalidated() {
 926             if (noInvalidate) {
 927                 return;
 928             }
 929             if (impl_peer != null) {
 930                 applyBounds();
 931                 impl_peer.setResizable(get());
 932             }
 933         }
 934 
 935         @Override
 936         public void bind(ObservableValue<? extends Boolean> rawObservable) {
 937             throw new RuntimeException("Resizable property cannot be bound");
 938         }
 939 
 940     }
 941 
 942     /**
 943      * Defines the minimum width of this {@code Stage}.
 944      *
 945      * @defaultValue 0
 946      * @since JavaFX 2.1
 947      */
 948     private DoubleProperty minWidth;
 949 
 950     public final void setMinWidth(double value) {
 951         minWidthProperty().set(value);
 952     }
 953 
 954     public final double getMinWidth() {
 955         return minWidth == null ? 0 : minWidth.get();
 956     }
 957 
 958     public final DoubleProperty minWidthProperty() {
 959         if (minWidth == null) {
 960             minWidth = new DoublePropertyBase(0) {
 961 
 962                 @Override
 963                 protected void invalidated() {
 964                     if (impl_peer != null) {
 965                         impl_peer.setMinimumSize((int) Math.ceil(get()),
 966                                 (int) Math.ceil(getMinHeight()));
 967                     }
 968                     if (getWidth() < getMinWidth()) {
 969                         setWidth(getMinWidth());
 970                     }
 971                 }
 972 
 973                 @Override
 974                 public Object getBean() {
 975                     return Stage.this;
 976                 }
 977 
 978                 @Override
 979                 public String getName() {
 980                     return "minWidth";
 981                 }
 982             };
 983         }
 984         return minWidth;
 985     }
 986 
 987     /**
 988      * Defines the minimum height of this {@code Stage}.
 989      *
 990      * @defaultValue 0
 991      * @since JavaFX 2.1
 992      */
 993     private DoubleProperty minHeight;
 994 
 995     public final void setMinHeight(double value) {
 996         minHeightProperty().set(value);
 997     }
 998 
 999     public final double getMinHeight() {
1000         return minHeight == null ? 0 : minHeight.get();
1001     }
1002 
1003     public final DoubleProperty minHeightProperty() {
1004         if (minHeight == null) {
1005             minHeight = new DoublePropertyBase(0) {
1006 
1007                 @Override
1008                 protected void invalidated() {
1009                     if (impl_peer != null) {
1010                         impl_peer.setMinimumSize(
1011                                 (int) Math.ceil(getMinWidth()),
1012                                 (int) Math.ceil(get()));
1013                     }
1014                     if (getHeight() < getMinHeight()) {
1015                         setHeight(getMinHeight());
1016                     }
1017                 }
1018 
1019                 @Override
1020                 public Object getBean() {
1021                     return Stage.this;
1022                 }
1023 
1024                 @Override
1025                 public String getName() {
1026                     return "minHeight";
1027                 }
1028             };
1029         }
1030         return minHeight;
1031     }
1032 
1033     /**
1034      * Defines the maximum width of this {@code Stage}.
1035      *
1036      * @defaultValue Double.MAX_VALUE
1037      * @since JavaFX 2.1
1038      */
1039     private DoubleProperty maxWidth;
1040 
1041     public final void setMaxWidth(double value) {
1042         maxWidthProperty().set(value);
1043     }
1044 
1045     public final double getMaxWidth() {
1046         return maxWidth == null ? Double.MAX_VALUE : maxWidth.get();
1047     }
1048 
1049     public final DoubleProperty maxWidthProperty() {
1050         if (maxWidth == null) {
1051             maxWidth = new DoublePropertyBase(Double.MAX_VALUE) {
1052 
1053                 @Override
1054                 protected void invalidated() {
1055                     if (impl_peer != null) {
1056                         impl_peer.setMaximumSize((int) Math.floor(get()),
1057                                 (int) Math.floor(getMaxHeight()));
1058                     }
1059                     if (getWidth() > getMaxWidth()) {
1060                         setWidth(getMaxWidth());
1061                     }
1062                 }
1063 
1064                 @Override
1065                 public Object getBean() {
1066                     return Stage.this;
1067                 }
1068 
1069                 @Override
1070                 public String getName() {
1071                     return "maxWidth";
1072                 }
1073             };
1074         }
1075         return maxWidth;
1076     }
1077 
1078     /**
1079      * Defines the maximum height of this {@code Stage}.
1080      *
1081      * @defaultValue Double.MAX_VALUE
1082      * @since JavaFX 2.1
1083      */
1084     private DoubleProperty maxHeight;
1085 
1086     public final void setMaxHeight(double value) {
1087         maxHeightProperty().set(value);
1088     }
1089 
1090     public final double getMaxHeight() {
1091         return maxHeight == null ? Double.MAX_VALUE : maxHeight.get();
1092     }
1093 
1094     public final DoubleProperty maxHeightProperty() {
1095         if (maxHeight == null) {
1096             maxHeight = new DoublePropertyBase(Double.MAX_VALUE) {
1097 
1098                 @Override
1099                 protected void invalidated() {
1100                     if (impl_peer != null) {
1101                         impl_peer.setMaximumSize(
1102                                 (int) Math.floor(getMaxWidth()),
1103                                 (int) Math.floor(get()));
1104                     }
1105                     if (getHeight() > getMaxHeight()) {
1106                         setHeight(getMaxHeight());
1107                     }
1108                 }
1109 
1110                 @Override
1111                 public Object getBean() {
1112                     return Stage.this;
1113                 }
1114 
1115                 @Override
1116                 public String getName() {
1117                     return "maxHeight";
1118                 }
1119             };
1120         }
1121         return maxHeight;
1122     }
1123 
1124     
1125     /**
1126      * @treatAsPrivate implementation detail
1127      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1128      */
1129     @Deprecated
1130     @Override protected void impl_visibleChanging(boolean value) {
1131         super.impl_visibleChanging(value);
1132         Toolkit toolkit = Toolkit.getToolkit();
1133         if (value && (impl_peer == null)) {
1134             // Setup the peer
1135             Window window = getOwner();
1136             TKStage tkStage = (window == null ? null : window.impl_getPeer());
1137             Scene scene = getScene();
1138             boolean rtl = scene != null && scene.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT;
1139 
1140             StageStyle stageStyle = getStyle();
1141             if (stageStyle == StageStyle.TRANSPARENT) {
1142                 final SecurityManager securityManager =
1143                         System.getSecurityManager();
1144                 if (securityManager != null) {
1145                     try {
1146                         securityManager.checkPermission(new AllPermission());
1147                     } catch (final SecurityException e) {
1148                         stageStyle = StageStyle.UNDECORATED;
1149                     }
1150                 }
1151             }
1152             impl_peer = toolkit.createTKStage(this, isSecurityDialog(), stageStyle, isPrimary(),
1153                                               getModality(), tkStage, rtl, acc);
1154             impl_peer.setMinimumSize((int) Math.ceil(getMinWidth()),
1155                     (int) Math.ceil(getMinHeight()));
1156             impl_peer.setMaximumSize((int) Math.floor(getMaxWidth()),
1157                     (int) Math.floor(getMaxHeight()));
1158             peerListener = new StagePeerListener(this, STAGE_ACCESSOR);
1159            // Insert this into stages so we have a references to all created stages
1160             stages.add(this);
1161         }
1162     }
1163 
1164     
1165     /**
1166      * @treatAsPrivate implementation detail
1167      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1168      */
1169     @Deprecated
1170     @Override protected void impl_visibleChanged(boolean value) {
1171         super.impl_visibleChanged(value);
1172 
1173         if (value) {
1174             // Finish initialization
1175             impl_peer.setImportant(isImportant());
1176             impl_peer.setResizable(isResizable());
1177             impl_peer.setFullScreen(isFullScreen());
1178             impl_peer.setAlwaysOnTop(isAlwaysOnTop());
1179             impl_peer.setIconified(isIconified());
1180             impl_peer.setMaximized(isMaximized());
1181             impl_peer.setTitle(getTitle());
1182 
1183             List<Object> platformImages = new ArrayList<Object>();
1184             for (Image icon : icons) {
1185                 platformImages.add(icon.impl_getPlatformImage());
1186             }
1187             if (impl_peer != null) {
1188                 impl_peer.setIcons(platformImages);
1189             }
1190         }
1191 
1192         if (!value) {
1193             // Remove form active stage list
1194             stages.remove(this);
1195         }
1196 
1197         if (!value && inNestedEventLoop) {
1198             inNestedEventLoop = false;
1199             Toolkit.getToolkit().exitNestedEventLoop(this, null);
1200         }
1201     }
1202 
1203     /**
1204      * Bring the {@code Window} to the foreground.  If the {@code Window} is
1205      * already in the foreground there is no visible difference.
1206      */
1207     public void toFront() {
1208         if (impl_peer != null) {
1209             impl_peer.toFront();
1210         }
1211     }
1212 
1213     /**
1214      * Send the {@code Window} to the background.  If the {@code Window} is
1215      * already in the background there is no visible difference.  This action
1216      * places this {@code Window} at the bottom of the stacking order on
1217      * platforms that support stacking.
1218      */
1219     public void toBack() {
1220         if (impl_peer != null) {
1221             impl_peer.toBack();
1222         }
1223     }
1224 
1225     /**
1226      * Closes this {@code Stage}.
1227      * This call is equivalent to {@code hide()}.
1228      */
1229     public void close() {
1230         hide();
1231     }
1232 
1233     @Override
1234     Window getWindowOwner() {
1235         return getOwner();
1236     }
1237 
1238     
1239     private final ObjectProperty<KeyCombination> fullScreenExitCombination =
1240             new SimpleObjectProperty<KeyCombination>(this, "fullScreenExitCombination", null);
1241 
1242     /**
1243      * Specifies the KeyCombination that will allow the user to exit full screen
1244      * mode. A value of KeyCombination.NO_MATCH will not match any KeyEvent and
1245      * will make it so the user is not able to escape from Full Screen mode.
1246      * A value of null indicates that the default platform specific key combination
1247      * should be used. 
1248      * <p>
1249      * An internal copy of this value is made when entering FullScreen mode and will be 
1250      * used to trigger the exit from the mode. If an application does not have
1251      * the proper permissions, this setting will be ignored.
1252      * </p>
1253      * @param keyCombination the key combination to exit on
1254      * @since JavaFX 8.0 
1255      */
1256     public final void setFullScreenExitKeyCombination(KeyCombination keyCombination) {
1257         fullScreenExitCombination.set(keyCombination);
1258     }
1259 
1260     /**
1261      * Get the current sequence used to exit Full Screen mode.
1262      * @return the current setting (null for system default)
1263      * @since JavaFX 8.0 
1264      */
1265     public final KeyCombination getFullScreenExitKeyCombination() {
1266         return fullScreenExitCombination.get();
1267     }
1268 
1269     /**
1270      * Get the property for the Full Screen exit key combination.
1271      * @return the property.
1272      * @since JavaFX 8.0 
1273      */
1274     public final ObjectProperty<KeyCombination> fullScreenExitKeyProperty() {
1275         return fullScreenExitCombination;
1276     }
1277 
1278     private final ObjectProperty<String> fullScreenExitHint = 
1279             new SimpleObjectProperty<String>(this, "fullScreenExitHint", null);
1280                 
1281     /**
1282      * Specifies the text to show when a user enters full screen mode, usually
1283      * used to indicate the way a user should go about exiting out of full
1284      * screen mode. A value of null will result in the default per-locale
1285      * message being displayed. 
1286      * If set to the empty string, then no message will be displayed. 
1287      * <p>
1288      * If an application does not have the proper permissions, this setting 
1289      * will be ignored.
1290      * </p>
1291      * @param value the string to be displayed.
1292      * @since JavaFX 8.0 
1293      */
1294     public final void setFullScreenExitHint(String value) {
1295         fullScreenExitHint.set(value);
1296     }
1297 
1298     public final String getFullScreenExitHint() {
1299         return fullScreenExitHint.get();
1300     }
1301 
1302     public final ObjectProperty<String> fullScreenExitHintProperty() {
1303         return fullScreenExitHint;
1304     }
1305 }