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