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 }