1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.lwawt.macosx; 27 28 import java.awt.*; 29 import java.awt.datatransfer.Clipboard; 30 import java.awt.dnd.*; 31 import java.awt.dnd.peer.DragSourceContextPeer; 32 import java.awt.event.InputEvent; 33 import java.awt.event.InvocationEvent; 34 import java.awt.event.KeyEvent; 35 import java.awt.im.InputMethodHighlight; 36 import java.awt.im.spi.InputMethodDescriptor; 37 import java.awt.peer.*; 38 import java.lang.reflect.*; 39 import java.net.URL; 40 import java.security.*; 41 import java.util.*; 42 import java.util.concurrent.Callable; 43 import java.net.MalformedURLException; 44 45 import sun.awt.*; 46 import sun.awt.datatransfer.DataTransferer; 47 import sun.java2d.opengl.OGLRenderQueue; 48 import sun.lwawt.*; 49 import sun.lwawt.LWWindowPeer.PeerType; 50 import sun.security.action.GetBooleanAction; 51 import sun.awt.image.MultiResolutionImage; 52 53 import sun.util.CoreResourceBundleControl; 54 55 final class NamedCursor extends Cursor { NamedCursor(String name)56 NamedCursor(String name) { 57 super(name); 58 } 59 } 60 61 /** 62 * Mac OS X Cocoa-based AWT Toolkit. 63 */ 64 public final class LWCToolkit extends LWToolkit { 65 // While it is possible to enumerate all mouse devices 66 // and query them for the number of buttons, the code 67 // that does it is rather complex. Instead, we opt for 68 // the easy way and just support up to 5 mouse buttons, 69 // like Windows. 70 private static final int BUTTONS = 5; 71 initIDs()72 private static native void initIDs(); 73 74 private static CInputMethodDescriptor sInputMethodDescriptor; 75 76 static { System.err.flush()77 System.err.flush(); 78 79 ResourceBundle platformResources = java.security.AccessController.doPrivileged( 80 new java.security.PrivilegedAction<ResourceBundle>() { 81 @Override 82 public ResourceBundle run() { 83 ResourceBundle platformResources = null; 84 try { 85 platformResources = 86 ResourceBundle.getBundle("sun.awt.resources.awtosx", 87 CoreResourceBundleControl.getRBControlInstance()); 88 } catch (MissingResourceException e) { 89 // No resource file; defaults will be used. 90 } 91 92 System.loadLibrary("awt"); 93 System.loadLibrary("fontmanager"); 94 95 return platformResources; 96 } 97 }); 98 99 AWTAccessor.getToolkitAccessor().setPlatformResources(platformResources); 100 101 if (!GraphicsEnvironment.isHeadless()) { initIDs()102 initIDs(); 103 } 104 inAWT = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 105 @Override 106 public Boolean run() { 107 return !Boolean.parseBoolean(System.getProperty("javafx.embed.singleThread", "false")); 108 } 109 }); 110 } 111 112 /* 113 * If true we operate in normal mode and nested runloop is executed in JavaRunLoopMode 114 * If false we operate in singleThreaded FX/AWT interop mode and nested loop uses NSDefaultRunLoopMode 115 */ 116 private static final boolean inAWT; 117 LWCToolkit()118 public LWCToolkit() { 119 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true")); 120 //set system property if not yet assigned 121 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled); 122 } 123 124 /* 125 * System colors with default initial values, overwritten by toolkit if system values differ and are available. 126 */ 127 private final static int NUM_APPLE_COLORS = 3; 128 public final static int KEYBOARD_FOCUS_COLOR = 0; 129 public final static int INACTIVE_SELECTION_BACKGROUND_COLOR = 1; 130 public final static int INACTIVE_SELECTION_FOREGROUND_COLOR = 2; 131 private static int[] appleColors = { 132 0xFF808080, // keyboardFocusColor = Color.gray; 133 0xFFC0C0C0, // secondarySelectedControlColor 134 0xFF303030, // controlDarkShadowColor 135 }; 136 loadNativeColors(final int[] systemColors, final int[] appleColors)137 private native void loadNativeColors(final int[] systemColors, final int[] appleColors); 138 139 @Override loadSystemColors(final int[] systemColors)140 protected void loadSystemColors(final int[] systemColors) { 141 if (systemColors == null) return; 142 loadNativeColors(systemColors, appleColors); 143 } 144 145 private static class AppleSpecificColor extends Color { 146 private final int index; AppleSpecificColor(int index)147 AppleSpecificColor(int index) { 148 super(appleColors[index]); 149 this.index = index; 150 } 151 152 @Override getRGB()153 public int getRGB() { 154 return appleColors[index]; 155 } 156 } 157 158 /** 159 * Returns Apple specific colors that we may expose going forward. 160 */ getAppleColor(int color)161 public static Color getAppleColor(int color) { 162 return new AppleSpecificColor(color); 163 } 164 165 // This is only called from native code. systemColorsChanged()166 static void systemColorsChanged() { 167 EventQueue.invokeLater(() -> { 168 AccessController.doPrivileged ((PrivilegedAction<Object>) () -> { 169 AWTAccessor.getSystemColorAccessor().updateSystemColors(); 170 return null; 171 }); 172 }); 173 } 174 getLWCToolkit()175 public static LWCToolkit getLWCToolkit() { 176 return (LWCToolkit)Toolkit.getDefaultToolkit(); 177 } 178 179 @Override createPlatformWindow(PeerType peerType)180 protected PlatformWindow createPlatformWindow(PeerType peerType) { 181 if (peerType == PeerType.EMBEDDED_FRAME) { 182 return new CPlatformEmbeddedFrame(); 183 } else if (peerType == PeerType.VIEW_EMBEDDED_FRAME) { 184 return new CViewPlatformEmbeddedFrame(); 185 } else if (peerType == PeerType.LW_FRAME) { 186 return new CPlatformLWWindow(); 187 } else { 188 assert (peerType == PeerType.SIMPLEWINDOW 189 || peerType == PeerType.DIALOG 190 || peerType == PeerType.FRAME); 191 return new CPlatformWindow(); 192 } 193 } 194 createEmbeddedFrame(CEmbeddedFrame target)195 LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) { 196 PlatformComponent platformComponent = createPlatformComponent(); 197 PlatformWindow platformWindow = createPlatformWindow(PeerType.EMBEDDED_FRAME); 198 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.EMBEDDED_FRAME); 199 } 200 createEmbeddedFrame(CViewEmbeddedFrame target)201 LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) { 202 PlatformComponent platformComponent = createPlatformComponent(); 203 PlatformWindow platformWindow = createPlatformWindow(PeerType.VIEW_EMBEDDED_FRAME); 204 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.VIEW_EMBEDDED_FRAME); 205 } 206 createCPrinterDialog(CPrinterDialog target)207 private CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) { 208 PlatformComponent platformComponent = createPlatformComponent(); 209 PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG); 210 CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow); 211 targetCreatedPeer(target, peer); 212 return peer; 213 } 214 215 @Override createDialog(Dialog target)216 public DialogPeer createDialog(Dialog target) { 217 if (target instanceof CPrinterDialog) { 218 return createCPrinterDialog((CPrinterDialog)target); 219 } 220 return super.createDialog(target); 221 } 222 223 @Override createSecurityWarning(Window ownerWindow, LWWindowPeer ownerPeer)224 protected SecurityWarningWindow createSecurityWarning(Window ownerWindow, 225 LWWindowPeer ownerPeer) { 226 return new CWarningWindow(ownerWindow, ownerPeer); 227 } 228 229 @Override createPlatformComponent()230 protected PlatformComponent createPlatformComponent() { 231 return new CPlatformComponent(); 232 } 233 234 @Override createLwPlatformComponent()235 protected PlatformComponent createLwPlatformComponent() { 236 return new CPlatformLWComponent(); 237 } 238 239 @Override createFileDialogPeer(FileDialog target)240 protected FileDialogPeer createFileDialogPeer(FileDialog target) { 241 return new CFileDialog(target); 242 } 243 244 @Override createMenu(Menu target)245 public MenuPeer createMenu(Menu target) { 246 MenuPeer peer = new CMenu(target); 247 targetCreatedPeer(target, peer); 248 return peer; 249 } 250 251 @Override createMenuBar(MenuBar target)252 public MenuBarPeer createMenuBar(MenuBar target) { 253 MenuBarPeer peer = new CMenuBar(target); 254 targetCreatedPeer(target, peer); 255 return peer; 256 } 257 258 @Override createMenuItem(MenuItem target)259 public MenuItemPeer createMenuItem(MenuItem target) { 260 MenuItemPeer peer = new CMenuItem(target); 261 targetCreatedPeer(target, peer); 262 return peer; 263 } 264 265 @Override createCheckboxMenuItem(CheckboxMenuItem target)266 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 267 CheckboxMenuItemPeer peer = new CCheckboxMenuItem(target); 268 targetCreatedPeer(target, peer); 269 return peer; 270 } 271 272 @Override createPopupMenu(PopupMenu target)273 public PopupMenuPeer createPopupMenu(PopupMenu target) { 274 PopupMenuPeer peer = new CPopupMenu(target); 275 targetCreatedPeer(target, peer); 276 return peer; 277 } 278 279 @Override createSystemTray(SystemTray target)280 public SystemTrayPeer createSystemTray(SystemTray target) { 281 return new CSystemTray(); 282 } 283 284 @Override createTrayIcon(TrayIcon target)285 public TrayIconPeer createTrayIcon(TrayIcon target) { 286 TrayIconPeer peer = new CTrayIcon(target); 287 targetCreatedPeer(target, peer); 288 return peer; 289 } 290 291 @Override createDesktopPeer(Desktop target)292 protected DesktopPeer createDesktopPeer(Desktop target) { 293 return new CDesktopPeer(); 294 } 295 296 @Override getCursorManager()297 public LWCursorManager getCursorManager() { 298 return CCursorManager.getInstance(); 299 } 300 301 @Override createCustomCursor(final Image cursor, final Point hotSpot, final String name)302 public Cursor createCustomCursor(final Image cursor, final Point hotSpot, 303 final String name) 304 throws IndexOutOfBoundsException, HeadlessException { 305 return new CCustomCursor(cursor, hotSpot, name); 306 } 307 308 @Override getBestCursorSize(final int preferredWidth, final int preferredHeight)309 public Dimension getBestCursorSize(final int preferredWidth, 310 final int preferredHeight) 311 throws HeadlessException { 312 return CCustomCursor.getBestCursorSize(preferredWidth, preferredHeight); 313 } 314 315 @Override platformCleanup()316 protected void platformCleanup() { 317 // TODO Auto-generated method stub 318 } 319 320 @Override platformInit()321 protected void platformInit() { 322 // TODO Auto-generated method stub 323 } 324 325 @Override platformRunMessage()326 protected void platformRunMessage() { 327 // TODO Auto-generated method stub 328 } 329 330 @Override platformShutdown()331 protected void platformShutdown() { 332 // TODO Auto-generated method stub 333 } 334 335 class OSXPlatformFont extends sun.awt.PlatformFont 336 { OSXPlatformFont(String name, int style)337 OSXPlatformFont(String name, int style) 338 { 339 super(name, style); 340 } 341 @Override getMissingGlyphCharacter()342 protected char getMissingGlyphCharacter() 343 { 344 // Follow up for real implementation 345 return (char)0xfff8; // see http://developer.apple.com/fonts/LastResortFont/ 346 } 347 } 348 @Override getFontPeer(String name, int style)349 public FontPeer getFontPeer(String name, int style) { 350 return new OSXPlatformFont(name, style); 351 } 352 353 @Override getScreenHeight()354 protected int getScreenHeight() { 355 return GraphicsEnvironment.getLocalGraphicsEnvironment() 356 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().height; 357 } 358 359 @Override getScreenWidth()360 protected int getScreenWidth() { 361 return GraphicsEnvironment.getLocalGraphicsEnvironment() 362 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().width; 363 } 364 365 @Override initializeDesktopProperties()366 protected void initializeDesktopProperties() { 367 super.initializeDesktopProperties(); 368 Map <Object, Object> fontHints = new HashMap<>(); 369 fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); 370 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); 371 desktopProperties.put("awt.mouse.numButtons", BUTTONS); 372 373 // These DnD properties must be set, otherwise Swing ends up spewing NPEs 374 // all over the place. The values came straight off of MToolkit. 375 desktopProperties.put("DnD.Autoscroll.initialDelay", new Integer(50)); 376 desktopProperties.put("DnD.Autoscroll.interval", new Integer(50)); 377 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", new Integer(5)); 378 379 desktopProperties.put("DnD.isDragImageSupported", new Boolean(true)); 380 381 // Register DnD cursors 382 desktopProperties.put("DnD.Cursor.CopyDrop", new NamedCursor("DnD.Cursor.CopyDrop")); 383 desktopProperties.put("DnD.Cursor.MoveDrop", new NamedCursor("DnD.Cursor.MoveDrop")); 384 desktopProperties.put("DnD.Cursor.LinkDrop", new NamedCursor("DnD.Cursor.LinkDrop")); 385 desktopProperties.put("DnD.Cursor.CopyNoDrop", new NamedCursor("DnD.Cursor.CopyNoDrop")); 386 desktopProperties.put("DnD.Cursor.MoveNoDrop", new NamedCursor("DnD.Cursor.MoveNoDrop")); 387 desktopProperties.put("DnD.Cursor.LinkNoDrop", new NamedCursor("DnD.Cursor.LinkNoDrop")); 388 } 389 390 @Override syncNativeQueue(long timeout)391 protected boolean syncNativeQueue(long timeout) { 392 return nativeSyncQueue(timeout); 393 } 394 395 @Override beep()396 public native void beep(); 397 398 @Override getScreenResolution()399 public int getScreenResolution() throws HeadlessException { 400 return (int) ((CGraphicsDevice) GraphicsEnvironment 401 .getLocalGraphicsEnvironment().getDefaultScreenDevice()) 402 .getXResolution(); 403 } 404 405 @Override getScreenInsets(final GraphicsConfiguration gc)406 public Insets getScreenInsets(final GraphicsConfiguration gc) { 407 return ((CGraphicsConfig) gc).getDevice().getScreenInsets(); 408 } 409 410 @Override sync()411 public void sync() { 412 // flush the OGL pipeline (this is a no-op if OGL is not enabled) 413 OGLRenderQueue.sync(); 414 // setNeedsDisplay() selector was sent to the appropriate CALayer so now 415 // we have to flush the native selectors queue. 416 flushNativeSelectors(); 417 } 418 419 @Override createRobot(Robot target, GraphicsDevice screen)420 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 421 return new CRobot(target, (CGraphicsDevice)screen); 422 } 423 isCapsLockOn()424 private native boolean isCapsLockOn(); 425 426 /* 427 * NOTE: Among the keys this method is supposed to check, 428 * only Caps Lock works as a true locking key with OS X. 429 * There is no Scroll Lock key on modern Apple keyboards, 430 * and with a PC keyboard plugged in Scroll Lock is simply 431 * ignored: no LED lights up if you press it. 432 * The key located at the same position on Apple keyboards 433 * as Num Lock on PC keyboards is called Clear, doesn't lock 434 * anything and is used for entirely different purpose. 435 */ 436 @Override getLockingKeyState(int keyCode)437 public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException { 438 switch (keyCode) { 439 case KeyEvent.VK_NUM_LOCK: 440 case KeyEvent.VK_SCROLL_LOCK: 441 case KeyEvent.VK_KANA_LOCK: 442 throw new UnsupportedOperationException("Toolkit.getLockingKeyState"); 443 444 case KeyEvent.VK_CAPS_LOCK: 445 return isCapsLockOn(); 446 447 default: 448 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState"); 449 } 450 } 451 452 //Is it allowed to generate events assigned to extra mouse buttons. 453 //Set to true by default. 454 private static boolean areExtraMouseButtonsEnabled = true; 455 456 @Override areExtraMouseButtonsEnabled()457 public boolean areExtraMouseButtonsEnabled() throws HeadlessException { 458 return areExtraMouseButtonsEnabled; 459 } 460 461 @Override getNumberOfButtons()462 public int getNumberOfButtons(){ 463 return BUTTONS; 464 } 465 466 @Override isTraySupported()467 public boolean isTraySupported() { 468 return true; 469 } 470 471 @Override getDataTransferer()472 public DataTransferer getDataTransferer() { 473 return CDataTransferer.getInstanceImpl(); 474 } 475 476 @Override isAlwaysOnTopSupported()477 public boolean isAlwaysOnTopSupported() { 478 return true; 479 } 480 481 // Intended to be called from the LWCToolkit.m only. installToolkitThreadInJava()482 private static void installToolkitThreadInJava() { 483 Thread.currentThread().setName(CThreading.APPKIT_THREAD_NAME); 484 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 485 Thread.currentThread().setContextClassLoader(null); 486 return null; 487 }); 488 } 489 490 @Override isWindowOpacitySupported()491 public boolean isWindowOpacitySupported() { 492 return true; 493 } 494 495 @Override isFrameStateSupported(int state)496 public boolean isFrameStateSupported(int state) throws HeadlessException { 497 switch (state) { 498 case Frame.NORMAL: 499 case Frame.ICONIFIED: 500 case Frame.MAXIMIZED_BOTH: 501 return true; 502 default: 503 return false; 504 } 505 } 506 507 /** 508 * Determines which modifier key is the appropriate accelerator 509 * key for menu shortcuts. 510 * <p> 511 * Menu shortcuts, which are embodied in the 512 * <code>MenuShortcut</code> class, are handled by the 513 * <code>MenuBar</code> class. 514 * <p> 515 * By default, this method returns <code>Event.CTRL_MASK</code>. 516 * Toolkit implementations should override this method if the 517 * <b>Control</b> key isn't the correct key for accelerators. 518 * @return the modifier mask on the <code>Event</code> class 519 * that is used for menu shortcuts on this toolkit. 520 * @see java.awt.MenuBar 521 * @see java.awt.MenuShortcut 522 * @since JDK1.1 523 */ 524 @Override getMenuShortcutKeyMask()525 public int getMenuShortcutKeyMask() { 526 return Event.META_MASK; 527 } 528 529 @Override getImage(final String filename)530 public Image getImage(final String filename) { 531 final Image nsImage = checkForNSImage(filename); 532 if (nsImage != null) { 533 return nsImage; 534 } 535 536 if (imageCached(filename)) { 537 return super.getImage(filename); 538 } 539 540 String filename2x = getScaledImageName(filename); 541 return (imageExists(filename2x)) 542 ? getImageWithResolutionVariant(filename, filename2x) 543 : super.getImage(filename); 544 } 545 546 @Override getImage(URL url)547 public Image getImage(URL url) { 548 549 if (imageCached(url)) { 550 return super.getImage(url); 551 } 552 553 URL url2x = getScaledImageURL(url); 554 return (imageExists(url2x)) 555 ? getImageWithResolutionVariant(url, url2x) : super.getImage(url); 556 } 557 558 private static final String nsImagePrefix = "NSImage://"; checkForNSImage(final String imageName)559 private Image checkForNSImage(final String imageName) { 560 if (imageName == null) return null; 561 if (!imageName.startsWith(nsImagePrefix)) return null; 562 return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length())); 563 } 564 565 // Thread-safe Object.equals() called from native doEquals(final Object a, final Object b, Component c)566 public static boolean doEquals(final Object a, final Object b, Component c) { 567 if (a == b) return true; 568 569 final boolean[] ret = new boolean[1]; 570 571 try { invokeAndWait(new Runnable() { public void run() { synchronized(ret) { 572 ret[0] = a.equals(b); 573 }}}, c); } catch (Exception e) { e.printStackTrace(); } 574 575 synchronized(ret) { return ret[0]; } 576 } 577 invokeAndWait(final Callable<T> callable, Component component)578 public static <T> T invokeAndWait(final Callable<T> callable, 579 Component component) throws Exception { 580 final CallableWrapper<T> wrapper = new CallableWrapper<>(callable); 581 invokeAndWait(wrapper, component); 582 return wrapper.getResult(); 583 } 584 585 static final class CallableWrapper<T> implements Runnable { 586 final Callable<T> callable; 587 T object; 588 Exception e; 589 CallableWrapper(final Callable<T> callable)590 CallableWrapper(final Callable<T> callable) { 591 this.callable = callable; 592 } 593 594 @Override run()595 public void run() { 596 try { 597 object = callable.call(); 598 } catch (final Exception e) { 599 this.e = e; 600 } 601 } 602 getResult()603 public T getResult() throws Exception { 604 if (e != null) throw e; 605 return object; 606 } 607 } 608 609 /** 610 * Kicks an event over to the appropriate eventqueue and waits for it to 611 * finish To avoid deadlocking, we manually run the NSRunLoop while waiting 612 * Any selector invoked using ThreadUtilities performOnMainThread will be 613 * processed in doAWTRunLoop The InvocationEvent will call 614 * LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual 615 * runloop Does not dispatch native events while in the loop 616 */ invokeAndWait(Runnable runnable, Component component)617 public static void invokeAndWait(Runnable runnable, Component component) 618 throws InvocationTargetException { 619 final long mediator = createAWTRunLoopMediator(); 620 621 InvocationEvent invocationEvent = 622 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), 623 runnable, 624 () -> { 625 if (mediator != 0) { 626 stopAWTRunLoop(mediator); 627 } 628 }, 629 true); 630 631 if (component != null) { 632 AppContext appContext = SunToolkit.targetToAppContext(component); 633 SunToolkit.postEvent(appContext, invocationEvent); 634 635 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock 636 SunToolkit.flushPendingEvents(appContext); 637 } else { 638 // This should be the equivalent to EventQueue.invokeAndWait 639 ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); 640 } 641 642 doAWTRunLoop(mediator, false); 643 644 Throwable eventException = invocationEvent.getException(); 645 if (eventException != null) { 646 if (eventException instanceof UndeclaredThrowableException) { 647 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable(); 648 } 649 throw new InvocationTargetException(eventException); 650 } 651 } 652 invokeLater(Runnable event, Component component)653 public static void invokeLater(Runnable event, Component component) 654 throws InvocationTargetException { 655 final InvocationEvent invocationEvent = 656 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event); 657 658 if (component != null) { 659 final AppContext appContext = SunToolkit.targetToAppContext(component); 660 SunToolkit.postEvent(appContext, invocationEvent); 661 662 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock 663 SunToolkit.flushPendingEvents(appContext); 664 } else { 665 // This should be the equivalent to EventQueue.invokeAndWait 666 ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); 667 } 668 669 final Throwable eventException = invocationEvent.getException(); 670 if (eventException == null) return; 671 672 if (eventException instanceof UndeclaredThrowableException) { 673 throw new InvocationTargetException(((UndeclaredThrowableException)eventException).getUndeclaredThrowable()); 674 } 675 throw new InvocationTargetException(eventException); 676 } 677 678 // This exists purely to get around permissions issues with getSystemEventQueueImpl getSystemEventQueueForInvokeAndWait()679 EventQueue getSystemEventQueueForInvokeAndWait() { 680 return getSystemEventQueueImpl(); 681 } 682 683 // DnD support 684 685 @Override createDragSourceContextPeer( DragGestureEvent dge)686 public DragSourceContextPeer createDragSourceContextPeer( 687 DragGestureEvent dge) throws InvalidDnDOperationException { 688 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent()); 689 if (f != null) { 690 return f.createDragSourceContextPeer(dge); 691 } 692 693 return CDragSourceContextPeer.createDragSourceContextPeer(dge); 694 } 695 696 @Override createDragGestureRecognizer( Class<T> abstractRecognizerClass, DragSource ds, Component c, int srcActions, DragGestureListener dgl)697 public <T extends DragGestureRecognizer> T createDragGestureRecognizer( 698 Class<T> abstractRecognizerClass, DragSource ds, Component c, 699 int srcActions, DragGestureListener dgl) { 700 final LightweightFrame f = SunToolkit.getLightweightFrame(c); 701 if (f != null) { 702 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl); 703 } 704 705 DragGestureRecognizer dgr = null; 706 707 // Create a new mouse drag gesture recognizer if we have a class match: 708 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) 709 dgr = new CMouseDragGestureRecognizer(ds, c, srcActions, dgl); 710 711 return (T)dgr; 712 } 713 714 // InputMethodSupport Method 715 /** 716 * Returns the default keyboard locale of the underlying operating system 717 */ 718 @Override getDefaultKeyboardLocale()719 public Locale getDefaultKeyboardLocale() { 720 Locale locale = CInputMethod.getNativeLocale(); 721 722 if (locale == null) { 723 return super.getDefaultKeyboardLocale(); 724 } 725 726 return locale; 727 } 728 isLocaleUSInternationalPC(Locale locale)729 public static boolean isLocaleUSInternationalPC(Locale locale) { 730 return (locale != null ? 731 locale.toString().equals("_US_UserDefined_15000") : false); 732 } 733 isCharModifierKeyInUSInternationalPC(char ch)734 public static boolean isCharModifierKeyInUSInternationalPC(char ch) { 735 // 5 characters: APOSTROPHE, QUOTATION MARK, ACCENT GRAVE, SMALL TILDE, 736 // CIRCUMFLEX ACCENT 737 final char[] modifierKeys = {'\'', '"', '`', '\u02DC', '\u02C6'}; 738 for (char modKey : modifierKeys) { 739 if (modKey == ch) { 740 return true; 741 } 742 } 743 return false; 744 } 745 746 @Override getInputMethodAdapterDescriptor()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 mapInputMethodHighlight(InputMethodHighlight highlight)764 public Map 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 getFocusAcceleratorKeyMask()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 isPrintableCharacterModifiersMask(int mods)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 canPopupOverlapTaskBar()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 */ getSunAwtDisableCALayers()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 */ isApplicationActive()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 */ isEmbedded()818 public static native boolean isEmbedded(); 819 820 /* 821 * Activates application ignoring other apps. 822 */ activateApplicationIgnoringOtherApps()823 public native void activateApplicationIgnoringOtherApps(); 824 825 /************************ 826 * Native methods section 827 ************************/ 828 createAWTRunLoopMediator()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 */ doAWTRunLoop(long mediator, boolean processEvents)841 static void doAWTRunLoop(long mediator, boolean processEvents) { 842 doAWTRunLoopImpl(mediator, processEvents, inAWT); 843 } doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT)844 private static native void doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT); stopAWTRunLoop(long mediator)845 static native void stopAWTRunLoop(long mediator); 846 nativeSyncQueue(long timeout)847 private native boolean nativeSyncQueue(long timeout); 848 849 /** 850 * Just spin a single empty block synchronously. 851 */ flushNativeSelectors()852 static native void flushNativeSelectors(); 853 854 @Override createPlatformClipboard()855 public Clipboard createPlatformClipboard() { 856 return new CClipboard("System"); 857 } 858 859 @Override isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType)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 isModalityTypeSupported(Dialog.ModalityType modalityType)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 isWindowShapingSupported()879 public boolean isWindowShapingSupported() { 880 return true; 881 } 882 883 @Override isWindowTranslucencySupported()884 public boolean isWindowTranslucencySupported() { 885 return true; 886 } 887 888 @Override isTranslucencyCapable(GraphicsConfiguration gc)889 public boolean isTranslucencyCapable(GraphicsConfiguration gc) { 890 return true; 891 } 892 893 @Override isSwingBackbufferTranslucencySupported()894 public boolean isSwingBackbufferTranslucencySupported() { 895 return true; 896 } 897 898 @Override enableInputMethodsForTextComponent()899 public boolean enableInputMethodsForTextComponent() { 900 return true; 901 } 902 getScaledImageURL(URL url)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 getScaledImageName(String path)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 isValidPath(String path)931 private static boolean isValidPath(String path) { 932 return path != null && 933 !path.isEmpty() && 934 !path.endsWith("/") && 935 !path.endsWith("."); 936 } 937 938 @Override getPlatformWindowUnderMouse()939 protected PlatformWindow getPlatformWindowUnderMouse() { 940 return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse(); 941 } 942 } 943