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