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