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