1 /* 2 * Copyright (c) 2011, 2016, 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 com.apple.laf.AquaMenuBarUI; 29 import java.awt.peer.TaskbarPeer; 30 import java.awt.*; 31 import java.awt.datatransfer.Clipboard; 32 import java.awt.dnd.*; 33 import java.awt.dnd.peer.DragSourceContextPeer; 34 import java.awt.event.InputEvent; 35 import java.awt.event.InvocationEvent; 36 import java.awt.event.KeyEvent; 37 import java.awt.font.TextAttribute; 38 import java.awt.im.InputMethodHighlight; 39 import java.awt.im.spi.InputMethodDescriptor; 40 import java.awt.peer.*; 41 import java.lang.reflect.*; 42 import java.net.URL; 43 import java.security.*; 44 import java.util.*; 45 import java.util.concurrent.Callable; 46 import java.net.MalformedURLException; 47 import javax.swing.UIManager; 48 49 import sun.awt.*; 50 import sun.awt.datatransfer.DataTransferer; 51 import sun.awt.util.ThreadGroupUtils; 52 import sun.java2d.opengl.OGLRenderQueue; 53 import sun.lwawt.*; 54 import sun.lwawt.LWWindowPeer.PeerType; 55 import sun.security.action.GetBooleanAction; 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 = ResourceBundle.getBundle("sun.awt.resources.awtosx"); 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 static final int NUM_APPLE_COLORS = 3; 130 public static final int KEYBOARD_FOCUS_COLOR = 0; 131 public static final int INACTIVE_SELECTION_BACKGROUND_COLOR = 1; 132 public static final 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 public DesktopPeer createDesktopPeer(Desktop target) { 296 return new CDesktopPeer(); 297 } 298 299 @Override 300 public TaskbarPeer createTaskbarPeer(Taskbar target) { 301 return new CTaskbarPeer(); 302 } 303 304 @Override 305 public LWCursorManager getCursorManager() { 306 return CCursorManager.getInstance(); 307 } 308 309 @Override 310 public Cursor createCustomCursor(final Image cursor, final Point hotSpot, 311 final String name) 312 throws IndexOutOfBoundsException, HeadlessException { 313 return new CCustomCursor(cursor, hotSpot, name); 314 } 315 316 @Override 317 public Dimension getBestCursorSize(final int preferredWidth, 318 final int preferredHeight) 319 throws HeadlessException { 320 return CCustomCursor.getBestCursorSize(preferredWidth, preferredHeight); 321 } 322 323 @Override 324 protected void platformCleanup() { 325 // TODO Auto-generated method stub 326 } 327 328 @Override 329 protected void platformInit() { 330 // TODO Auto-generated method stub 331 } 332 333 @Override 334 protected void platformRunMessage() { 335 // TODO Auto-generated method stub 336 } 337 338 @Override 339 protected void platformShutdown() { 340 // TODO Auto-generated method stub 341 } 342 343 class OSXPlatformFont extends sun.awt.PlatformFont 344 { 345 OSXPlatformFont(String name, int style) 346 { 347 super(name, style); 348 } 349 @Override 350 protected char getMissingGlyphCharacter() 351 { 352 // Follow up for real implementation 353 return (char)0xfff8; // see http://developer.apple.com/fonts/LastResortFont/ 354 } 355 } 356 @Override 357 public FontPeer getFontPeer(String name, int style) { 358 return new OSXPlatformFont(name, style); 359 } 360 361 @Override 362 protected int getScreenHeight() { 363 return GraphicsEnvironment.getLocalGraphicsEnvironment() 364 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().height; 365 } 366 367 @Override 368 protected int getScreenWidth() { 369 return GraphicsEnvironment.getLocalGraphicsEnvironment() 370 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().width; 371 } 372 373 @Override 374 protected void initializeDesktopProperties() { 375 super.initializeDesktopProperties(); 376 Map <Object, Object> fontHints = new HashMap<>(); 377 fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); 378 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); 379 desktopProperties.put("awt.mouse.numButtons", BUTTONS); 380 381 // These DnD properties must be set, otherwise Swing ends up spewing NPEs 382 // all over the place. The values came straight off of MToolkit. 383 desktopProperties.put("DnD.Autoscroll.initialDelay", Integer.valueOf(50)); 384 desktopProperties.put("DnD.Autoscroll.interval", Integer.valueOf(50)); 385 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", Integer.valueOf(5)); 386 387 desktopProperties.put("DnD.isDragImageSupported", Boolean.TRUE); 388 389 // Register DnD cursors 390 desktopProperties.put("DnD.Cursor.CopyDrop", new NamedCursor("DnD.Cursor.CopyDrop")); 391 desktopProperties.put("DnD.Cursor.MoveDrop", new NamedCursor("DnD.Cursor.MoveDrop")); 392 desktopProperties.put("DnD.Cursor.LinkDrop", new NamedCursor("DnD.Cursor.LinkDrop")); 393 desktopProperties.put("DnD.Cursor.CopyNoDrop", new NamedCursor("DnD.Cursor.CopyNoDrop")); 394 desktopProperties.put("DnD.Cursor.MoveNoDrop", new NamedCursor("DnD.Cursor.MoveNoDrop")); 395 desktopProperties.put("DnD.Cursor.LinkNoDrop", new NamedCursor("DnD.Cursor.LinkNoDrop")); 396 } 397 398 @Override 399 protected boolean syncNativeQueue(long timeout) { 400 return nativeSyncQueue(timeout); 401 } 402 403 @Override 404 public native void beep(); 405 406 @Override 407 public int getScreenResolution() throws HeadlessException { 408 return (int) ((CGraphicsDevice) GraphicsEnvironment 409 .getLocalGraphicsEnvironment().getDefaultScreenDevice()) 410 .getXResolution(); 411 } 412 413 @Override 414 public Insets getScreenInsets(final GraphicsConfiguration gc) { 415 return ((CGraphicsConfig) gc).getDevice().getScreenInsets(); 416 } 417 418 @Override 419 public void sync() { 420 // flush the OGL pipeline (this is a no-op if OGL is not enabled) 421 OGLRenderQueue.sync(); 422 // setNeedsDisplay() selector was sent to the appropriate CALayer so now 423 // we have to flush the native selectors queue. 424 flushNativeSelectors(); 425 } 426 427 @Override 428 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 429 return new CRobot(target, (CGraphicsDevice)screen); 430 } 431 432 private native boolean isCapsLockOn(); 433 434 /* 435 * NOTE: Among the keys this method is supposed to check, 436 * only Caps Lock works as a true locking key with OS X. 437 * There is no Scroll Lock key on modern Apple keyboards, 438 * and with a PC keyboard plugged in Scroll Lock is simply 439 * ignored: no LED lights up if you press it. 440 * The key located at the same position on Apple keyboards 441 * as Num Lock on PC keyboards is called Clear, doesn't lock 442 * anything and is used for entirely different purpose. 443 */ 444 @Override 445 public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException { 446 switch (keyCode) { 447 case KeyEvent.VK_NUM_LOCK: 448 case KeyEvent.VK_SCROLL_LOCK: 449 case KeyEvent.VK_KANA_LOCK: 450 throw new UnsupportedOperationException("Toolkit.getLockingKeyState"); 451 452 case KeyEvent.VK_CAPS_LOCK: 453 return isCapsLockOn(); 454 455 default: 456 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState"); 457 } 458 } 459 460 //Is it allowed to generate events assigned to extra mouse buttons. 461 //Set to true by default. 462 private static boolean areExtraMouseButtonsEnabled = true; 463 464 @Override 465 public boolean areExtraMouseButtonsEnabled() throws HeadlessException { 466 return areExtraMouseButtonsEnabled; 467 } 468 469 @Override 470 public int getNumberOfButtons(){ 471 return BUTTONS; 472 } 473 474 @Override 475 public boolean isTraySupported() { 476 return true; 477 } 478 479 @Override 480 public DataTransferer getDataTransferer() { 481 return CDataTransferer.getInstanceImpl(); 482 } 483 484 @Override 485 public boolean isAlwaysOnTopSupported() { 486 return true; 487 } 488 489 private static final String APPKIT_THREAD_NAME = "AppKit Thread"; 490 491 // Intended to be called from the LWCToolkit.m only. 492 private static void installToolkitThreadInJava() { 493 Thread.currentThread().setName(APPKIT_THREAD_NAME); 494 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 495 Thread.currentThread().setContextClassLoader(null); 496 return null; 497 }); 498 } 499 500 @Override 501 public boolean isWindowOpacitySupported() { 502 return true; 503 } 504 505 @Override 506 public boolean isFrameStateSupported(int state) throws HeadlessException { 507 switch (state) { 508 case Frame.NORMAL: 509 case Frame.ICONIFIED: 510 case Frame.MAXIMIZED_BOTH: 511 return true; 512 default: 513 return false; 514 } 515 } 516 517 /** 518 * Determines which modifier key is the appropriate accelerator 519 * key for menu shortcuts. 520 * <p> 521 * Menu shortcuts, which are embodied in the 522 * {@code MenuShortcut} class, are handled by the 523 * {@code MenuBar} class. 524 * <p> 525 * By default, this method returns {@code Event.CTRL_MASK}. 526 * Toolkit implementations should override this method if the 527 * <b>Control</b> key isn't the correct key for accelerators. 528 * @return the modifier mask on the {@code Event} class 529 * that is used for menu shortcuts on this toolkit. 530 * @see java.awt.MenuBar 531 * @see java.awt.MenuShortcut 532 * @since 1.1 533 */ 534 @Override 535 public int getMenuShortcutKeyMask() { 536 return Event.META_MASK; 537 } 538 539 @Override 540 public Image getImage(final String filename) { 541 final Image nsImage = checkForNSImage(filename); 542 if (nsImage != null) { 543 return nsImage; 544 } 545 546 if (imageCached(filename)) { 547 return super.getImage(filename); 548 } 549 550 String filename2x = getScaledImageName(filename); 551 return (imageExists(filename2x)) 552 ? getImageWithResolutionVariant(filename, filename2x) 553 : super.getImage(filename); 554 } 555 556 @Override 557 public Image getImage(URL url) { 558 559 if (imageCached(url)) { 560 return super.getImage(url); 561 } 562 563 URL url2x = getScaledImageURL(url); 564 return (imageExists(url2x)) 565 ? getImageWithResolutionVariant(url, url2x) : super.getImage(url); 566 } 567 568 private static final String nsImagePrefix = "NSImage://"; 569 private Image checkForNSImage(final String imageName) { 570 if (imageName == null) return null; 571 if (!imageName.startsWith(nsImagePrefix)) return null; 572 return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length())); 573 } 574 575 // Thread-safe Object.equals() called from native 576 public static boolean doEquals(final Object a, final Object b, Component c) { 577 if (a == b) return true; 578 579 final boolean[] ret = new boolean[1]; 580 581 try { invokeAndWait(new Runnable() { @Override 582 public void run() { synchronized(ret) { 583 ret[0] = a.equals(b); 584 }}}, c); } catch (Exception e) { e.printStackTrace(); } 585 586 synchronized(ret) { return ret[0]; } 587 } 588 589 public static <T> T invokeAndWait(final Callable<T> callable, 590 Component component) throws Exception { 591 final CallableWrapper<T> wrapper = new CallableWrapper<>(callable); 592 invokeAndWait(wrapper, component); 593 return wrapper.getResult(); 594 } 595 596 static final class CallableWrapper<T> implements Runnable { 597 final Callable<T> callable; 598 T object; 599 Exception e; 600 601 CallableWrapper(final Callable<T> callable) { 602 this.callable = callable; 603 } 604 605 @Override 606 public void run() { 607 try { 608 object = callable.call(); 609 } catch (final Exception e) { 610 this.e = e; 611 } 612 } 613 614 public T getResult() throws Exception { 615 if (e != null) throw e; 616 return object; 617 } 618 } 619 620 /** 621 * Kicks an event over to the appropriate event queue and waits for it to 622 * finish To avoid deadlocking, we manually run the NSRunLoop while waiting 623 * Any selector invoked using ThreadUtilities performOnMainThread will be 624 * processed in doAWTRunLoop The InvocationEvent will call 625 * LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual 626 * run loop. Does not dispatch native events while in the loop 627 */ 628 public static void invokeAndWait(Runnable runnable, Component component) 629 throws InvocationTargetException { 630 Objects.requireNonNull(component, "Null component provided to invokeAndWait"); 631 632 long mediator = createAWTRunLoopMediator(); 633 InvocationEvent invocationEvent = 634 new InvocationEvent(component, 635 runnable, 636 () -> { 637 if (mediator != 0) { 638 stopAWTRunLoop(mediator); 639 } 640 }, 641 true); 642 643 AppContext appContext = SunToolkit.targetToAppContext(component); 644 SunToolkit.postEvent(appContext, invocationEvent); 645 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock 646 SunToolkit.flushPendingEvents(appContext); 647 doAWTRunLoop(mediator, false); 648 649 checkException(invocationEvent); 650 } 651 652 public static void invokeLater(Runnable event, Component component) 653 throws InvocationTargetException { 654 Objects.requireNonNull(component, "Null component provided to invokeLater"); 655 656 InvocationEvent invocationEvent = new InvocationEvent(component, event); 657 658 AppContext appContext = SunToolkit.targetToAppContext(component); 659 SunToolkit.postEvent(SunToolkit.targetToAppContext(component), invocationEvent); 660 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock 661 SunToolkit.flushPendingEvents(appContext); 662 663 checkException(invocationEvent); 664 } 665 666 /** 667 * Checks if exception occurred while {@code InvocationEvent} was processed and rethrows it as 668 * an {@code InvocationTargetException} 669 * 670 * @param event the event to check for an exception 671 * @throws InvocationTargetException if exception occurred when event was processed 672 */ 673 private static void checkException(InvocationEvent event) throws InvocationTargetException { 674 Throwable eventException = event.getException(); 675 if (eventException == null) return; 676 677 if (eventException instanceof UndeclaredThrowableException) { 678 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable(); 679 } 680 throw new InvocationTargetException(eventException); 681 } 682 683 /** 684 * Schedules a {@code Runnable} execution on the Appkit thread after a delay 685 * @param r a {@code Runnable} to execute 686 * @param delay a delay in milliseconds 687 */ 688 static native void performOnMainThreadAfterDelay(Runnable r, long delay); 689 690 // DnD support 691 692 @Override 693 public DragSourceContextPeer createDragSourceContextPeer( 694 DragGestureEvent dge) throws InvalidDnDOperationException { 695 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent()); 696 if (f != null) { 697 return f.createDragSourceContextPeer(dge); 698 } 699 700 return CDragSourceContextPeer.createDragSourceContextPeer(dge); 701 } 702 703 @Override 704 @SuppressWarnings("unchecked") 705 public <T extends DragGestureRecognizer> T createDragGestureRecognizer( 706 Class<T> abstractRecognizerClass, DragSource ds, Component c, 707 int srcActions, DragGestureListener dgl) { 708 final LightweightFrame f = SunToolkit.getLightweightFrame(c); 709 if (f != null) { 710 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl); 711 } 712 713 DragGestureRecognizer dgr = null; 714 715 // Create a new mouse drag gesture recognizer if we have a class match: 716 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) 717 dgr = new CMouseDragGestureRecognizer(ds, c, srcActions, dgl); 718 719 return (T)dgr; 720 } 721 722 @Override 723 protected PlatformDropTarget createDropTarget(DropTarget dropTarget, 724 Component component, 725 LWComponentPeer<?, ?> peer) { 726 return new CDropTarget(dropTarget, component, peer); 727 } 728 729 // InputMethodSupport Method 730 /** 731 * Returns the default keyboard locale of the underlying operating system 732 */ 733 @Override 734 public Locale getDefaultKeyboardLocale() { 735 Locale locale = CInputMethod.getNativeLocale(); 736 737 if (locale == null) { 738 return super.getDefaultKeyboardLocale(); 739 } 740 741 return locale; 742 } 743 744 @Override 745 public InputMethodDescriptor getInputMethodAdapterDescriptor() { 746 if (sInputMethodDescriptor == null) 747 sInputMethodDescriptor = new CInputMethodDescriptor(); 748 749 return sInputMethodDescriptor; 750 } 751 752 /** 753 * Returns a map of visual attributes for thelevel description 754 * of the given input method highlight, or null if no mapping is found. 755 * The style field of the input method highlight is ignored. The map 756 * returned is unmodifiable. 757 * @param highlight input method highlight 758 * @return style attribute map, or null 759 * @since 1.3 760 */ 761 @Override 762 public Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) { 763 return CInputMethod.mapInputMethodHighlight(highlight); 764 } 765 766 /** 767 * Returns key modifiers used by Swing to set up a focus accelerator key 768 * stroke. 769 */ 770 @Override 771 public int getFocusAcceleratorKeyMask() { 772 return InputEvent.CTRL_MASK | InputEvent.ALT_MASK; 773 } 774 775 /** 776 * Tests whether specified key modifiers mask can be used to enter a 777 * printable character. 778 */ 779 @Override 780 public boolean isPrintableCharacterModifiersMask(int mods) { 781 return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0); 782 } 783 784 /** 785 * Returns whether popup is allowed to be shown above the task bar. 786 */ 787 @Override 788 public boolean canPopupOverlapTaskBar() { 789 return false; 790 } 791 792 private static Boolean sunAwtDisableCALayers = null; 793 794 /** 795 * Returns the value of "sun.awt.disableCALayers" property. Default 796 * value is {@code false}. 797 */ 798 public static synchronized boolean getSunAwtDisableCALayers() { 799 if (sunAwtDisableCALayers == null) { 800 sunAwtDisableCALayers = AccessController.doPrivileged( 801 new GetBooleanAction("sun.awt.disableCALayers")); 802 } 803 return sunAwtDisableCALayers; 804 } 805 806 /* 807 * Returns true if the application (one of its windows) owns keyboard focus. 808 */ 809 native boolean isApplicationActive(); 810 811 /** 812 * Returns true if AWT toolkit is embedded, false otherwise. 813 * 814 * @return true if AWT toolkit is embedded, false otherwise 815 */ 816 public static native boolean isEmbedded(); 817 818 /* 819 * Activates application ignoring other apps. 820 */ 821 public native void activateApplicationIgnoringOtherApps(); 822 823 /************************ 824 * Native methods section 825 ************************/ 826 827 static native long createAWTRunLoopMediator(); 828 /** 829 * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent 830 * by [JNFRunLoop performOnMainThreadWaiting] are processed. 831 * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator 832 * @param processEvents if true - dispatches event while in the nested loop. Used in DnD. 833 * Additional attention is needed when using this feature as we short-circuit normal event 834 * processing which could break Appkit. 835 * (One known example is when the window is resized with the mouse) 836 * 837 * if false - all events come after exit form the nested loop 838 */ 839 static void doAWTRunLoop(long mediator, boolean processEvents) { 840 doAWTRunLoopImpl(mediator, processEvents, inAWT); 841 } 842 private static native void doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT); 843 static native void stopAWTRunLoop(long mediator); 844 845 private native boolean nativeSyncQueue(long timeout); 846 847 /** 848 * Just spin a single empty block synchronously. 849 */ 850 static native void flushNativeSelectors(); 851 852 @Override 853 public Clipboard createPlatformClipboard() { 854 return new CClipboard("System"); 855 } 856 857 @Override 858 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { 859 return (exclusionType == null) || 860 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) || 861 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) || 862 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); 863 } 864 865 @Override 866 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { 867 //TODO: FileDialog blocks excluded windows... 868 //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be). 869 return (modalityType == null) || 870 (modalityType == Dialog.ModalityType.MODELESS) || 871 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) || 872 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) || 873 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL); 874 } 875 876 @Override 877 public boolean isWindowShapingSupported() { 878 return true; 879 } 880 881 @Override 882 public boolean isWindowTranslucencySupported() { 883 return true; 884 } 885 886 @Override 887 public boolean isTranslucencyCapable(GraphicsConfiguration gc) { 888 return true; 889 } 890 891 @Override 892 public boolean isSwingBackbufferTranslucencySupported() { 893 return true; 894 } 895 896 @Override 897 public boolean enableInputMethodsForTextComponent() { 898 return true; 899 } 900 901 private static URL getScaledImageURL(URL url) { 902 try { 903 String scaledImagePath = getScaledImageName(url.getPath()); 904 return scaledImagePath == null ? null : new URL(url.getProtocol(), 905 url.getHost(), url.getPort(), scaledImagePath); 906 } catch (MalformedURLException e) { 907 return null; 908 } 909 } 910 911 private static String getScaledImageName(String path) { 912 if (!isValidPath(path)) { 913 return null; 914 } 915 916 int slash = path.lastIndexOf('/'); 917 String name = (slash < 0) ? path : path.substring(slash + 1); 918 919 if (name.contains("@2x")) { 920 return null; 921 } 922 923 int dot = name.lastIndexOf('.'); 924 String name2x = (dot < 0) ? name + "@2x" 925 : name.substring(0, dot) + "@2x" + name.substring(dot); 926 return (slash < 0) ? name2x : path.substring(0, slash + 1) + name2x; 927 } 928 929 private static boolean isValidPath(String path) { 930 return path != null && 931 !path.isEmpty() && 932 !path.endsWith("/") && 933 !path.endsWith("."); 934 } 935 936 @Override 937 protected PlatformWindow getPlatformWindowUnderMouse() { 938 return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse(); 939 } 940 941 @Override 942 public void updateScreenMenuBarUI() { 943 if (AquaMenuBarUI.getScreenMenuBarProperty()) { 944 UIManager.put("MenuBarUI", "com.apple.laf.AquaMenuBarUI"); 945 } else { 946 UIManager.put("MenuBarUI", null); 947 } 948 } 949 }