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