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