1 /*
   2  * Copyright (c) 2010, 2018, 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     public static void exit() {
 197         PlatformImpl.exit();
 198     }
 199 
 200     /**
 201      * Sets the implicitExit attribute to the specified value. If this
 202      * attribute is true, the JavaFX runtime will implicitly shutdown
 203      * when the last window is closed; the JavaFX launcher will call the
 204      * {@link Application#stop} method and terminate the JavaFX
 205      * application thread.
 206      * If this attribute is false, the application will continue to
 207      * run normally even after the last window is closed, until the
 208      * application calls {@link #exit}.
 209      * The default value is true.
 210      *
 211      * <p>This method may be called from any thread.</p>
 212      *
 213      * @param implicitExit a flag indicating whether or not to implicitly exit
 214      * when the last window is closed.
 215      * @since JavaFX 2.2
 216      */
 217     public static void setImplicitExit(boolean implicitExit) {
 218         PlatformImpl.setImplicitExit(implicitExit);
 219     }
 220 
 221     /**
 222      * Gets the value of the implicitExit attribute.
 223      *
 224      * <p>This method may be called from any thread.</p>
 225      *
 226      * @return the implicitExit attribute
 227      * @since JavaFX 2.2
 228      */
 229     public static boolean isImplicitExit() {
 230         return PlatformImpl.isImplicitExit();
 231     }
 232 
 233     /**
 234      * Queries whether a specific conditional feature is supported
 235      * by the platform.
 236      * <p>
 237      * For example:
 238      * <pre>
 239      * // Query whether filter effects are supported
 240      * if (Platform.isSupported(ConditionalFeature.EFFECT)) {
 241      *    // use effects
 242      * }
 243      * </pre>
 244      *
 245      * @param feature the conditional feature in question.
 246      * @return true if a specific conditional feature is supported by the
 247      * platform, otherwise false
 248      */
 249     public static boolean isSupported(ConditionalFeature feature) {
 250         return PlatformImpl.isSupported(feature);
 251     }
 252 
 253     /**
 254      * Enter a nested event loop and block until the corresponding
 255      * exitNestedEventLoop call is made.
 256      * The key passed into this method is used to
 257      * uniquely identify the matched enter/exit pair. This method creates a
 258      * new nested event loop and blocks until the corresponding
 259      * exitNestedEventLoop method is called with the same key.
 260      * The return value of this method will be the {@code rval}
 261      * object supplied to the exitNestedEventLoop method call that unblocks it.
 262      *
 263      * <p>
 264      * This method must either be called from an input event handler or
 265      * from the run method of a Runnable passed to
 266      * {@link javafx.application.Platform#runLater Platform.runLater}.
 267      * It must not be called during animation or layout processing.
 268      * </p>
 269      *
 270      * @param key the Object that identifies the nested event loop, which
 271      * must not be null
 272      *
 273      * @throws IllegalArgumentException if the specified key is associated
 274      * with a nested event loop that has not yet returned
 275      *
 276      * @throws NullPointerException if the key is null
 277      *
 278      * @throws IllegalStateException if this method is called during
 279      * animation or layout processing.
 280      *
 281      * @throws IllegalStateException if this method is called on a thread
 282      * other than the JavaFX Application Thread.
 283      *
 284      * @return the value passed into the corresponding call to exitEventLoop
 285      *
 286      * @since 9
 287      */
 288     public static Object enterNestedEventLoop(Object key) {
 289         return Toolkit.getToolkit().enterNestedEventLoop(key);
 290     }
 291 
 292     /**
 293      * Exit a nested event loop and unblock the caller of the
 294      * corresponding enterNestedEventLoop.
 295      * The key passed into this method is used to
 296      * uniquely identify the matched enter/exit pair. This method causes the
 297      * nested event loop that was previously created with the key to exit and
 298      * return control to the caller. If the specified nested event loop is not
 299      * the inner-most loop then it will not return until all other inner loops
 300      * also exit.
 301      *
 302      * @param key the Object that identifies the nested event loop, which
 303      * must not be null
 304      *
 305      * @param rval an Object that is returned to the caller of the
 306      * corresponding enterNestedEventLoop. This may be null.
 307      *
 308      * @throws IllegalArgumentException if the specified key is not associated
 309      * with an active nested event loop
 310      *
 311      * @throws NullPointerException if the key is null
 312      *
 313      * @throws IllegalStateException if this method is called on a thread
 314      * other than the FX Application thread
 315      *
 316      * @since 9
 317      */
 318     public static void exitNestedEventLoop(Object key, Object rval) {
 319         Toolkit.getToolkit().exitNestedEventLoop(key, rval);
 320     }
 321 
 322     /**
 323      * Checks whether a nested event loop is running, returning true to indicate
 324      * that one is, and false if there are no nested event loops currently
 325      * running.
 326      * This method must be called on the JavaFX Application thread.
 327      *
 328      * @return true if there is a nested event loop running, and false otherwise.
 329      *
 330      * @throws IllegalStateException if this method is called on a thread
 331      * other than the JavaFX Application Thread.
 332      *
 333      * @since 9
 334      */
 335     public static boolean isNestedLoopRunning() {
 336         return Toolkit.getToolkit().isNestedLoopRunning();
 337     }
 338 
 339     private static ReadOnlyBooleanWrapper accessibilityActiveProperty;
 340 
 341     public static boolean isAccessibilityActive() {
 342         return accessibilityActiveProperty == null ? false : accessibilityActiveProperty.get();
 343     }
 344 
 345     /**
 346      * Indicates whether or not accessibility is active.
 347      * This property is typically set to true the first time an
 348      * assistive technology, such as a screen reader, requests
 349      * information about any JavaFX window or its children.
 350      *
 351      * <p>This method may be called from any thread.</p>
 352      *
 353      * @return the read-only boolean property indicating if accessibility is active
 354      *
 355      * @since JavaFX 8u40
 356      */
 357     public static ReadOnlyBooleanProperty accessibilityActiveProperty() {
 358         if (accessibilityActiveProperty == null) {
 359             accessibilityActiveProperty = new ReadOnlyBooleanWrapper(Platform.class, "accessibilityActive");
 360             accessibilityActiveProperty.bind(PlatformImpl.accessibilityActiveProperty());
 361         }
 362         return accessibilityActiveProperty.getReadOnlyProperty();
 363     }
 364 }