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