1 /* 2 * Copyright (c) 2010, 2015, 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 com.sun.javafx.application; 27 28 import com.sun.javafx.PlatformUtil; 29 import com.sun.javafx.css.StyleManager; 30 import com.sun.javafx.runtime.SystemProperties; 31 32 import java.lang.reflect.InvocationTargetException; 33 import java.lang.reflect.Method; 34 import java.security.AccessControlContext; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Set; 38 import java.util.concurrent.CopyOnWriteArraySet; 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.atomic.AtomicBoolean; 41 import java.util.concurrent.atomic.AtomicInteger; 42 43 import javafx.application.Application; 44 import javafx.application.ConditionalFeature; 45 46 import com.sun.javafx.tk.TKListener; 47 import com.sun.javafx.tk.TKStage; 48 import com.sun.javafx.tk.Toolkit; 49 import javafx.beans.property.BooleanProperty; 50 import javafx.beans.property.SimpleBooleanProperty; 51 import javafx.scene.Scene; 52 53 import java.security.AccessController; 54 import java.security.AllPermission; 55 import java.security.PrivilegedAction; 56 57 public class PlatformImpl { 58 59 private static AtomicBoolean initialized = new AtomicBoolean(false); 60 private static AtomicBoolean platformExit = new AtomicBoolean(false); 61 private static AtomicBoolean toolkitExit = new AtomicBoolean(false); 62 private static CountDownLatch startupLatch = new CountDownLatch(1); 63 private static AtomicBoolean listenersRegistered = new AtomicBoolean(false); 64 private static TKListener toolkitListener = null; 65 private static volatile boolean implicitExit = true; 66 private static boolean taskbarApplication = true; 67 private static boolean contextual2DNavigation; 68 private static AtomicInteger pendingRunnables = new AtomicInteger(0); 69 private static AtomicInteger numWindows = new AtomicInteger(0); 70 private static volatile boolean firstWindowShown = false; 71 private static volatile boolean lastWindowClosed = false; 72 private static AtomicBoolean reallyIdle = new AtomicBoolean(false); 73 private static Set<FinishListener> finishListeners = 74 new CopyOnWriteArraySet<FinishListener>(); 75 private final static Object runLaterLock = new Object(); 76 private static Boolean isGraphicsSupported; 77 private static Boolean isControlsSupported; 78 private static Boolean isMediaSupported; 79 private static Boolean isWebSupported; 80 private static Boolean isSWTSupported; 81 private static Boolean isSwingSupported; 82 private static Boolean isFXMLSupported; 83 private static Boolean hasTwoLevelFocus; 84 private static Boolean hasVirtualKeyboard; 85 private static Boolean hasTouch; 86 private static Boolean hasMultiTouch; 87 private static Boolean hasPointer; 88 private static boolean isThreadMerged = false; 89 private static BooleanProperty accessibilityActive = new SimpleBooleanProperty(); 90 91 /** 92 * Set a flag indicating whether this application should show up in the 93 * task bar. The default value is true. 94 * 95 * @param taskbarApplication the new value of this attribute 96 */ 97 public static void setTaskbarApplication(boolean taskbarApplication) { 98 PlatformImpl.taskbarApplication = taskbarApplication; 99 } 100 101 /** 102 * Returns the current value of the taskBarApplication flag. 103 * 104 * @return the current state of the flag. 105 */ 106 public static boolean isTaskbarApplication() { 107 return taskbarApplication; 108 } 109 110 /** 111 * Sets the name of the this application based on the Application class. 112 * This method is called by the launcher or by the deploy code, and is not 113 * called from the FX Application Thread, so we need to do it in a runLater. 114 * We do not need to wait for the result since it will complete before the 115 * Application start() method is called regardless. 116 * 117 * @param appClass the Application class. 118 */ 119 public static void setApplicationName(final Class appClass) { 120 runLater(() -> com.sun.glass.ui.Application.GetApplication().setName(appClass.getName())); 121 } 122 123 /** 124 * Return whether or not focus navigation between controls is context- 125 * sensitive. 126 * @return true if the context-sensitive algorithm for focus navigation is 127 * used 128 */ 129 public static boolean isContextual2DNavigation() { 130 return contextual2DNavigation; 131 } 132 133 /** 134 * This method is invoked typically on the main thread. At this point, 135 * the JavaFX Application Thread has not been started. Any attempt 136 * to call startup twice results in an exception. 137 * @param r 138 */ 139 public static void startup(final Runnable r) { 140 141 // NOTE: if we ever support re-launching an application and/or 142 // launching a second application in the same VM/classloader 143 // this will need to be changed. 144 if (platformExit.get()) { 145 throw new IllegalStateException("Platform.exit has been called"); 146 } 147 148 if (initialized.getAndSet(true)) { 149 // If we've already initialized, just put the runnable on the queue. 150 runLater(r); 151 return; 152 } 153 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 154 contextual2DNavigation = Boolean.getBoolean( 155 "com.sun.javafx.isContextual2DNavigation"); 156 String s = System.getProperty("com.sun.javafx.twoLevelFocus"); 157 if (s != null) { 158 hasTwoLevelFocus = Boolean.valueOf(s); 159 } 160 s = System.getProperty("com.sun.javafx.virtualKeyboard"); 161 if (s != null) { 162 if (s.equalsIgnoreCase("none")) { 163 hasVirtualKeyboard = false; 164 } else if (s.equalsIgnoreCase("javafx")) { 165 hasVirtualKeyboard = true; 166 } else if (s.equalsIgnoreCase("native")) { 167 hasVirtualKeyboard = true; 168 } 169 } 170 s = System.getProperty("com.sun.javafx.touch"); 171 if (s != null) { 172 hasTouch = Boolean.valueOf(s); 173 } 174 s = System.getProperty("com.sun.javafx.multiTouch"); 175 if (s != null) { 176 hasMultiTouch = Boolean.valueOf(s); 177 } 178 s = System.getProperty("com.sun.javafx.pointer"); 179 if (s != null) { 180 hasPointer = Boolean.valueOf(s); 181 } 182 s = System.getProperty("javafx.embed.singleThread"); 183 if (s != null) { 184 isThreadMerged = Boolean.valueOf(s); 185 } 186 return null; 187 }); 188 189 if (!taskbarApplication) { 190 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 191 System.setProperty("glass.taskbarApplication", "false"); 192 return null; 193 }); 194 } 195 196 // Create Toolkit listener and register it with the Toolkit. 197 // Call notifyFinishListeners when we get notified. 198 toolkitListener = new TKListener() { 199 @Override public void changedTopLevelWindows(List<TKStage> windows) { 200 numWindows.set(windows.size()); 201 checkIdle(); 202 } 203 204 @Override 205 public void exitedLastNestedLoop() { 206 checkIdle(); 207 } 208 }; 209 Toolkit.getToolkit().addTkListener(toolkitListener); 210 211 Toolkit.getToolkit().startup(() -> { 212 startupLatch.countDown(); 213 r.run(); 214 }); 215 216 //Initialize the thread merging mechanism 217 if (isThreadMerged) { 218 installFwEventQueue(); 219 } 220 } 221 222 private static void installFwEventQueue() { 223 invokeSwingFXUtilsMethod("installFwEventQueue"); 224 } 225 226 private static void removeFwEventQueue() { 227 invokeSwingFXUtilsMethod("removeFwEventQueue"); 228 } 229 230 private static void invokeSwingFXUtilsMethod(final String methodName) { 231 //Use reflection in case we are running compact profile 232 try { 233 Class swingFXUtilsClass = Class.forName("javafx.embed.swing.SwingFXUtils"); 234 Method installFwEventQueue = swingFXUtilsClass.getDeclaredMethod(methodName); 235 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 236 installFwEventQueue.setAccessible(true); 237 return null; 238 }); 239 240 waitForStart(); 241 installFwEventQueue.invoke(null); 242 243 } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) { 244 throw new RuntimeException("Property javafx.embed.singleThread is not supported"); 245 } catch (InvocationTargetException e) { 246 throw new RuntimeException(e); 247 } 248 } 249 250 private static void waitForStart() { 251 // If the startup runnable has not yet been called, then wait it. 252 // Note that we check the count before calling await() to avoid 253 // the try/catch which is unnecessary after startup. 254 if (startupLatch.getCount() > 0) { 255 try { 256 startupLatch.await(); 257 } catch (InterruptedException ex) { 258 ex.printStackTrace(); 259 } 260 } 261 } 262 263 public static boolean isFxApplicationThread() { 264 return Toolkit.getToolkit().isFxUserThread(); 265 } 266 267 public static void runLater(final Runnable r) { 268 runLater(r, false); 269 } 270 271 private static void runLater(final Runnable r, boolean exiting) { 272 if (!initialized.get()) { 273 throw new IllegalStateException("Toolkit not initialized"); 274 } 275 276 pendingRunnables.incrementAndGet(); 277 waitForStart(); 278 279 if (SystemProperties.isDebug()) { 280 Toolkit.getToolkit().pauseCurrentThread(); 281 } 282 283 synchronized (runLaterLock) { 284 if (!exiting && toolkitExit.get()) { 285 // Don't schedule a runnable after we have exited the toolkit 286 pendingRunnables.decrementAndGet(); 287 return; 288 } 289 290 final AccessControlContext acc = AccessController.getContext(); 291 // Don't catch exceptions, they are handled by Toolkit.defer() 292 Toolkit.getToolkit().defer(() -> { 293 try { 294 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 295 r.run(); 296 return null; 297 }, acc); 298 } finally { 299 pendingRunnables.decrementAndGet(); 300 checkIdle(); 301 } 302 }); 303 } 304 } 305 306 public static void runAndWait(final Runnable r) { 307 runAndWait(r, false); 308 } 309 310 private static void runAndWait(final Runnable r, boolean exiting) { 311 if (SystemProperties.isDebug()) { 312 Toolkit.getToolkit().pauseCurrentThread(); 313 } 314 315 if (isFxApplicationThread()) { 316 try { 317 r.run(); 318 } catch (Throwable t) { 319 System.err.println("Exception in runnable"); 320 t.printStackTrace(); 321 } 322 } else { 323 final CountDownLatch doneLatch = new CountDownLatch(1); 324 runLater(() -> { 325 try { 326 r.run(); 327 } finally { 328 doneLatch.countDown(); 329 } 330 }, exiting); 331 332 if (!exiting && toolkitExit.get()) { 333 throw new IllegalStateException("Toolkit has exited"); 334 } 335 336 try { 337 doneLatch.await(); 338 } catch (InterruptedException ex) { 339 ex.printStackTrace(); 340 } 341 } 342 } 343 344 public static void setImplicitExit(boolean implicitExit) { 345 PlatformImpl.implicitExit = implicitExit; 346 checkIdle(); 347 } 348 349 public static boolean isImplicitExit() { 350 return implicitExit; 351 } 352 353 public static void addListener(FinishListener l) { 354 listenersRegistered.set(true); 355 finishListeners.add(l); 356 } 357 358 public static void removeListener(FinishListener l) { 359 finishListeners.remove(l); 360 listenersRegistered.set(!finishListeners.isEmpty()); 361 if (!listenersRegistered.get()) { 362 checkIdle(); 363 } 364 } 365 366 private static void notifyFinishListeners(boolean exitCalled) { 367 // Notify listeners if any are registered, else exit directly 368 if (listenersRegistered.get()) { 369 for (FinishListener l : finishListeners) { 370 if (exitCalled) { 371 l.exitCalled(); 372 } else { 373 l.idle(implicitExit); 374 } 375 } 376 } else if (implicitExit || platformExit.get()) { 377 tkExit(); 378 } 379 } 380 381 // Check for idle, meaning the last top-level window has been closed and 382 // there are no pending Runnables waiting to be run. 383 private static void checkIdle() { 384 // If we aren't initialized yet, then this method is a no-op. 385 if (!initialized.get()) { 386 return; 387 } 388 389 if (!isFxApplicationThread()) { 390 // Add a dummy runnable to the runLater queue, which will then call 391 // checkIdle() on the FX application thread. 392 runLater(() -> { 393 }); 394 return; 395 } 396 397 boolean doNotify = false; 398 399 synchronized (PlatformImpl.class) { 400 int numWin = numWindows.get(); 401 if (numWin > 0) { 402 firstWindowShown = true; 403 lastWindowClosed = false; 404 reallyIdle.set(false); 405 } else if (numWin == 0 && firstWindowShown) { 406 lastWindowClosed = true; 407 } 408 409 // In case there is an event in process, allow for it to show 410 // another window. If no new window is shown before all pending 411 // runnables (including this one) are done and there is no running 412 // nested loops, then we will shutdown. 413 if (lastWindowClosed && pendingRunnables.get() == 0 414 && (toolkitExit.get() || !Toolkit.getToolkit().isNestedLoopRunning())) { 415 // System.err.println("Last window closed and no pending runnables"); 416 if (reallyIdle.getAndSet(true)) { 417 // System.err.println("Really idle now"); 418 doNotify = true; 419 lastWindowClosed = false; 420 } else { 421 // System.err.println("Queuing up a dummy idle check runnable"); 422 runLater(() -> { 423 // System.err.println("Dummy runnable"); 424 }); 425 } 426 } 427 } 428 429 if (doNotify) { 430 notifyFinishListeners(false); 431 } 432 } 433 434 // package scope method for testing 435 private static final CountDownLatch platformExitLatch = new CountDownLatch(1); 436 static CountDownLatch test_getPlatformExitLatch() { 437 return platformExitLatch; 438 } 439 440 public static void tkExit() { 441 if (toolkitExit.getAndSet(true)) { 442 return; 443 } 444 445 if (initialized.get()) { 446 // Always call toolkit exit on FX app thread 447 // System.err.println("PlatformImpl.tkExit: scheduling Toolkit.exit"); 448 PlatformImpl.runAndWait(() -> { 449 // System.err.println("PlatformImpl.tkExit: calling Toolkit.exit"); 450 Toolkit.getToolkit().exit(); 451 }, true); 452 453 if (isThreadMerged) { 454 removeFwEventQueue(); 455 } 456 457 Toolkit.getToolkit().removeTkListener(toolkitListener); 458 toolkitListener = null; 459 platformExitLatch.countDown(); 460 } 461 } 462 463 public static BooleanProperty accessibilityActiveProperty() { 464 return accessibilityActive; 465 } 466 467 public static void exit() { 468 platformExit.set(true); 469 notifyFinishListeners(true); 470 } 471 472 private static Boolean checkForClass(String classname) { 473 try { 474 Class.forName(classname, false, PlatformImpl.class.getClassLoader()); 475 return Boolean.TRUE; 476 } catch (ClassNotFoundException cnfe) { 477 return Boolean.FALSE; 478 } 479 } 480 481 public static boolean isSupported(ConditionalFeature feature) { 482 final boolean supported = isSupportedImpl(feature); 483 if (supported && (feature == ConditionalFeature.TRANSPARENT_WINDOW)) { 484 // some features require the application to have the corresponding 485 // permissions, if the application doesn't have them, the platform 486 // will behave as if the feature wasn't supported 487 final SecurityManager securityManager = 488 System.getSecurityManager(); 489 if (securityManager != null) { 490 try { 491 securityManager.checkPermission(new AllPermission()); 492 } catch (final SecurityException e) { 493 return false; 494 } 495 } 496 497 return true; 498 } 499 500 return supported; 501 } 502 503 public static interface FinishListener { 504 public void idle(boolean implicitExit); 505 public void exitCalled(); 506 } 507 508 /** 509 * Set the platform user agent stylesheet to the default. 510 */ 511 public static void setDefaultPlatformUserAgentStylesheet() { 512 setPlatformUserAgentStylesheet(Application.STYLESHEET_MODENA); 513 } 514 515 private static boolean isModena = false; 516 private static boolean isCaspian = false; 517 518 /** 519 * Current Platform User Agent Stylesheet is Modena. 520 * 521 * Note: Please think hard before using this as we really want to avoid special cases in the platform for specific 522 * themes. This was added to allow tempory work arounds in the platform for bugs. 523 * 524 * @return true if using modena stylesheet 525 */ 526 public static boolean isModena() { 527 return isModena; 528 } 529 530 /** 531 * Current Platform User Agent Stylesheet is Caspian. 532 * 533 * Note: Please think hard before using this as we really want to avoid special cases in the platform for specific 534 * themes. This was added to allow tempory work arounds in the platform for bugs. 535 * 536 * @return true if using caspian stylesheet 537 */ 538 public static boolean isCaspian() { 539 return isCaspian; 540 } 541 542 /** 543 * Set the platform user agent stylesheet to the given URL. This method has special handling for platform theme 544 * name constants. 545 */ 546 public static void setPlatformUserAgentStylesheet(final String stylesheetUrl) { 547 if (isFxApplicationThread()) { 548 _setPlatformUserAgentStylesheet(stylesheetUrl); 549 } else { 550 runLater(() -> _setPlatformUserAgentStylesheet(stylesheetUrl)); 551 } 552 } 553 554 private static String accessibilityTheme; 555 public static boolean setAccessibilityTheme(String platformTheme) { 556 557 if (accessibilityTheme != null) { 558 StyleManager.getInstance().removeUserAgentStylesheet(accessibilityTheme); 559 accessibilityTheme = null; 560 } 561 562 _setAccessibilityTheme(platformTheme); 563 564 if (accessibilityTheme != null) { 565 StyleManager.getInstance().addUserAgentStylesheet(accessibilityTheme); 566 return true; 567 } 568 return false; 569 570 } 571 572 private static void _setAccessibilityTheme(String platformTheme) { 573 574 // check to see if there is an override to enable a high-contrast theme 575 final String userTheme = AccessController.doPrivileged( 576 (PrivilegedAction<String>) () -> System.getProperty("com.sun.javafx.highContrastTheme")); 577 578 if (isCaspian()) { 579 if (platformTheme != null || userTheme != null) { 580 // caspian has only one high contrast theme, use it regardless of the user or platform theme. 581 accessibilityTheme = "com/sun/javafx/scene/control/skin/caspian/highcontrast.css"; 582 } 583 } else if (isModena()) { 584 // User-defined property takes precedence 585 if (userTheme != null) { 586 switch (userTheme.toUpperCase()) { 587 case "BLACKONWHITE": 588 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css"; 589 break; 590 case "WHITEONBLACK": 591 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css"; 592 break; 593 case "YELLOWONBLACK": 594 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css"; 595 break; 596 default: 597 } 598 } else { 599 if (platformTheme != null) { 600 // The following names are Platform specific (Windows 7 and 8) 601 switch (platformTheme) { 602 case "High Contrast White": 603 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css"; 604 break; 605 case "High Contrast Black": 606 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css"; 607 break; 608 case "High Contrast #1": 609 case "High Contrast #2": //TODO #2 should be green on black 610 accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css"; 611 break; 612 default: 613 } 614 } 615 } 616 } 617 } 618 619 private static void _setPlatformUserAgentStylesheet(String stylesheetUrl) { 620 isModena = isCaspian = false; 621 // check for command line override 622 final String overrideStylesheetUrl = AccessController.doPrivileged( 623 (PrivilegedAction<String>) () -> System.getProperty("javafx.userAgentStylesheetUrl")); 624 625 if (overrideStylesheetUrl != null) { 626 stylesheetUrl = overrideStylesheetUrl; 627 } 628 629 final List<String> uaStylesheets = new ArrayList<>(); 630 631 // check for named theme constants for modena and caspian 632 if (Application.STYLESHEET_CASPIAN.equalsIgnoreCase(stylesheetUrl)) { 633 isCaspian = true; 634 635 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/caspian.css"); 636 637 if (isSupported(ConditionalFeature.INPUT_TOUCH)) { 638 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/embedded.css"); 639 if (com.sun.javafx.util.Utils.isQVGAScreen()) { 640 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/embedded-qvga.css"); 641 } 642 if (PlatformUtil.isAndroid()) { 643 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/android.css"); 644 } 645 } 646 647 if (isSupported(ConditionalFeature.TWO_LEVEL_FOCUS)) { 648 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/two-level-focus.css"); 649 } 650 651 if (isSupported(ConditionalFeature.VIRTUAL_KEYBOARD)) { 652 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/fxvk.css"); 653 } 654 655 if (!isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) { 656 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/caspian-no-transparency.css"); 657 } 658 659 } else if (Application.STYLESHEET_MODENA.equalsIgnoreCase(stylesheetUrl)) { 660 isModena = true; 661 662 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/modena.css"); 663 664 if (isSupported(ConditionalFeature.INPUT_TOUCH)) { 665 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/touch.css"); 666 } 667 // when running on embedded add a extra stylesheet to tune performance of modena theme 668 if (PlatformUtil.isEmbedded()) { 669 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/modena-embedded-performance.css"); 670 } 671 if (PlatformUtil.isAndroid()) { 672 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/android.css"); 673 } 674 675 if (isSupported(ConditionalFeature.TWO_LEVEL_FOCUS)) { 676 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/two-level-focus.css"); 677 } 678 679 if (isSupported(ConditionalFeature.VIRTUAL_KEYBOARD)) { 680 uaStylesheets.add("com/sun/javafx/scene/control/skin/caspian/fxvk.css"); 681 } 682 683 if (!isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) { 684 uaStylesheets.add("com/sun/javafx/scene/control/skin/modena/modena-no-transparency.css"); 685 } 686 687 } else { 688 uaStylesheets.add(stylesheetUrl); 689 } 690 691 // Ensure that accessibility starts right 692 _setAccessibilityTheme(Toolkit.getToolkit().getThemeName()); 693 if (accessibilityTheme != null) { 694 uaStylesheets.add(accessibilityTheme); 695 } 696 697 AccessController.doPrivileged((PrivilegedAction) () -> { 698 StyleManager.getInstance().setUserAgentStylesheets(uaStylesheets); 699 return null; 700 }); 701 702 } 703 704 public static void addNoTransparencyStylesheetToScene(final Scene scene) { 705 if (PlatformImpl.isCaspian()) { 706 AccessController.doPrivileged((PrivilegedAction) () -> { 707 StyleManager.getInstance().addUserAgentStylesheet(scene, 708 "com/sun/javafx/scene/control/skin/caspian/caspian-no-transparency.css"); 709 return null; 710 }); 711 } else if (PlatformImpl.isModena()) { 712 AccessController.doPrivileged((PrivilegedAction) () -> { 713 StyleManager.getInstance().addUserAgentStylesheet(scene, 714 "com/sun/javafx/scene/control/skin/modena/modena-no-transparency.css"); 715 return null; 716 }); 717 } 718 } 719 720 private static boolean isSupportedImpl(ConditionalFeature feature) { 721 switch (feature) { 722 case GRAPHICS: 723 if (isGraphicsSupported == null) { 724 isGraphicsSupported = checkForClass("javafx.stage.Stage"); 725 } 726 return isGraphicsSupported; 727 case CONTROLS: 728 if (isControlsSupported == null) { 729 isControlsSupported = checkForClass( 730 "javafx.scene.control.Control"); 731 } 732 return isControlsSupported; 733 case MEDIA: 734 if (isMediaSupported == null) { 735 isMediaSupported = checkForClass( 736 "javafx.scene.media.MediaView"); 737 if (isMediaSupported && PlatformUtil.isEmbedded()) { 738 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 739 String s = System.getProperty( 740 "com.sun.javafx.experimental.embedded.media", 741 "false"); 742 isMediaSupported = Boolean.valueOf(s); 743 return null; 744 745 }); 746 } 747 } 748 return isMediaSupported; 749 case WEB: 750 if (isWebSupported == null) { 751 isWebSupported = checkForClass("javafx.scene.web.WebView"); 752 if (isWebSupported && PlatformUtil.isEmbedded()) { 753 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 754 String s = System.getProperty( 755 "com.sun.javafx.experimental.embedded.web", 756 "false"); 757 isWebSupported = Boolean.valueOf(s); 758 return null; 759 760 }); 761 } 762 } 763 return isWebSupported; 764 case SWT: 765 if (isSWTSupported == null) { 766 isSWTSupported = checkForClass("javafx.embed.swt.FXCanvas"); 767 } 768 return isSWTSupported; 769 case SWING: 770 if (isSwingSupported == null) { 771 isSwingSupported = 772 // check for JComponent first, it may not be present 773 checkForClass("javax.swing.JComponent") && 774 checkForClass("javafx.embed.swing.JFXPanel"); 775 } 776 return isSwingSupported; 777 case FXML: 778 if (isFXMLSupported == null) { 779 isFXMLSupported = checkForClass("javafx.fxml.FXMLLoader") 780 && checkForClass("javax.xml.stream.XMLInputFactory"); 781 } 782 return isFXMLSupported; 783 case TWO_LEVEL_FOCUS: 784 if (hasTwoLevelFocus == null) { 785 return Toolkit.getToolkit().isSupported(feature); 786 } 787 return hasTwoLevelFocus; 788 case VIRTUAL_KEYBOARD: 789 if (hasVirtualKeyboard == null) { 790 return Toolkit.getToolkit().isSupported(feature); 791 } 792 return hasVirtualKeyboard; 793 case INPUT_TOUCH: 794 if (hasTouch == null) { 795 return Toolkit.getToolkit().isSupported(feature); 796 } 797 return hasTouch; 798 case INPUT_MULTITOUCH: 799 if (hasMultiTouch == null) { 800 return Toolkit.getToolkit().isSupported(feature); 801 } 802 return hasMultiTouch; 803 case INPUT_POINTER: 804 if (hasPointer == null) { 805 return Toolkit.getToolkit().isSupported(feature); 806 } 807 return hasPointer; 808 default: 809 return Toolkit.getToolkit().isSupported(feature); 810 } 811 } 812 }