1 /*
   2  * Copyright (c) 2011, 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 sun.lwawt.macosx;
  27 
  28 import java.awt.*;
  29 import java.awt.datatransfer.Clipboard;
  30 import java.awt.dnd.*;
  31 import java.awt.dnd.peer.DragSourceContextPeer;
  32 import java.awt.event.InputEvent;
  33 import java.awt.event.InvocationEvent;
  34 import java.awt.event.KeyEvent;
  35 import java.awt.im.InputMethodHighlight;
  36 import java.awt.im.spi.InputMethodDescriptor;
  37 import java.awt.peer.*;
  38 import java.lang.reflect.*;
  39 import java.net.URL;
  40 import java.security.*;
  41 import java.util.*;
  42 import java.util.concurrent.Callable;
  43 import java.net.MalformedURLException;
  44 
  45 import sun.awt.*;
  46 import sun.awt.datatransfer.DataTransferer;
  47 import sun.java2d.opengl.OGLRenderQueue;
  48 import sun.lwawt.*;
  49 import sun.lwawt.LWWindowPeer.PeerType;
  50 import sun.security.action.GetBooleanAction;
  51 import sun.awt.image.MultiResolutionImage;
  52 
  53 import sun.util.CoreResourceBundleControl;
  54 
  55 final class NamedCursor extends Cursor {
  56     NamedCursor(String name) {
  57         super(name);
  58     }
  59 }
  60 
  61 /**
  62  * Mac OS X Cocoa-based AWT Toolkit.
  63  */
  64 public final class LWCToolkit extends LWToolkit {
  65     // While it is possible to enumerate all mouse devices
  66     // and query them for the number of buttons, the code
  67     // that does it is rather complex. Instead, we opt for
  68     // the easy way and just support up to 5 mouse buttons,
  69     // like Windows.
  70     private static final int BUTTONS = 5;
  71 
  72     private static native void initIDs();
  73 
  74     private static CInputMethodDescriptor sInputMethodDescriptor;
  75 
  76     static {
  77         System.err.flush();
  78 
  79         ResourceBundle platformResources = java.security.AccessController.doPrivileged(
  80                 new java.security.PrivilegedAction<ResourceBundle>() {
  81             @Override
  82             public ResourceBundle run() {
  83                 ResourceBundle platformResources = null;
  84                 try {
  85                     platformResources =
  86                             ResourceBundle.getBundle("sun.awt.resources.awtosx",
  87                                     CoreResourceBundleControl.getRBControlInstance());
  88                 } catch (MissingResourceException e) {
  89                     // No resource file; defaults will be used.
  90                 }
  91 
  92                 System.loadLibrary("awt");
  93                 System.loadLibrary("fontmanager");
  94 
  95                 return platformResources;
  96             }
  97         });
  98 
  99         AWTAccessor.getToolkitAccessor().setPlatformResources(platformResources);
 100 
 101         if (!GraphicsEnvironment.isHeadless()) {
 102             initIDs();
 103         }
 104         inAWT = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 105             @Override
 106             public Boolean run() {
 107                 return !Boolean.parseBoolean(System.getProperty("javafx.embed.singleThread", "false"));
 108             }
 109         });
 110     }
 111 
 112     /*
 113      * If true  we operate in normal mode and nested runloop is executed in JavaRunLoopMode
 114      * If false we operate in singleThreaded FX/AWT interop mode and nested loop uses NSDefaultRunLoopMode
 115      */
 116     private static final boolean inAWT;
 117 
 118     public LWCToolkit() {
 119         areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
 120         //set system property if not yet assigned
 121         System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
 122     }
 123 
 124     /*
 125      * System colors with default initial values, overwritten by toolkit if system values differ and are available.
 126      */
 127     private final static int NUM_APPLE_COLORS = 3;
 128     public final static int KEYBOARD_FOCUS_COLOR = 0;
 129     public final static int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
 130     public final static int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
 131     private static int[] appleColors = {
 132         0xFF808080, // keyboardFocusColor = Color.gray;
 133         0xFFC0C0C0, // secondarySelectedControlColor
 134         0xFF303030, // controlDarkShadowColor
 135     };
 136 
 137     private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
 138 
 139     @Override
 140     protected void loadSystemColors(final int[] systemColors) {
 141         if (systemColors == null) return;
 142         loadNativeColors(systemColors, appleColors);
 143     }
 144 
 145     private static class AppleSpecificColor extends Color {
 146         private final int index;
 147         AppleSpecificColor(int index) {
 148             super(appleColors[index]);
 149             this.index = index;
 150         }
 151 
 152         @Override
 153         public int getRGB() {
 154             return appleColors[index];
 155         }
 156     }
 157 
 158     /**
 159      * Returns Apple specific colors that we may expose going forward.
 160      */
 161     public static Color getAppleColor(int color) {
 162         return new AppleSpecificColor(color);
 163     }
 164 
 165     // This is only called from native code.
 166     static void systemColorsChanged() {
 167         EventQueue.invokeLater(() -> {
 168             AccessController.doPrivileged ((PrivilegedAction<Object>) () -> {
 169                 AWTAccessor.getSystemColorAccessor().updateSystemColors();
 170                 return null;
 171             });
 172         });
 173     }
 174 
 175     public static LWCToolkit getLWCToolkit() {
 176         return (LWCToolkit)Toolkit.getDefaultToolkit();
 177     }
 178 
 179     @Override
 180     protected PlatformWindow createPlatformWindow(PeerType peerType) {
 181         if (peerType == PeerType.EMBEDDED_FRAME) {
 182             return new CPlatformEmbeddedFrame();
 183         } else if (peerType == PeerType.VIEW_EMBEDDED_FRAME) {
 184             return new CViewPlatformEmbeddedFrame();
 185         } else if (peerType == PeerType.LW_FRAME) {
 186             return new CPlatformLWWindow();
 187         } else {
 188             assert (peerType == PeerType.SIMPLEWINDOW
 189                     || peerType == PeerType.DIALOG
 190                     || peerType == PeerType.FRAME);
 191             return new CPlatformWindow();
 192         }
 193     }
 194 
 195     LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) {
 196         PlatformComponent platformComponent = createPlatformComponent();
 197         PlatformWindow platformWindow = createPlatformWindow(PeerType.EMBEDDED_FRAME);
 198         return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.EMBEDDED_FRAME);
 199     }
 200 
 201     LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) {
 202         PlatformComponent platformComponent = createPlatformComponent();
 203         PlatformWindow platformWindow = createPlatformWindow(PeerType.VIEW_EMBEDDED_FRAME);
 204         return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.VIEW_EMBEDDED_FRAME);
 205     }
 206 
 207     private CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) {
 208         PlatformComponent platformComponent = createPlatformComponent();
 209         PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG);
 210         CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow);
 211         targetCreatedPeer(target, peer);
 212         return peer;
 213     }
 214 
 215     @Override
 216     public DialogPeer createDialog(Dialog target) {
 217         if (target instanceof CPrinterDialog) {
 218             return createCPrinterDialog((CPrinterDialog)target);
 219         }
 220         return super.createDialog(target);
 221     }
 222 
 223     @Override
 224     protected SecurityWarningWindow createSecurityWarning(Window ownerWindow,
 225                                                           LWWindowPeer ownerPeer) {
 226         return new CWarningWindow(ownerWindow, ownerPeer);
 227     }
 228 
 229     @Override
 230     protected PlatformComponent createPlatformComponent() {
 231         return new CPlatformComponent();
 232     }
 233 
 234     @Override
 235     protected PlatformComponent createLwPlatformComponent() {
 236         return new CPlatformLWComponent();
 237     }
 238 
 239     @Override
 240     protected FileDialogPeer createFileDialogPeer(FileDialog target) {
 241         return new CFileDialog(target);
 242     }
 243 
 244     @Override
 245     public MenuPeer createMenu(Menu target) {
 246         MenuPeer peer = new CMenu(target);
 247         targetCreatedPeer(target, peer);
 248         return peer;
 249     }
 250 
 251     @Override
 252     public MenuBarPeer createMenuBar(MenuBar target) {
 253         MenuBarPeer peer = new CMenuBar(target);
 254         targetCreatedPeer(target, peer);
 255         return peer;
 256     }
 257 
 258     @Override
 259     public MenuItemPeer createMenuItem(MenuItem target) {
 260         MenuItemPeer peer = new CMenuItem(target);
 261         targetCreatedPeer(target, peer);
 262         return peer;
 263     }
 264 
 265     @Override
 266     public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
 267         CheckboxMenuItemPeer peer = new CCheckboxMenuItem(target);
 268         targetCreatedPeer(target, peer);
 269         return peer;
 270     }
 271 
 272     @Override
 273     public PopupMenuPeer createPopupMenu(PopupMenu target) {
 274         PopupMenuPeer peer = new CPopupMenu(target);
 275         targetCreatedPeer(target, peer);
 276         return peer;
 277     }
 278 
 279     @Override
 280     public SystemTrayPeer createSystemTray(SystemTray target) {
 281         return new CSystemTray();
 282     }
 283 
 284     @Override
 285     public TrayIconPeer createTrayIcon(TrayIcon target) {
 286         TrayIconPeer peer = new CTrayIcon(target);
 287         targetCreatedPeer(target, peer);
 288         return peer;
 289     }
 290 
 291     @Override
 292     protected DesktopPeer createDesktopPeer(Desktop target) {
 293         return new CDesktopPeer();
 294     }
 295 
 296     @Override
 297     public LWCursorManager getCursorManager() {
 298         return CCursorManager.getInstance();
 299     }
 300 
 301     @Override
 302     public Cursor createCustomCursor(final Image cursor, final Point hotSpot,
 303                                      final String name)
 304             throws IndexOutOfBoundsException, HeadlessException {
 305         return new CCustomCursor(cursor, hotSpot, name);
 306     }
 307 
 308     @Override
 309     public Dimension getBestCursorSize(final int preferredWidth,
 310                                        final int preferredHeight)
 311             throws HeadlessException {
 312         return CCustomCursor.getBestCursorSize(preferredWidth, preferredHeight);
 313     }
 314 
 315     @Override
 316     protected void platformCleanup() {
 317         // TODO Auto-generated method stub
 318     }
 319 
 320     @Override
 321     protected void platformInit() {
 322         // TODO Auto-generated method stub
 323     }
 324 
 325     @Override
 326     protected void platformRunMessage() {
 327         // TODO Auto-generated method stub
 328     }
 329 
 330     @Override
 331     protected void platformShutdown() {
 332         // TODO Auto-generated method stub
 333     }
 334 
 335     class OSXPlatformFont extends sun.awt.PlatformFont
 336     {
 337         OSXPlatformFont(String name, int style)
 338         {
 339             super(name, style);
 340         }
 341         @Override
 342         protected char getMissingGlyphCharacter()
 343         {
 344             // Follow up for real implementation
 345             return (char)0xfff8; // see http://developer.apple.com/fonts/LastResortFont/
 346         }
 347     }
 348     @Override
 349     public FontPeer getFontPeer(String name, int style) {
 350         return new OSXPlatformFont(name, style);
 351     }
 352 
 353     @Override
 354     protected int getScreenHeight() {
 355         return GraphicsEnvironment.getLocalGraphicsEnvironment()
 356                 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().height;
 357     }
 358 
 359     @Override
 360     protected int getScreenWidth() {
 361         return GraphicsEnvironment.getLocalGraphicsEnvironment()
 362                 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().width;
 363     }
 364 
 365     @Override
 366     protected void initializeDesktopProperties() {
 367         super.initializeDesktopProperties();
 368         Map <Object, Object> fontHints = new HashMap<>();
 369         fontHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 370         fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 371         desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints);
 372         desktopProperties.put("awt.mouse.numButtons", BUTTONS);
 373 
 374         // These DnD properties must be set, otherwise Swing ends up spewing NPEs
 375         // all over the place. The values came straight off of MToolkit.
 376         desktopProperties.put("DnD.Autoscroll.initialDelay", new Integer(50));
 377         desktopProperties.put("DnD.Autoscroll.interval", new Integer(50));
 378         desktopProperties.put("DnD.Autoscroll.cursorHysteresis", new Integer(5));
 379 
 380         desktopProperties.put("DnD.isDragImageSupported", new Boolean(true));
 381 
 382         // Register DnD cursors
 383         desktopProperties.put("DnD.Cursor.CopyDrop", new NamedCursor("DnD.Cursor.CopyDrop"));
 384         desktopProperties.put("DnD.Cursor.MoveDrop", new NamedCursor("DnD.Cursor.MoveDrop"));
 385         desktopProperties.put("DnD.Cursor.LinkDrop", new NamedCursor("DnD.Cursor.LinkDrop"));
 386         desktopProperties.put("DnD.Cursor.CopyNoDrop", new NamedCursor("DnD.Cursor.CopyNoDrop"));
 387         desktopProperties.put("DnD.Cursor.MoveNoDrop", new NamedCursor("DnD.Cursor.MoveNoDrop"));
 388         desktopProperties.put("DnD.Cursor.LinkNoDrop", new NamedCursor("DnD.Cursor.LinkNoDrop"));
 389     }
 390 
 391     @Override
 392     protected boolean syncNativeQueue(long timeout) {
 393         return nativeSyncQueue(timeout);
 394     }
 395 
 396     @Override
 397     public native void beep();
 398 
 399     @Override
 400     public int getScreenResolution() throws HeadlessException {
 401         return (int) ((CGraphicsDevice) GraphicsEnvironment
 402                 .getLocalGraphicsEnvironment().getDefaultScreenDevice())
 403                 .getXResolution();
 404     }
 405 
 406     @Override
 407     public Insets getScreenInsets(final GraphicsConfiguration gc) {
 408         return ((CGraphicsConfig) gc).getDevice().getScreenInsets();
 409     }
 410 
 411     @Override
 412     public void sync() {
 413         // flush the OGL pipeline (this is a no-op if OGL is not enabled)
 414         OGLRenderQueue.sync();
 415         // setNeedsDisplay() selector was sent to the appropriate CALayer so now
 416         // we have to flush the native selectors queue.
 417         flushNativeSelectors();
 418     }
 419 
 420     @Override
 421     public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
 422         return new CRobot(target, (CGraphicsDevice)screen);
 423     }
 424 
 425     private native boolean isCapsLockOn();
 426 
 427     /*
 428      * NOTE: Among the keys this method is supposed to check,
 429      * only Caps Lock works as a true locking key with OS X.
 430      * There is no Scroll Lock key on modern Apple keyboards,
 431      * and with a PC keyboard plugged in Scroll Lock is simply
 432      * ignored: no LED lights up if you press it.
 433      * The key located at the same position on Apple keyboards
 434      * as Num Lock on PC keyboards is called Clear, doesn't lock
 435      * anything and is used for entirely different purpose.
 436      */
 437     @Override
 438     public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
 439         switch (keyCode) {
 440             case KeyEvent.VK_NUM_LOCK:
 441             case KeyEvent.VK_SCROLL_LOCK:
 442             case KeyEvent.VK_KANA_LOCK:
 443                 throw new UnsupportedOperationException("Toolkit.getLockingKeyState");
 444 
 445             case KeyEvent.VK_CAPS_LOCK:
 446                 return isCapsLockOn();
 447 
 448             default:
 449                 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
 450         }
 451     }
 452 
 453     //Is it allowed to generate events assigned to extra mouse buttons.
 454     //Set to true by default.
 455     private static boolean areExtraMouseButtonsEnabled = true;
 456 
 457     @Override
 458     public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
 459         return areExtraMouseButtonsEnabled;
 460     }
 461 
 462     @Override
 463     public int getNumberOfButtons(){
 464         return BUTTONS;
 465     }
 466 
 467     @Override
 468     public boolean isTraySupported() {
 469         return true;
 470     }
 471 
 472     @Override
 473     public DataTransferer getDataTransferer() {
 474         return CDataTransferer.getInstanceImpl();
 475     }
 476 
 477     @Override
 478     public boolean isAlwaysOnTopSupported() {
 479         return true;
 480     }
 481 
 482     // Intended to be called from the LWCToolkit.m only.
 483     private static void installToolkitThreadInJava() {
 484         Thread.currentThread().setName(CThreading.APPKIT_THREAD_NAME);
 485         AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
 486             Thread.currentThread().setContextClassLoader(null);
 487             return null;
 488         });
 489     }
 490 
 491     @Override
 492     public boolean isWindowOpacitySupported() {
 493         return true;
 494     }
 495 
 496     @Override
 497     public boolean isFrameStateSupported(int state) throws HeadlessException {
 498         switch (state) {
 499             case Frame.NORMAL:
 500             case Frame.ICONIFIED:
 501             case Frame.MAXIMIZED_BOTH:
 502                 return true;
 503             default:
 504                 return false;
 505         }
 506     }
 507 
 508     /**
 509      * Determines which modifier key is the appropriate accelerator
 510      * key for menu shortcuts.
 511      * <p>
 512      * Menu shortcuts, which are embodied in the
 513      * <code>MenuShortcut</code> class, are handled by the
 514      * <code>MenuBar</code> class.
 515      * <p>
 516      * By default, this method returns <code>Event.CTRL_MASK</code>.
 517      * Toolkit implementations should override this method if the
 518      * <b>Control</b> key isn't the correct key for accelerators.
 519      * @return    the modifier mask on the <code>Event</code> class
 520      *                 that is used for menu shortcuts on this toolkit.
 521      * @see       java.awt.MenuBar
 522      * @see       java.awt.MenuShortcut
 523      * @since     JDK1.1
 524      */
 525     @Override
 526     public int getMenuShortcutKeyMask() {
 527         return Event.META_MASK;
 528     }
 529 
 530     @Override
 531     public Image getImage(final String filename) {
 532         final Image nsImage = checkForNSImage(filename);
 533         if (nsImage != null) {
 534             return nsImage;
 535         }
 536 
 537         if (imageCached(filename)) {
 538             return super.getImage(filename);
 539         }
 540 
 541         String filename2x = getScaledImageName(filename);
 542         return (imageExists(filename2x))
 543                 ? getImageWithResolutionVariant(filename, filename2x)
 544                 : super.getImage(filename);
 545     }
 546 
 547     @Override
 548     public Image getImage(URL url) {
 549 
 550         if (imageCached(url)) {
 551             return super.getImage(url);
 552         }
 553 
 554         URL url2x = getScaledImageURL(url);
 555         return (imageExists(url2x))
 556                 ? getImageWithResolutionVariant(url, url2x) : super.getImage(url);
 557     }
 558 
 559     private static final String nsImagePrefix = "NSImage://";
 560     private Image checkForNSImage(final String imageName) {
 561         if (imageName == null) return null;
 562         if (!imageName.startsWith(nsImagePrefix)) return null;
 563         return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length()));
 564     }
 565 
 566     // Thread-safe Object.equals() called from native
 567     public static boolean doEquals(final Object a, final Object b, Component c) {
 568         if (a == b) return true;
 569 
 570         final boolean[] ret = new boolean[1];
 571 
 572         try {  invokeAndWait(new Runnable() { public void run() { synchronized(ret) {
 573             ret[0] = a.equals(b);
 574         }}}, c); } catch (Exception e) { e.printStackTrace(); }
 575 
 576         synchronized(ret) { return ret[0]; }
 577     }
 578 
 579     public static <T> T invokeAndWait(final Callable<T> callable,
 580                                       Component component) throws Exception {
 581         final CallableWrapper<T> wrapper = new CallableWrapper<>(callable);
 582         invokeAndWait(wrapper, component);
 583         return wrapper.getResult();
 584     }
 585 
 586     static final class CallableWrapper<T> implements Runnable {
 587         final Callable<T> callable;
 588         T object;
 589         Exception e;
 590 
 591         CallableWrapper(final Callable<T> callable) {
 592             this.callable = callable;
 593         }
 594 
 595         @Override
 596         public void run() {
 597             try {
 598                 object = callable.call();
 599             } catch (final Exception e) {
 600                 this.e = e;
 601             }
 602         }
 603 
 604         public T getResult() throws Exception {
 605             if (e != null) throw e;
 606             return object;
 607         }
 608     }
 609 
 610     /**
 611      * Kicks an event over to the appropriate eventqueue and waits for it to
 612      * finish To avoid deadlocking, we manually run the NSRunLoop while waiting
 613      * Any selector invoked using ThreadUtilities performOnMainThread will be
 614      * processed in doAWTRunLoop The InvocationEvent will call
 615      * LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual
 616      * runloop Does not dispatch native events while in the loop
 617      */
 618     public static void invokeAndWait(Runnable runnable, Component component)
 619             throws InvocationTargetException {
 620         final long mediator = createAWTRunLoopMediator();
 621 
 622         InvocationEvent invocationEvent =
 623                 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(),
 624                         runnable,
 625                         () -> {
 626                             if (mediator != 0) {
 627                                 stopAWTRunLoop(mediator);
 628                             }
 629                         },
 630                         true);
 631 
 632         if (component != null) {
 633             AppContext appContext = SunToolkit.targetToAppContext(component);
 634             SunToolkit.postEvent(appContext, invocationEvent);
 635 
 636             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 637             SunToolkit.flushPendingEvents(appContext);
 638         } else {
 639             // This should be the equivalent to EventQueue.invokeAndWait
 640             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 641         }
 642 
 643         doAWTRunLoop(mediator, false);
 644 
 645         Throwable eventException = invocationEvent.getException();
 646         if (eventException != null) {
 647             if (eventException instanceof UndeclaredThrowableException) {
 648                 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
 649             }
 650             throw new InvocationTargetException(eventException);
 651         }
 652     }
 653 
 654     public static void invokeLater(Runnable event, Component component)
 655             throws InvocationTargetException {
 656         final InvocationEvent invocationEvent =
 657                 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event);
 658 
 659         if (component != null) {
 660             final AppContext appContext = SunToolkit.targetToAppContext(component);
 661             SunToolkit.postEvent(appContext, invocationEvent);
 662 
 663             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 664             SunToolkit.flushPendingEvents(appContext);
 665         } else {
 666             // This should be the equivalent to EventQueue.invokeAndWait
 667             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 668         }
 669 
 670         final Throwable eventException = invocationEvent.getException();
 671         if (eventException == null) return;
 672 
 673         if (eventException instanceof UndeclaredThrowableException) {
 674             throw new InvocationTargetException(((UndeclaredThrowableException)eventException).getUndeclaredThrowable());
 675         }
 676         throw new InvocationTargetException(eventException);
 677     }
 678 
 679     // This exists purely to get around permissions issues with getSystemEventQueueImpl
 680     EventQueue getSystemEventQueueForInvokeAndWait() {
 681         return getSystemEventQueueImpl();
 682     }
 683 
 684 // DnD support
 685 
 686     @Override
 687     public DragSourceContextPeer createDragSourceContextPeer(
 688             DragGestureEvent dge) throws InvalidDnDOperationException {
 689         return CDragSourceContextPeer.createDragSourceContextPeer(dge);
 690     }
 691 
 692     @Override
 693     public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
 694             Class<T> abstractRecognizerClass, DragSource ds, Component c,
 695             int srcActions, DragGestureListener dgl) {
 696         DragGestureRecognizer dgr = null;
 697 
 698         // Create a new mouse drag gesture recognizer if we have a class match:
 699         if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
 700             dgr = new CMouseDragGestureRecognizer(ds, c, srcActions, dgl);
 701 
 702         return (T)dgr;
 703     }
 704 
 705 // InputMethodSupport Method
 706     /**
 707      * Returns the default keyboard locale of the underlying operating system
 708      */
 709     @Override
 710     public Locale getDefaultKeyboardLocale() {
 711         Locale locale = CInputMethod.getNativeLocale();
 712 
 713         if (locale == null) {
 714             return super.getDefaultKeyboardLocale();
 715         }
 716 
 717         return locale;
 718     }
 719 
 720     @Override
 721     public InputMethodDescriptor getInputMethodAdapterDescriptor() {
 722         if (sInputMethodDescriptor == null)
 723             sInputMethodDescriptor = new CInputMethodDescriptor();
 724 
 725         return sInputMethodDescriptor;
 726     }
 727 
 728     /**
 729      * Returns a map of visual attributes for thelevel description
 730      * of the given input method highlight, or null if no mapping is found.
 731      * The style field of the input method highlight is ignored. The map
 732      * returned is unmodifiable.
 733      * @param highlight input method highlight
 734      * @return style attribute map, or null
 735      * @since 1.3
 736      */
 737     @Override
 738     public Map mapInputMethodHighlight(InputMethodHighlight highlight) {
 739         return CInputMethod.mapInputMethodHighlight(highlight);
 740     }
 741 
 742     /**
 743      * Returns key modifiers used by Swing to set up a focus accelerator key
 744      * stroke.
 745      */
 746     @Override
 747     public int getFocusAcceleratorKeyMask() {
 748         return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
 749     }
 750 
 751     /**
 752      * Tests whether specified key modifiers mask can be used to enter a
 753      * printable character.
 754      */
 755     @Override
 756     public boolean isPrintableCharacterModifiersMask(int mods) {
 757         return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
 758     }
 759 
 760     /**
 761      * Returns whether popup is allowed to be shown above the task bar.
 762      */
 763     @Override
 764     public boolean canPopupOverlapTaskBar() {
 765         return false;
 766     }
 767 
 768     private static Boolean sunAwtDisableCALayers = null;
 769 
 770     /**
 771      * Returns the value of "sun.awt.disableCALayers" property. Default
 772      * value is {@code false}.
 773      */
 774     public static synchronized boolean getSunAwtDisableCALayers() {
 775         if (sunAwtDisableCALayers == null) {
 776             sunAwtDisableCALayers = AccessController.doPrivileged(
 777                 new GetBooleanAction("sun.awt.disableCALayers"));
 778         }
 779         return sunAwtDisableCALayers;
 780     }
 781 
 782     /*
 783      * Returns true if the application (one of its windows) owns keyboard focus.
 784      */
 785     native boolean isApplicationActive();
 786 
 787     /**
 788      * Returns true if AWT toolkit is embedded, false otherwise.
 789      *
 790      * @return true if AWT toolkit is embedded, false otherwise
 791      */
 792     public static native boolean isEmbedded();
 793 
 794     /************************
 795      * Native methods section
 796      ************************/
 797 
 798     static native long createAWTRunLoopMediator();
 799     /**
 800      * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
 801      * by [JNFRunLoop performOnMainThreadWaiting] are processed.
 802      * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
 803      * @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
 804      *                      Additional attention is needed when using this feature as we short-circuit normal event
 805      *                      processing which could break Appkit.
 806      *                      (One known example is when the window is resized with the mouse)
 807      *
 808      *                      if false - all events come after exit form the nested loop
 809      */
 810     static void doAWTRunLoop(long mediator, boolean processEvents) {
 811         doAWTRunLoopImpl(mediator, processEvents, inAWT);
 812     }
 813     private static native void doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT);
 814     static native void stopAWTRunLoop(long mediator);
 815 
 816     private native boolean nativeSyncQueue(long timeout);
 817 
 818     /**
 819      * Just spin a single empty block synchronously.
 820      */
 821     private static native void flushNativeSelectors();
 822 
 823     @Override
 824     public Clipboard createPlatformClipboard() {
 825         return new CClipboard("System");
 826     }
 827 
 828     @Override
 829     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
 830         return (exclusionType == null) ||
 831             (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
 832             (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
 833             (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
 834     }
 835 
 836     @Override
 837     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
 838         //TODO: FileDialog blocks excluded windows...
 839         //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).
 840         return (modalityType == null) ||
 841             (modalityType == Dialog.ModalityType.MODELESS) ||
 842             (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
 843             (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
 844             (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
 845     }
 846 
 847     @Override
 848     public boolean isWindowShapingSupported() {
 849         return true;
 850     }
 851 
 852     @Override
 853     public boolean isWindowTranslucencySupported() {
 854         return true;
 855     }
 856 
 857     @Override
 858     public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
 859         return true;
 860     }
 861 
 862     @Override
 863     public boolean isSwingBackbufferTranslucencySupported() {
 864         return true;
 865     }
 866 
 867     @Override
 868     public boolean enableInputMethodsForTextComponent() {
 869         return true;
 870     }
 871 
 872     private static URL getScaledImageURL(URL url) {
 873         try {
 874             String scaledImagePath = getScaledImageName(url.getPath());
 875             return scaledImagePath == null ? null : new URL(url.getProtocol(),
 876                     url.getHost(), url.getPort(), scaledImagePath);
 877         } catch (MalformedURLException e) {
 878             return null;
 879         }
 880     }
 881 
 882     private static String getScaledImageName(String path) {
 883         if (!isValidPath(path)) {
 884             return null;
 885         }
 886 
 887         int slash = path.lastIndexOf('/');
 888         String name = (slash < 0) ? path : path.substring(slash + 1);
 889 
 890         if (name.contains("@2x")) {
 891             return null;
 892         }
 893 
 894         int dot = name.lastIndexOf('.');
 895         String name2x = (dot < 0) ? name + "@2x"
 896                 : name.substring(0, dot) + "@2x" + name.substring(dot);
 897         return (slash < 0) ? name2x : path.substring(0, slash + 1) + name2x;
 898     }
 899 
 900     private static boolean isValidPath(String path) {
 901         return path != null &&
 902                 !path.isEmpty() &&
 903                 !path.endsWith("/") &&
 904                 !path.endsWith(".");
 905     }
 906 }