1 /*
   2  * Copyright (c) 2010, 2017, 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.application;
  27 
  28 import com.sun.javafx.tk.Toolkit;
  29 import javafx.beans.property.ReadOnlyBooleanProperty;
  30 import javafx.beans.property.ReadOnlyBooleanWrapper;
  31 import com.sun.javafx.application.PlatformImpl;
  32 
  33 /**
  34  * Application platform support class.
  35  * @since JavaFX 2.0
  36  */
  37 public final class Platform {
  38 
  39     // To prevent instantiation
  40     private Platform() {
  41     }
  42 
  43     /**
  44      * This method starts the JavaFX runtime. The specified Runnable will then be
  45      * called on the JavaFX Application Thread. In general it is not necessary to
  46      * explicitly call this method, since it is invoked as a consequence of
  47      * how most JavaFX applications are built. However there are valid use cases
  48      * for calling this method directly. Because this method starts the JavaFX
  49      * runtime, there is not yet any JavaFX Application Thread, so it is normal
  50      * that this method is called directly on the main thread of the application.
  51      *
  52      * <p>
  53      * This method may or may not return to the caller before the run method
  54      * of the specified Runnable has been called. In any case, once this method
  55      * returns, you may call {@link #runLater(Runnable)} with additional Runnables.
  56      * Those Runnables will be called, also on the JavaFX Application Thread,
  57      * after the Runnable passed into this method has been called.
  58      * </p>
  59      *
  60      * <p>As noted, it is normally the case that the JavaFX Application Thread
  61      * is started automatically. It is important that this method only be called
  62      * when the JavaFX runtime has not yet been initialized. Situations where
  63      * the JavaFX runtime is started automatically include:
  64      * </p>
  65      *
  66      * <ul>
  67      *   <li>For standard JavaFX applications that extend {@link Application}, and
  68      *   use either the Java launcher or one of the launch methods in the
  69      *   Application class to launch the application, the FX runtime is
  70      *   initialized automatically by the launcher before the {@code Application}
  71      *   class is loaded.</li>
  72      *   <li>For Swing applications that use {@link javafx.embed.swing.JFXPanel}
  73      *   to display FX content, the
  74      *   FX runtime is initialized when the first {@code JFXPanel} instance is
  75      *   constructed.</li>
  76      *   <li>For SWT application that use {@code FXCanvas} to display FX content,
  77      *   the FX runtime is initialized when the first {@code FXCanvas} instance is
  78      *   constructed.</li>
  79      * </ul>
  80      *
  81      * <p>When an application does not follow any of these common approaches,
  82      * then it becomes the responsibility of the developer to manually start the
  83      * JavaFX runtime by calling this startup method.
  84      * </p>
  85      *
  86      * <p>Calling this method when the JavaFX runtime is already running will result in an
  87      * {@link IllegalStateException} being thrown - it is only valid to request
  88      * that the JavaFX runtime be started once.
  89      * </p>
  90      *
  91      * @throws IllegalStateException if the JavaFX runtime is already running
  92      *
  93      * @param runnable the Runnable whose run method will be executed on the
  94      * JavaFX Application Thread once it has been started
  95      *
  96      * @see Application
  97      *
  98      * @since 9
  99      */
 100     public static void startup(Runnable runnable) {
 101         PlatformImpl.startup(runnable, true);
 102     }
 103 
 104     /**
 105      * Run the specified Runnable on the JavaFX Application Thread at some
 106      * unspecified
 107      * time in the future. This method, which may be called from any thread,
 108      * will post the Runnable to an event queue and then return immediately to
 109      * the caller. The Runnables are executed in the order they are posted.
 110      * A runnable passed into the runLater method will be
 111      * executed before any Runnable passed into a subsequent call to runLater.
 112      * If this method is called after the JavaFX runtime has been shutdown, the
 113      * call will be ignored: the Runnable will not be executed and no
 114      * exception will be thrown.
 115      *
 116      * <p>
 117      * NOTE: applications should avoid flooding JavaFX with too many
 118      * pending Runnables. Otherwise, the application may become unresponsive.
 119      * Applications are encouraged to batch up multiple operations into fewer
 120      * runLater calls.
 121      * Additionally, long-running operations should be done on a background
 122      * thread where possible, freeing up the JavaFX Application Thread for GUI
 123      * operations.
 124      * </p>
 125      *
 126      * <p>
 127      * This method must not be called before the FX runtime has been
 128      * initialized. For standard JavaFX applications that extend
 129      * {@link Application}, and use either the Java launcher or one of the
 130      * launch methods in the Application class to launch the application,
 131      * the FX runtime is initialized by the launcher before the Application
 132      * class is loaded.
 133      * For Swing applications that use JFXPanel to display FX content, the FX
 134      * runtime is initialized when the first JFXPanel instance is constructed.
 135      * For SWT application that use FXCanvas to display FX content, the FX
 136      * runtime is initialized when the first FXCanvas instance is constructed.
 137      * For applications that do not follow any of these approaches, then it is
 138      * necessary to manually start the JavaFX runtime by calling
 139      * {@link #startup(Runnable)} once.
 140      * </p>
 141      *
 142      * @param runnable the Runnable whose run method will be executed on the
 143      * JavaFX Application Thread
 144      *
 145      * @throws IllegalStateException if the FX runtime has not been initialized
 146      *
 147      * @see Application
 148      */
 149     public static void runLater(Runnable runnable) {
 150         PlatformImpl.runLater(runnable);
 151     }
 152 
 153     // NOTE: Add the following if we decide to expose it publicly
 154 //    public static void runAndWait(Runnable runnable) {
 155 //        PlatformImpl.runAndWait(runnable);
 156 //    }
 157 
 158     /**
 159      * Requests the Java Runtime to perform a pulse. This will run a pulse
 160      * even if there are no animation timers, scene graph modifications,
 161      * or window events that would otherwise cause the pulse to run.
 162      * If no pulse is in progress, then one will be scheduled to
 163      * run the next time the pulse timer fires.
 164      * If there is already a pulse running, then
 165      * at least one more pulse after the current pulse will be scheduled.
 166      * This method may be called on any thread.
 167      *
 168      * @since 9
 169      */
 170     public static void requestNextPulse() {
 171         Toolkit.getToolkit().requestNextPulse();
 172     }
 173 
 174     /**
 175      * Returns true if the calling thread is the JavaFX Application Thread.
 176      * Use this call the ensure that a given task is being executed
 177      * (or not being executed) on the JavaFX Application Thread.
 178      *
 179      * @return true if running on the JavaFX Application Thread
 180      */
 181     public static boolean isFxApplicationThread() {
 182         return PlatformImpl.isFxApplicationThread();
 183     }
 184 
 185     /**
 186      * Causes the JavaFX application to terminate. If this method is called
 187      * after the Application start method is called, then the JavaFX launcher
 188      * will call the Application stop method and terminate the JavaFX
 189      * application thread. The launcher thread will then shutdown. If there
 190      * are no other non-daemon threads that are running, the Java VM will exit.
 191      * If this method is called from the Preloader or the Application init
 192      * method, then the Application stop method may not be called.
 193      *
 194      * <p>This method may be called from any thread.</p>
 195      *
 196      * <p>Note: if the application is embedded in a browser, then this method
 197      * may have no effect.
 198      */
 199     public static void exit() {
 200         PlatformImpl.exit();
 201     }
 202 
 203     /**
 204      * Sets the implicitExit attribute to the specified value. If this
 205      * attribute is true, the JavaFX runtime will implicitly shutdown
 206      * when the last window is closed; the JavaFX launcher will call the
 207      * {@link Application#stop} method and terminate the JavaFX
 208      * application thread.
 209      * If this attribute is false, the application will continue to
 210      * run normally even after the last window is closed, until the
 211      * application calls {@link #exit}.
 212      * The default value is true.
 213      *
 214      * <p>This method may be called from any thread.</p>
 215      *
 216      * @param implicitExit a flag indicating whether or not to implicitly exit
 217      * when the last window is closed.
 218      * @since JavaFX 2.2
 219      */
 220     public static void setImplicitExit(boolean implicitExit) {
 221         PlatformImpl.setImplicitExit(implicitExit);
 222     }
 223 
 224     /**
 225      * Gets the value of the implicitExit attribute.
 226      *
 227      * <p>This method may be called from any thread.</p>
 228      *
 229      * @return the implicitExit attribute
 230      * @since JavaFX 2.2
 231      */
 232     public static boolean isImplicitExit() {
 233         return PlatformImpl.isImplicitExit();
 234     }
 235 
 236     /**
 237      * Queries whether a specific conditional feature is supported
 238      * by the platform.
 239      * <p>
 240      * For example:
 241      * <pre>
 242      * // Query whether filter effects are supported
 243      * if (Platform.isSupported(ConditionalFeature.EFFECT)) {
 244      *    // use effects
 245      * }
 246      * </pre>
 247      *
 248      * @param feature the conditional feature in question.
 249      * @return true if a specific conditional feature is supported by the
 250      * platform, otherwise false
 251      */
 252     public static boolean isSupported(ConditionalFeature feature) {
 253         return PlatformImpl.isSupported(feature);
 254     }
 255 
 256     /**
 257      * Enter a nested event loop and block until the corresponding
 258      * exitNestedEventLoop call is made.
 259      * The key passed into this method is used to
 260      * uniquely identify the matched enter/exit pair. This method creates a
 261      * new nested event loop and blocks until the corresponding
 262      * exitNestedEventLoop method is called with the same key.
 263      * The return value of this method will be the {@code rval}
 264      * object supplied to the exitNestedEventLoop method call that unblocks it.
 265      *
 266      * <p>
 267      * This method must either be called from an input event handler or
 268      * from the run method of a Runnable passed to
 269      * {@link javafx.application.Platform#runLater Platform.runLater}.
 270      * It must not be called during animation or layout processing.
 271      * </p>
 272      *
 273      * @param key the Object that identifies the nested event loop, which
 274      * must not be null
 275      *
 276      * @throws IllegalArgumentException if the specified key is associated
 277      * with a nested event loop that has not yet returned
 278      *
 279      * @throws NullPointerException if the key is null
 280      *
 281      * @throws IllegalStateException if this method is called during
 282      * animation or layout processing.
 283      *
 284      * @throws IllegalStateException if this method is called on a thread
 285      * other than the JavaFX Application Thread.
 286      *
 287      * @return the value passed into the corresponding call to exitEventLoop
 288      *
 289      * @since 9
 290      */
 291     public static Object enterNestedEventLoop(Object key) {
 292         return Toolkit.getToolkit().enterNestedEventLoop(key);
 293     }
 294 
 295     /**
 296      * Exit a nested event loop and unblock the caller of the
 297      * corresponding enterNestedEventLoop.
 298      * The key passed into this method is used to
 299      * uniquely identify the matched enter/exit pair. This method causes the
 300      * nested event loop that was previously created with the key to exit and
 301      * return control to the caller. If the specified nested event loop is not
 302      * the inner-most loop then it will not return until all other inner loops
 303      * also exit.
 304      *
 305      * @param key the Object that identifies the nested event loop, which
 306      * must not be null
 307      *
 308      * @param rval an Object that is returned to the caller of the
 309      * corresponding enterNestedEventLoop. This may be null.
 310      *
 311      * @throws IllegalArgumentException if the specified key is not associated
 312      * with an active nested event loop
 313      *
 314      * @throws NullPointerException if the key is null
 315      *
 316      * @throws IllegalStateException if this method is called on a thread
 317      * other than the FX Application thread
 318      *
 319      * @since 9
 320      */
 321     public static void exitNestedEventLoop(Object key, Object rval) {
 322         Toolkit.getToolkit().exitNestedEventLoop(key, rval);
 323     }
 324 
 325     /**
 326      * Checks whether a nested event loop is running, returning true to indicate
 327      * that one is, and false if there are no nested event loops currently
 328      * running.
 329      * This method must be called on the JavaFX Application thread.
 330      *
 331      * @return true if there is a nested event loop running, and false otherwise.
 332      *
 333      * @throws IllegalStateException if this method is called on a thread
 334      * other than the JavaFX Application Thread.
 335      *
 336      * @since 9
 337      */
 338     public static boolean isNestedLoopRunning() {
 339         return Toolkit.getToolkit().isNestedLoopRunning();
 340     }
 341 
 342     private static ReadOnlyBooleanWrapper accessibilityActiveProperty;
 343 
 344     public static boolean isAccessibilityActive() {
 345         return accessibilityActiveProperty == null ? false : accessibilityActiveProperty.get();
 346     }
 347 
 348     /**
 349      * Indicates whether or not accessibility is active.
 350      * This property is typically set to true the first time an
 351      * assistive technology, such as a screen reader, requests
 352      * information about any JavaFX window or its children.
 353      *
 354      * <p>This method may be called from any thread.</p>
 355      *
 356      * @return the read-only boolean property indicating if accessibility is active
 357      *
 358      * @since JavaFX 8u40
 359      */
 360     public static ReadOnlyBooleanProperty accessibilityActiveProperty() {
 361         if (accessibilityActiveProperty == null) {
 362             accessibilityActiveProperty = new ReadOnlyBooleanWrapper(Platform.class, "accessibilityActive");
 363             accessibilityActiveProperty.bind(PlatformImpl.accessibilityActiveProperty());
 364         }
 365         return accessibilityActiveProperty.getReadOnlyProperty();
 366     }
 367 }