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