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