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 }