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