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