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