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