/* * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javafx.stage; import java.util.ArrayList; import java.util.List; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.StringProperty; import javafx.beans.property.StringPropertyBase; import javafx.collections.ListChangeListener.Change; import javafx.collections.ObservableList; import javafx.geometry.NodeOrientation; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.input.KeyCombination; import com.sun.javafx.collections.VetoableListDecorator; import com.sun.javafx.collections.TrackableObservableList; import com.sun.javafx.scene.SceneHelper; import com.sun.javafx.stage.StageHelper; import com.sun.javafx.stage.StagePeerListener; import com.sun.javafx.tk.TKStage; import com.sun.javafx.tk.Toolkit; import static com.sun.javafx.FXPermissions.CREATE_TRANSPARENT_WINDOW_PERMISSION; import javafx.beans.NamedArg; import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoublePropertyBase; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; /** * The JavaFX {@code Stage} class is the top level JavaFX container. * The primary Stage is constructed by the platform. Additional Stage * objects may be constructed by the application. * *
* Stage objects must be constructed and modified on the * JavaFX Application Thread. *
** The JavaFX Application Thread is created as part of the startup process for * the JavaFX runtime. See the {@link javafx.application.Application} class and * the {@link Platform#startup(Runnable)} method for more information. *
** Many of the {@code Stage} properties are read only because they can * be changed externally by the underlying platform and therefore must * not be bindable. *
* *Style
** A stage has one of the following styles: *
The style must be initialized before the stage is made visible.
*On some platforms decorations might not be available. For example, on * some mobile or embedded devices. In these cases a request for a DECORATED or * UTILITY window will be accepted, but no decorations will be shown.
* *Owner
** A stage can optionally have an owner Window. * When a window is a stage's owner, it is said to be the parent of that stage. *
* Owned Stages are tied to the parent Window. * An owned stage will always be on top of its parent window. * When a parent window is closed or iconified, then all owned windows will be affected as well. * Owned Stages cannot be independantly iconified. *
* The owner must be initialized before the stage is made visible. * *
Modality
** A stage has one of the following modalities: *
When a window is blocked by a modal stage its Z-order relative to its ancestors * is preserved, and it receives no input events and no window activation events, * but continues to animate and render normally. * Note that showing a modal stage does not necessarily block the caller. The * {@link #show} method returns immediately regardless of the modality of the stage. * Use the {@link #showAndWait} method if you need to block the caller until * the modal stage is hidden (closed). * The modality must be initialized before the stage is made visible.
* *Example:
* *
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class HelloWorld extends Application {
{@literal @Override} public void start(Stage stage) {
Text text = new Text(10, 40, "Hello World!");
text.setFont(new Font(40));
Scene scene = new Scene(new Group(text));
stage.setTitle("Welcome to JavaFX!");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
*
* produces the following on Windows:
* * *produces the following on Mac OSX:
* * *produces the following on Linux:
* * @since JavaFX 2.0 */ public class Stage extends Window { private boolean inNestedEventLoop = false; static { StageHelper.setStageAccessor(new StageHelper.StageAccessor() { @Override public void doVisibleChanging(Window window, boolean visible) { ((Stage) window).doVisibleChanging(visible); } @Override public void doVisibleChanged(Window window, boolean visible) { ((Stage) window).doVisibleChanged(visible); } @Override public void initSecurityDialog(Stage stage, boolean securityDialog) { stage.initSecurityDialog(securityDialog); } @Override public void setPrimary(Stage stage, boolean primary) { stage.setPrimary(primary); } @Override public void setImportant(Stage stage, boolean important) { stage.setImportant(important); } }); } private static final StagePeerListener.StageAccessor STAGE_ACCESSOR = new StagePeerListener.StageAccessor() { @Override public void setIconified(Stage stage, boolean iconified) { stage.iconifiedPropertyImpl().set(iconified); } @Override public void setMaximized(Stage stage, boolean maximized) { stage.maximizedPropertyImpl().set(maximized); } @Override public void setResizable(Stage stage, boolean resizable) { ((ResizableProperty)stage.resizableProperty()).setNoInvalidate(resizable); } @Override public void setFullScreen(Stage stage, boolean fs) { stage.fullScreenPropertyImpl().set(fs); } @Override public void setAlwaysOnTop(Stage stage, boolean aot) { stage.alwaysOnTopPropertyImpl().set(aot); } }; /** * Creates a new instance of decorated {@code Stage}. * * @throws IllegalStateException if this constructor is called on a thread * other than the JavaFX Application Thread. */ public Stage() { this(StageStyle.DECORATED); } /** * Creates a new instance of {@code Stage}. * * @param style The style of the {@code Stage} * * @throws IllegalStateException if this constructor is called on a thread * other than the JavaFX Application Thread. */ public Stage(@NamedArg(value="style", defaultValue="DECORATED") StageStyle style) { super(); Toolkit.getToolkit().checkFxUserThread(); // Set the style initStyle(style); StageHelper.initHelper(this); } /** * Specify the scene to be used on this stage. */ @Override final public void setScene(Scene value) { Toolkit.getToolkit().checkFxUserThread(); super.setScene(value); } /** * {@inheritDoc} */ @Override public final void show() { super.show(); } private boolean primary = false; //////////////////////////////////////////////////////////////////// // Flag indicating that this stage is being used to show a security dialog private boolean securityDialog = false; /** * Sets a flag indicating that this stage is used for a security dialog and * must always be on top. If set, this will cause the window to be always * on top, regardless of the setting of the alwaysOnTop property, and * whether or not permissions are granted when the dialog is shown. * NOTE: this flag must be set prior to showing the stage the first time. * * @param securityDialog flag indicating that this Stage is being used to * show a security dialog that should be always-on-top * * @throws IllegalStateException if this property is set after the stage * has ever been made visible. * * @defaultValue false */ final void initSecurityDialog(boolean securityDialog) { if (hasBeenVisible) { throw new IllegalStateException("Cannot set securityDialog once stage has been set visible"); } this.securityDialog = securityDialog; } /** * Returns the state of the securityDialog flag. * * @return a flag indicating whether or not this is a security dialog */ final boolean isSecurityDialog() { return securityDialog; } /* * Sets this stage to be the primary stage. */ void setPrimary(boolean primary) { this.primary = primary; } /* * Returns whether this stage is the primary stage. * * @return true if this stage is the primary stage for the application. */ boolean isPrimary() { return primary; } private boolean important = true; /* * Sets a flag indicating whether this stage is an "important" window for * the purpose of determining whether the application is idle and should * exit. The application is considered finished when the last important * window is closed. */ void setImportant(boolean important) { this.important = important; } private boolean isImportant() { return important; } /** * Shows this stage and waits for it to be hidden (closed) before returning * to the caller. This method temporarily blocks processing of the current * event, and starts a nested event loop to handle other events. * This method must be called on the FX Application thread. ** A Stage is hidden (closed) by one of the following means: *
* After the Stage is hidden, and the application has returned from the * event handler to the event loop, the nested event loop terminates * and this method returns to the caller. *
** For example, consider the following sequence of operations for different * event handlers, assumed to execute in the order shown below: *
void evtHander1(...) { * stage1.showAndWait(); * doSomethingAfterStage1Closed(...) * } * * void evtHander2(...) { * stage1.hide(); * doSomethingElseHere(...) * }* evtHandler1 will block at the call to showAndWait. It will resume execution * after stage1 is hidden and the current event handler, in this case evtHandler2, * returns to the event loop. This means that doSomethingElseHere will * execute before doSomethingAfterStage1Closed. * *
* More than one stage may be shown with showAndWait. Each call * will start a new nested event loop. The stages may be hidden in any order, * but a particular nested event loop (and thus the showAndWait method * for the associated stage) will only terminate after all inner event loops * have also terminated. *
** For example, consider the following sequence of operations for different * event handlers, assumed to execute in the order shown below: *
void evtHander1() { * stage1.showAndWait(); * doSomethingAfterStage1Closed(...) * } * * void evtHander2() { * stage2.showAndWait(); * doSomethingAfterStage2Closed(...) * } * * void evtHander3() { * stage1.hide(); * doSomethingElseHere(...) * } * * void evtHander4() { * stage2.hide(); * doSomethingElseHereToo(...) * }* evtHandler1 will block at the call to stage1.showAndWait, starting up * a nested event loop just like in the previous example. evtHandler2 will * then block at the call to stage2.showAndWait, starting up another (inner) * nested event loop. The first call to stage1.showAndWait will resume execution * after stage1 is hidden, but only after the inner nested event loop started * by stage2.showAndWait has terminated. This means that the call to * stage1.showAndWait won't return until after evtHandler2 has returned. * The order of execution is: stage1.showAndWait, stage2.showAndWait, * stage1.hide, doSomethingElseHere, stage2.hide, doSomethingElseHereToo, * doSomethingAfterStage2Closed, doSomethingAfterStage1Closed. * *
* This method must not be called on the primary stage or on a stage that * is already visible. * Additionally, it must either be called from an input event handler or * from the run method of a Runnable passed to * {@link javafx.application.Platform#runLater Platform.runLater}. * It must not be called during animation or layout processing. *
* * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * @throws IllegalStateException if this method is called during * animation or layout processing. * @throws IllegalStateException if this method is called on the * primary stage. * @throws IllegalStateException if this stage is already showing. * @since JavaFX 2.2 */ public void showAndWait() { Toolkit.getToolkit().checkFxUserThread(); if (isPrimary()) { throw new IllegalStateException("Cannot call this method on primary stage"); } if (isShowing()) { throw new IllegalStateException("Stage already visible"); } if (!Toolkit.getToolkit().canStartNestedEventLoop()) { throw new IllegalStateException("showAndWait is not allowed during animation or layout processing"); } // TODO: file a new bug; the following assertion can fail if this // method is called from an event handler that is listening to a // WindowEvent.WINDOW_HIDING event. assert !inNestedEventLoop; show(); inNestedEventLoop = true; Toolkit.getToolkit().enterNestedEventLoop(this); } private StageStyle style; // default is set in constructor /** * Specifies the style for this stage. This must be done prior to making * the stage visible. The style is one of: StageStyle.DECORATED, * StageStyle.UNDECORATED, StageStyle.TRANSPARENT, or StageStyle.UTILITY. * * @param style the style for this stage. * * @throws IllegalStateException if this property is set after the stage * has ever been made visible. * * @defaultValue StageStyle.DECORATED */ public final void initStyle(StageStyle style) { if (hasBeenVisible) { throw new IllegalStateException("Cannot set style once stage has been set visible"); } this.style = style; } /** * Retrieves the style attribute for this stage. * * @return the stage style. */ public final StageStyle getStyle() { return style; } private Modality modality = Modality.NONE; /** * Specifies the modality for this stage. This must be done prior to making * the stage visible. The modality is one of: Modality.NONE, * Modality.WINDOW_MODAL, or Modality.APPLICATION_MODAL. * * @param modality the modality for this stage. * * @throws IllegalStateException if this property is set after the stage * has ever been made visible. * * @throws IllegalStateException if this stage is the primary stage. * * @defaultValue Modality.NONE */ public final void initModality(Modality modality) { if (hasBeenVisible) { throw new IllegalStateException("Cannot set modality once stage has been set visible"); } if (isPrimary()) { throw new IllegalStateException("Cannot set modality for the primary stage"); } this.modality = modality; } /** * Retrieves the modality attribute for this stage. * * @return the modality. */ public final Modality getModality() { return modality; } private Window owner = null; /** * Specifies the owner Window for this stage, or null for a top-level, * unowned stage. This must be done prior to making the stage visible. * * @param owner the owner for this stage. * * @throws IllegalStateException if this property is set after the stage * has ever been made visible. * * @throws IllegalStateException if this stage is the primary stage. * * @defaultValue null */ public final void initOwner(Window owner) { if (hasBeenVisible) { throw new IllegalStateException("Cannot set owner once stage has been set visible"); } if (isPrimary()) { throw new IllegalStateException("Cannot set owner for the primary stage"); } this.owner = owner; final Scene sceneValue = getScene(); if (sceneValue != null) { SceneHelper.parentEffectiveOrientationInvalidated(sceneValue); } } /** * Retrieves the owner Window for this stage, or null for an unowned stage. * * @return the owner Window. */ public final Window getOwner() { return owner; } /** * Specifies whether this {@code Stage} should be a full-screen, * undecorated window. ** The implementation of full-screen mode is platform and profile-dependent. *
** When set to {@code true}, the {@code Stage} will attempt to enter * full-screen mode when visible. Set to {@code false} to return {@code Stage} * to windowed mode. * An {@link IllegalStateException} is thrown if this property is set * on a thread other than the JavaFX Application Thread. *
** The full-screen mode will be exited (and the {@code fullScreen} attribute * will be set to {@code false}) if the full-screen * {@code Stage} loses focus or if another {@code Stage} enters * full-screen mode on the same {@link Screen}. Note that a {@code Stage} * in full-screen mode can become invisible without losing its * full-screen status and will again enter full-screen mode when the * {@code Stage} becomes visible. *
* If the platform supports multiple screens an application can control * which {@code Screen} the Stage will enter full-screen mode on by * setting its position to be within the bounds of that {@code Screen} * prior to entering full-screen mode. ** However once in full-screen mode, {@code Stage}'s {@code x}, {@code y}, * {@code width}, and {@code height} variables will continue to represent * the non-full-screen position and size of the window; the same for * {@code iconified}, {@code resizable}, {@code style}, and {@code * opacity}. If changes are made to any of these attributes while in * full-screen mode, upon exiting full-screen mode the {@code Stage} will * assume those attributes. *
** In case that more {@code Stage} modes are set simultaneously their order * of importance is {@code iconified}, fullScreen, {@code maximized} (from * strongest to weakest). *
** The property is read only because it can be changed externally * by the underlying platform and therefore must not be bindable. *
* * The user can unconditionally exit full-screen mode * at any time by pressing {@code ESC}. ** If a security manager is present, the application must have the * {@link javafx.util.FXPermission} "unrestrictedFullScreen" in order * to enter full-screen mode with no restrictions. Applications without * permission will have the following restrictions: *
** If {@code Stage} was constructed as full-screen but not visible * it will enter full-screen mode upon becoming visible, with the same * limitations to when this is allowed to happen as when setting * {@code fullScreen} to {@code true}. *
*