1 /* 2 * Copyright (c) 1996, 2019, 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.awt.windows; 27 28 import java.awt.*; 29 import java.awt.im.InputMethodHighlight; 30 import java.awt.im.spi.InputMethodDescriptor; 31 import java.awt.image.*; 32 import java.awt.peer.*; 33 import java.awt.event.FocusEvent; 34 import java.awt.event.KeyEvent; 35 import java.awt.event.MouseEvent; 36 import java.awt.datatransfer.Clipboard; 37 import java.awt.TextComponent; 38 import java.awt.TrayIcon; 39 import java.beans.PropertyChangeListener; 40 import java.lang.ref.WeakReference; 41 import java.security.AccessController; 42 import java.security.PrivilegedAction; 43 import javax.swing.text.JTextComponent; 44 45 import sun.awt.AppContext; 46 import sun.awt.AWTAccessor; 47 import sun.awt.AWTAutoShutdown; 48 import sun.awt.LightweightFrame; 49 import sun.awt.SunToolkit; 50 import sun.misc.ThreadGroupUtils; 51 import sun.awt.Win32GraphicsDevice; 52 import sun.awt.Win32GraphicsEnvironment; 53 import sun.awt.datatransfer.DataTransferer; 54 import sun.java2d.d3d.D3DRenderQueue; 55 import sun.java2d.opengl.OGLRenderQueue; 56 57 import sun.print.PrintJob2D; 58 59 import java.awt.dnd.DragSource; 60 import java.awt.dnd.DragGestureListener; 61 import java.awt.dnd.DragGestureEvent; 62 import java.awt.dnd.DragGestureRecognizer; 63 import java.awt.dnd.MouseDragGestureRecognizer; 64 import java.awt.dnd.InvalidDnDOperationException; 65 import java.awt.dnd.peer.DragSourceContextPeer; 66 67 import java.util.Hashtable; 68 import java.util.Locale; 69 import java.util.Map; 70 import java.util.Properties; 71 import java.util.concurrent.ExecutorService; 72 import java.util.concurrent.Executors; 73 74 import sun.font.FontManager; 75 import sun.font.FontManagerFactory; 76 import sun.font.SunFontManager; 77 import sun.misc.PerformanceLogger; 78 import sun.util.logging.PlatformLogger; 79 import sun.security.util.SecurityConstants; 80 81 public final class WToolkit extends SunToolkit implements Runnable { 82 83 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WToolkit"); 84 85 // Desktop property which specifies whether XP visual styles are in effect 86 public static final String XPSTYLE_THEME_ACTIVE = "win.xpstyle.themeActive"; 87 88 static GraphicsConfiguration config; 89 90 // System clipboard. 91 WClipboard clipboard; 92 93 // cache of font peers 94 private Hashtable<String,FontPeer> cacheFontPeer; 95 96 // Windows properties 97 private WDesktopProperties wprops; 98 99 // Dynamic Layout Resize client code setting 100 protected boolean dynamicLayoutSetting = false; 101 102 //Is it allowed to generate events assigned to extra mouse buttons. 103 //Set to true by default. 104 private static boolean areExtraMouseButtonsEnabled = true; 105 106 /** 107 * Initialize JNI field and method IDs 108 */ 109 private static native void initIDs(); 110 private static boolean loaded = false; 111 public static void loadLibraries() { 112 if (!loaded) { 113 java.security.AccessController.doPrivileged( 114 new java.security.PrivilegedAction<Void>() { 115 @Override 116 public Void run() { 117 System.loadLibrary("awt"); 118 return null; 119 } 120 }); 121 loaded = true; 122 } 123 } 124 125 private static native String getWindowsVersion(); 126 127 static { 128 loadLibraries(); 129 initIDs(); 130 131 // Print out which version of Windows is running 132 if (log.isLoggable(PlatformLogger.Level.FINE)) { 133 log.fine("Win version: " + getWindowsVersion()); 134 } 135 136 AccessController.doPrivileged( 137 new PrivilegedAction <Void> () 138 { 139 @Override 140 public Void run() { 141 String browserProp = System.getProperty("browser"); 142 if (browserProp != null && browserProp.equals("sun.plugin")) { 143 disableCustomPalette(); 144 } 145 return null; 146 } 147 }); 148 } 149 150 private static native void disableCustomPalette(); 151 152 /* 153 * Reset the static GraphicsConfiguration to the default. Called on 154 * startup and when display settings have changed. 155 */ 156 public static void resetGC() { 157 if (GraphicsEnvironment.isHeadless()) { 158 config = null; 159 } else { 160 config = (GraphicsEnvironment 161 .getLocalGraphicsEnvironment() 162 .getDefaultScreenDevice() 163 .getDefaultConfiguration()); 164 } 165 } 166 167 /* 168 * NOTE: The following embedded*() methods are non-public API intended 169 * for internal use only. The methods are unsupported and could go 170 * away in future releases. 171 * 172 * New hook functions for using the AWT as an embedded service. These 173 * functions replace the global C function AwtInit() which was previously 174 * exported by awt.dll. 175 * 176 * When used as an embedded service, the AWT does NOT have its own 177 * message pump. It instead relies on the parent application to provide 178 * this functionality. embeddedInit() assumes that the thread on which it 179 * is called is the message pumping thread. Violating this assumption 180 * will lead to undefined behavior. 181 * 182 * embeddedInit must be called before the WToolkit() constructor. 183 * embeddedDispose should be called before the applicaton terminates the 184 * Java VM. It is currently unsafe to reinitialize the toolkit again 185 * after it has been disposed. Instead, awt.dll must be reloaded and the 186 * class loader which loaded WToolkit must be finalized before it is 187 * safe to reuse AWT. Dynamic reusability may be added to the toolkit in 188 * the future. 189 */ 190 191 /** 192 * Initializes the Toolkit for use in an embedded environment. 193 * 194 * @return true if the the initialization succeeded; false if it failed. 195 * The function will fail if the Toolkit was already initialized. 196 * @since 1.3 197 */ 198 public static native boolean embeddedInit(); 199 200 /** 201 * Disposes the Toolkit in an embedded environment. This method should 202 * not be called on exit unless the Toolkit was constructed with 203 * embeddedInit. 204 * 205 * @return true if the disposal succeeded; false if it failed. The 206 * function will fail if the calling thread is not the same 207 * thread which called embeddedInit(), or if the Toolkit was 208 * already disposed. 209 * @since 1.3 210 */ 211 public static native boolean embeddedDispose(); 212 213 /** 214 * To be called after processing the event queue by users of the above 215 * embeddedInit() function. The reason for this additional call is that 216 * there are some operations performed during idle time in the AwtToolkit 217 * event loop which should also be performed during idle time in any 218 * other native event loop. Failure to do so could result in 219 * deadlocks. 220 * 221 * This method was added at the last minute of the jdk1.4 release 222 * to work around a specific customer problem. As with the above 223 * embedded*() class, this method is non-public and should not be 224 * used by external applications. 225 * 226 * See bug #4526587 for more information. 227 */ 228 public native void embeddedEventLoopIdleProcessing(); 229 230 static class ToolkitDisposer implements sun.java2d.DisposerRecord { 231 @Override 232 public void dispose() { 233 WToolkit.postDispose(); 234 } 235 } 236 237 private final Object anchor = new Object(); 238 239 private static native void postDispose(); 240 241 private static native boolean startToolkitThread(Runnable thread, ThreadGroup rootThreadGroup); 242 243 public WToolkit() { 244 // Startup toolkit threads 245 if (PerformanceLogger.loggingEnabled()) { 246 PerformanceLogger.setTime("WToolkit construction"); 247 } 248 249 sun.java2d.Disposer.addRecord(anchor, new ToolkitDisposer()); 250 251 /* 252 * Fix for 4701990. 253 * AWTAutoShutdown state must be changed before the toolkit thread 254 * starts to avoid race condition. 255 */ 256 AWTAutoShutdown.notifyToolkitThreadBusy(); 257 258 // Find a root TG and attach Appkit thread to it 259 ThreadGroup rootTG = AccessController.doPrivileged( 260 (PrivilegedAction<ThreadGroup>) ThreadGroupUtils::getRootThreadGroup); 261 if (!startToolkitThread(this, rootTG)) { 262 Thread toolkitThread = new Thread(rootTG, this, "AWT-Windows"); 263 toolkitThread.setDaemon(true); 264 toolkitThread.start(); 265 } 266 267 try { 268 synchronized(this) { 269 while(!inited) { 270 wait(); 271 } 272 } 273 } catch (InterruptedException x) { 274 // swallow the exception 275 } 276 277 // Enabled "live resizing" by default. It remains controlled 278 // by the native system though. 279 setDynamicLayout(true); 280 281 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true")); 282 //set system property if not yet assigned 283 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled); 284 setExtraMouseButtonsEnabledNative(areExtraMouseButtonsEnabled); 285 } 286 287 private final void registerShutdownHook() { 288 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 289 Thread shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown); 290 shutdown.setContextClassLoader(null); 291 Runtime.getRuntime().addShutdownHook(shutdown); 292 return null; 293 }); 294 } 295 296 @Override 297 public void run() { 298 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 299 Thread.currentThread().setContextClassLoader(null); 300 return null; 301 }); 302 Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1); 303 boolean startPump = init(); 304 305 if (startPump) { 306 registerShutdownHook(); 307 } 308 309 synchronized(this) { 310 inited = true; 311 notifyAll(); 312 } 313 314 if (startPump) { 315 eventLoop(); // will Dispose Toolkit when shutdown hook executes 316 } 317 } 318 319 /* 320 * eventLoop() begins the native message pump which retrieves and processes 321 * native events. 322 * 323 * When shutdown() is called by the ShutdownHook added in run(), a 324 * WM_QUIT message is posted to the Toolkit thread indicating that 325 * eventLoop() should Dispose the toolkit and exit. 326 */ 327 private native boolean init(); 328 private boolean inited = false; 329 330 private native void eventLoop(); 331 private native void shutdown(); 332 333 /* 334 * Instead of blocking the "AWT-Windows" thread uselessly on a semaphore, 335 * use these functions. startSecondaryEventLoop() corresponds to wait() 336 * and quitSecondaryEventLoop() corresponds to notify. 337 * 338 * These functions simulate blocking while allowing the AWT to continue 339 * processing native events, eliminating a potential deadlock situation 340 * with SendMessage. 341 * 342 * WARNING: startSecondaryEventLoop must only be called from the "AWT- 343 * Windows" thread. 344 */ 345 static native void startSecondaryEventLoop(); 346 static native void quitSecondaryEventLoop(); 347 348 /* 349 * Create peer objects. 350 */ 351 352 @Override 353 public ButtonPeer createButton(Button target) { 354 ButtonPeer peer = new WButtonPeer(target); 355 targetCreatedPeer(target, peer); 356 return peer; 357 } 358 359 @Override 360 public TextFieldPeer createTextField(TextField target) { 361 TextFieldPeer peer = new WTextFieldPeer(target); 362 targetCreatedPeer(target, peer); 363 return peer; 364 } 365 366 @Override 367 public LabelPeer createLabel(Label target) { 368 LabelPeer peer = new WLabelPeer(target); 369 targetCreatedPeer(target, peer); 370 return peer; 371 } 372 373 @Override 374 public ListPeer createList(List target) { 375 ListPeer peer = new WListPeer(target); 376 targetCreatedPeer(target, peer); 377 return peer; 378 } 379 380 @Override 381 public CheckboxPeer createCheckbox(Checkbox target) { 382 CheckboxPeer peer = new WCheckboxPeer(target); 383 targetCreatedPeer(target, peer); 384 return peer; 385 } 386 387 @Override 388 public ScrollbarPeer createScrollbar(Scrollbar target) { 389 ScrollbarPeer peer = new WScrollbarPeer(target); 390 targetCreatedPeer(target, peer); 391 return peer; 392 } 393 394 @Override 395 public ScrollPanePeer createScrollPane(ScrollPane target) { 396 ScrollPanePeer peer = new WScrollPanePeer(target); 397 targetCreatedPeer(target, peer); 398 return peer; 399 } 400 401 @Override 402 public TextAreaPeer createTextArea(TextArea target) { 403 TextAreaPeer peer = new WTextAreaPeer(target); 404 targetCreatedPeer(target, peer); 405 return peer; 406 } 407 408 @Override 409 public ChoicePeer createChoice(Choice target) { 410 ChoicePeer peer = new WChoicePeer(target); 411 targetCreatedPeer(target, peer); 412 return peer; 413 } 414 415 @Override 416 public FramePeer createFrame(Frame target) { 417 FramePeer peer = new WFramePeer(target); 418 targetCreatedPeer(target, peer); 419 return peer; 420 } 421 422 @Override 423 public FramePeer createLightweightFrame(LightweightFrame target) { 424 FramePeer peer = new WLightweightFramePeer(target); 425 targetCreatedPeer(target, peer); 426 return peer; 427 } 428 429 @Override 430 public CanvasPeer createCanvas(Canvas target) { 431 CanvasPeer peer = new WCanvasPeer(target); 432 targetCreatedPeer(target, peer); 433 return peer; 434 } 435 436 @Override 437 @SuppressWarnings("deprecation") 438 public void disableBackgroundErase(Canvas canvas) { 439 WCanvasPeer peer = (WCanvasPeer)canvas.getPeer(); 440 if (peer == null) { 441 throw new IllegalStateException("Canvas must have a valid peer"); 442 } 443 peer.disableBackgroundErase(); 444 } 445 446 @Override 447 public PanelPeer createPanel(Panel target) { 448 PanelPeer peer = new WPanelPeer(target); 449 targetCreatedPeer(target, peer); 450 return peer; 451 } 452 453 @Override 454 public WindowPeer createWindow(Window target) { 455 WindowPeer peer = new WWindowPeer(target); 456 targetCreatedPeer(target, peer); 457 return peer; 458 } 459 460 @Override 461 public DialogPeer createDialog(Dialog target) { 462 DialogPeer peer = new WDialogPeer(target); 463 targetCreatedPeer(target, peer); 464 return peer; 465 } 466 467 @Override 468 public FileDialogPeer createFileDialog(FileDialog target) { 469 FileDialogPeer peer = new WFileDialogPeer(target); 470 targetCreatedPeer(target, peer); 471 return peer; 472 } 473 474 @Override 475 public MenuBarPeer createMenuBar(MenuBar target) { 476 MenuBarPeer peer = new WMenuBarPeer(target); 477 targetCreatedPeer(target, peer); 478 return peer; 479 } 480 481 @Override 482 public MenuPeer createMenu(Menu target) { 483 MenuPeer peer = new WMenuPeer(target); 484 targetCreatedPeer(target, peer); 485 return peer; 486 } 487 488 @Override 489 public PopupMenuPeer createPopupMenu(PopupMenu target) { 490 PopupMenuPeer peer = new WPopupMenuPeer(target); 491 targetCreatedPeer(target, peer); 492 return peer; 493 } 494 495 @Override 496 public MenuItemPeer createMenuItem(MenuItem target) { 497 MenuItemPeer peer = new WMenuItemPeer(target); 498 targetCreatedPeer(target, peer); 499 return peer; 500 } 501 502 @Override 503 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 504 CheckboxMenuItemPeer peer = new WCheckboxMenuItemPeer(target); 505 targetCreatedPeer(target, peer); 506 return peer; 507 } 508 509 @Override 510 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 511 // (target is unused for now) 512 // Robot's don't need to go in the peer map since 513 // they're not Component's 514 return new WRobotPeer(screen); 515 } 516 517 public WEmbeddedFramePeer createEmbeddedFrame(WEmbeddedFrame target) { 518 WEmbeddedFramePeer peer = new WEmbeddedFramePeer(target); 519 targetCreatedPeer(target, peer); 520 return peer; 521 } 522 523 WPrintDialogPeer createWPrintDialog(WPrintDialog target) { 524 WPrintDialogPeer peer = new WPrintDialogPeer(target); 525 targetCreatedPeer(target, peer); 526 return peer; 527 } 528 529 WPageDialogPeer createWPageDialog(WPageDialog target) { 530 WPageDialogPeer peer = new WPageDialogPeer(target); 531 targetCreatedPeer(target, peer); 532 return peer; 533 } 534 535 @Override 536 public TrayIconPeer createTrayIcon(TrayIcon target) { 537 WTrayIconPeer peer = new WTrayIconPeer(target); 538 targetCreatedPeer(target, peer); 539 return peer; 540 } 541 542 @Override 543 public SystemTrayPeer createSystemTray(SystemTray target) { 544 return new WSystemTrayPeer(target); 545 } 546 547 @Override 548 public boolean isTraySupported() { 549 return true; 550 } 551 552 @Override 553 public DataTransferer getDataTransferer() { 554 return WDataTransferer.getInstanceImpl(); 555 } 556 557 @Override 558 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() 559 throws HeadlessException 560 { 561 return WKeyboardFocusManagerPeer.getInstance(); 562 } 563 564 private native void setDynamicLayoutNative(boolean b); 565 566 @Override 567 public void setDynamicLayout(boolean b) { 568 if (b == dynamicLayoutSetting) { 569 return; 570 } 571 572 dynamicLayoutSetting = b; 573 setDynamicLayoutNative(b); 574 } 575 576 @Override 577 protected boolean isDynamicLayoutSet() { 578 return dynamicLayoutSetting; 579 } 580 581 /* 582 * Called from lazilyLoadDynamicLayoutSupportedProperty because 583 * Windows doesn't always send WM_SETTINGCHANGE when it should. 584 */ 585 private native boolean isDynamicLayoutSupportedNative(); 586 587 @Override 588 public boolean isDynamicLayoutActive() { 589 return (isDynamicLayoutSet() && isDynamicLayoutSupported()); 590 } 591 592 /** 593 * Returns <code>true</code> if this frame state is supported. 594 */ 595 @Override 596 public boolean isFrameStateSupported(int state) { 597 switch (state) { 598 case Frame.NORMAL: 599 case Frame.ICONIFIED: 600 case Frame.MAXIMIZED_BOTH: 601 return true; 602 default: 603 return false; 604 } 605 } 606 607 static native ColorModel makeColorModel(); 608 static ColorModel screenmodel; 609 610 static ColorModel getStaticColorModel() { 611 if (GraphicsEnvironment.isHeadless()) { 612 throw new IllegalArgumentException(); 613 } 614 if (config == null) { 615 resetGC(); 616 } 617 return config.getColorModel(); 618 } 619 620 @Override 621 public ColorModel getColorModel() { 622 return getStaticColorModel(); 623 } 624 625 @Override 626 public Insets getScreenInsets(GraphicsConfiguration gc) 627 { 628 return getScreenInsets(((Win32GraphicsDevice) gc.getDevice()).getScreen()); 629 } 630 631 @Override 632 public int getScreenResolution() { 633 Win32GraphicsEnvironment ge = (Win32GraphicsEnvironment) 634 GraphicsEnvironment.getLocalGraphicsEnvironment(); 635 return ge.getXResolution(); 636 } 637 @Override 638 protected native int getScreenWidth(); 639 @Override 640 protected native int getScreenHeight(); 641 private native Insets getScreenInsets(int screen); 642 643 644 @Override 645 public FontMetrics getFontMetrics(Font font) { 646 // This is an unsupported hack, but left in for a customer. 647 // Do not remove. 648 FontManager fm = FontManagerFactory.getInstance(); 649 if (fm instanceof SunFontManager 650 && ((SunFontManager) fm).usePlatformFontMetrics()) { 651 return WFontMetrics.getFontMetrics(font); 652 } 653 return super.getFontMetrics(font); 654 } 655 656 @Override 657 public FontPeer getFontPeer(String name, int style) { 658 FontPeer retval = null; 659 String lcName = name.toLowerCase(); 660 if (null != cacheFontPeer) { 661 retval = cacheFontPeer.get(lcName + style); 662 if (null != retval) { 663 return retval; 664 } 665 } 666 retval = new WFontPeer(name, style); 667 if (retval != null) { 668 if (null == cacheFontPeer) { 669 cacheFontPeer = new Hashtable<>(5, 0.9f); 670 } 671 if (null != cacheFontPeer) { 672 cacheFontPeer.put(lcName + style, retval); 673 } 674 } 675 return retval; 676 } 677 678 private native void nativeSync(); 679 680 @Override 681 public void sync() { 682 // flush the GDI/DD buffers 683 nativeSync(); 684 // now flush the OGL pipeline (this is a no-op if OGL is not enabled) 685 OGLRenderQueue.sync(); 686 // now flush the D3D pipeline (this is a no-op if D3D is not enabled) 687 D3DRenderQueue.sync(); 688 } 689 690 @Override 691 public PrintJob getPrintJob(Frame frame, String doctitle, 692 Properties props) { 693 return getPrintJob(frame, doctitle, null, null); 694 } 695 696 @Override 697 public PrintJob getPrintJob(Frame frame, String doctitle, 698 JobAttributes jobAttributes, 699 PageAttributes pageAttributes) 700 { 701 if (frame == null) { 702 throw new NullPointerException("frame must not be null"); 703 } 704 705 PrintJob2D printJob = new PrintJob2D(frame, doctitle, 706 jobAttributes, pageAttributes); 707 708 if (printJob.printDialog() == false) { 709 printJob = null; 710 } 711 712 return printJob; 713 } 714 715 @Override 716 public native void beep(); 717 718 @Override 719 public boolean getLockingKeyState(int key) { 720 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK || 721 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) { 722 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState"); 723 } 724 return getLockingKeyStateNative(key); 725 } 726 727 private native boolean getLockingKeyStateNative(int key); 728 729 @Override 730 public void setLockingKeyState(int key, boolean on) { 731 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK || 732 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) { 733 throw new IllegalArgumentException("invalid key for Toolkit.setLockingKeyState"); 734 } 735 setLockingKeyStateNative(key, on); 736 } 737 738 private native void setLockingKeyStateNative(int key, boolean on); 739 740 @Override 741 public Clipboard getSystemClipboard() { 742 SecurityManager security = System.getSecurityManager(); 743 if (security != null) { 744 security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION); 745 } 746 synchronized (this) { 747 if (clipboard == null) { 748 clipboard = new WClipboard(); 749 } 750 } 751 return clipboard; 752 } 753 754 @Override 755 protected native void loadSystemColors(int[] systemColors); 756 757 public static final Object targetToPeer(Object target) { 758 return SunToolkit.targetToPeer(target); 759 } 760 761 public static final void targetDisposedPeer(Object target, Object peer) { 762 SunToolkit.targetDisposedPeer(target, peer); 763 } 764 765 /** 766 * Returns a new input method adapter descriptor for native input methods. 767 */ 768 @Override 769 public InputMethodDescriptor getInputMethodAdapterDescriptor() { 770 return new WInputMethodDescriptor(); 771 } 772 773 /** 774 * Returns a style map for the input method highlight. 775 */ 776 @Override 777 public Map<java.awt.font.TextAttribute,?> mapInputMethodHighlight( 778 InputMethodHighlight highlight) 779 { 780 return WInputMethod.mapInputMethodHighlight(highlight); 781 } 782 783 /** 784 * Returns whether enableInputMethods should be set to true for peered 785 * TextComponent instances on this platform. 786 */ 787 @Override 788 public boolean enableInputMethodsForTextComponent() { 789 return true; 790 } 791 792 /** 793 * Returns the default keyboard locale of the underlying operating system 794 */ 795 @Override 796 public Locale getDefaultKeyboardLocale() { 797 Locale locale = WInputMethod.getNativeLocale(); 798 799 if (locale == null) { 800 return super.getDefaultKeyboardLocale(); 801 } else { 802 return locale; 803 } 804 } 805 806 /** 807 * Returns a new custom cursor. 808 */ 809 @Override 810 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) 811 throws IndexOutOfBoundsException { 812 return new WCustomCursor(cursor, hotSpot, name); 813 } 814 815 /** 816 * Returns the supported cursor size (Win32 only has one). 817 */ 818 @Override 819 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) { 820 return new Dimension(WCustomCursor.getCursorWidth(), 821 WCustomCursor.getCursorHeight()); 822 } 823 824 @Override 825 public native int getMaximumCursorColors(); 826 827 static void paletteChanged() { 828 ((Win32GraphicsEnvironment)GraphicsEnvironment 829 .getLocalGraphicsEnvironment()) 830 .paletteChanged(); 831 } 832 833 private static ExecutorService displayChangeExecutor; 834 835 /* 836 * Called from Toolkit native code when a WM_DISPLAYCHANGE occurs. 837 * Have Win32GraphicsEnvironment execute the display change code on the 838 * Event thread. 839 */ 840 static public void displayChanged() { 841 final Runnable runnable = () -> { 842 Object lge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 843 if (lge instanceof DisplayChangedListener) { 844 ((DisplayChangedListener) lge).displayChanged(); 845 } 846 }; 847 if (AppContext.getAppContext() != null) { 848 // Common case, standalone application 849 EventQueue.invokeLater(runnable); 850 } else { 851 if (displayChangeExecutor == null) { 852 // No synchronization, called on the Toolkit thread only 853 displayChangeExecutor = Executors.newFixedThreadPool(1, r -> { 854 Thread t = Executors.defaultThreadFactory().newThread(r); 855 t.setDaemon(true); 856 return t; 857 }); 858 } 859 displayChangeExecutor.submit(runnable); 860 } 861 } 862 863 /** 864 * create the peer for a DragSourceContext 865 */ 866 867 @Override 868 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { 869 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent()); 870 if (f != null) { 871 return f.createDragSourceContextPeer(dge); 872 } 873 874 return WDragSourceContextPeer.createDragSourceContextPeer(dge); 875 } 876 877 @Override 878 public <T extends DragGestureRecognizer> T 879 createDragGestureRecognizer(Class<T> abstractRecognizerClass, 880 DragSource ds, Component c, int srcActions, 881 DragGestureListener dgl) 882 { 883 final LightweightFrame f = SunToolkit.getLightweightFrame(c); 884 if (f != null) { 885 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl); 886 } 887 888 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) 889 return (T)new WMouseDragGestureRecognizer(ds, c, srcActions, dgl); 890 else 891 return null; 892 } 893 894 /** 895 * 896 */ 897 898 private static final String prefix = "DnD.Cursor."; 899 private static final String postfix = ".32x32"; 900 private static final String awtPrefix = "awt."; 901 private static final String dndPrefix = "DnD."; 902 903 @Override 904 protected Object lazilyLoadDesktopProperty(String name) { 905 if (name.startsWith(prefix)) { 906 String cursorName = name.substring(prefix.length(), name.length()) + postfix; 907 908 try { 909 return Cursor.getSystemCustomCursor(cursorName); 910 } catch (AWTException awte) { 911 throw new RuntimeException("cannot load system cursor: " + cursorName, awte); 912 } 913 } 914 915 if (name.equals("awt.dynamicLayoutSupported")) { 916 return Boolean.valueOf(isDynamicLayoutSupported()); 917 } 918 919 if (WDesktopProperties.isWindowsProperty(name) || 920 name.startsWith(awtPrefix) || name.startsWith(dndPrefix)) 921 { 922 synchronized(this) { 923 lazilyInitWProps(); 924 return desktopProperties.get(name); 925 } 926 } 927 928 return super.lazilyLoadDesktopProperty(name); 929 } 930 931 private synchronized void lazilyInitWProps() { 932 if (wprops == null) { 933 wprops = new WDesktopProperties(this); 934 updateProperties(wprops.getProperties()); 935 } 936 } 937 938 /* 939 * Called from lazilyLoadDesktopProperty because Windows doesn't 940 * always send WM_SETTINGCHANGE when it should. 941 */ 942 private synchronized boolean isDynamicLayoutSupported() { 943 boolean nativeDynamic = isDynamicLayoutSupportedNative(); 944 lazilyInitWProps(); 945 Boolean prop = (Boolean) desktopProperties.get("awt.dynamicLayoutSupported"); 946 947 if (log.isLoggable(PlatformLogger.Level.FINER)) { 948 log.finer("In WTK.isDynamicLayoutSupported()" + 949 " nativeDynamic == " + nativeDynamic + 950 " wprops.dynamic == " + prop); 951 } 952 953 if ((prop == null) || (nativeDynamic != prop.booleanValue())) { 954 // We missed the WM_SETTINGCHANGE, so we pretend 955 // we just got one - fire the propertyChange, etc. 956 windowsSettingChange(); 957 return nativeDynamic; 958 } 959 960 return prop.booleanValue(); 961 } 962 963 /* 964 * Called from native toolkit code when WM_SETTINGCHANGE message received 965 * Also called from lazilyLoadDynamicLayoutSupportedProperty because 966 * Windows doesn't always send WM_SETTINGCHANGE when it should. 967 */ 968 private void windowsSettingChange() { 969 // JDK-8039383: Have to update the value of XPSTYLE_THEME_ACTIVE property 970 // as soon as possible to prevent NPE and other errors because theme data 971 // has become unavailable. 972 final Map<String, Object> props = getWProps(); 973 if (props == null) { 974 // props has not been initialized, so we have nothing to update 975 return; 976 } 977 978 updateXPStyleEnabled(props.get(XPSTYLE_THEME_ACTIVE)); 979 980 if (AppContext.getAppContext() == null) { 981 // We cannot post the update to any EventQueue. Listeners will 982 // be called on EDTs by DesktopPropertyChangeSupport 983 updateProperties(props); 984 } else { 985 // Cannot update on Toolkit thread. 986 // DesktopPropertyChangeSupport will call listeners on Toolkit 987 // thread if it has AppContext (standalone mode) 988 EventQueue.invokeLater(() -> updateProperties(props)); 989 } 990 } 991 992 private synchronized void updateProperties(final Map<String, Object> props) { 993 if (null == props) { 994 return; 995 } 996 997 updateXPStyleEnabled(props.get(XPSTYLE_THEME_ACTIVE)); 998 999 for (String propName : props.keySet()) { 1000 Object val = props.get(propName); 1001 if (log.isLoggable(PlatformLogger.Level.FINER)) { 1002 log.finer("changed " + propName + " to " + val); 1003 } 1004 setDesktopProperty(propName, val); 1005 } 1006 } 1007 1008 private synchronized Map<String, Object> getWProps() { 1009 return (wprops != null) ? wprops.getProperties() : null; 1010 } 1011 1012 private void updateXPStyleEnabled(final Object dskProp) { 1013 ThemeReader.xpStyleEnabled = Boolean.TRUE.equals(dskProp); 1014 } 1015 1016 @Override 1017 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) { 1018 if (name == null) { 1019 // See JavaDoc for the Toolkit.addPropertyChangeListener() method 1020 return; 1021 } 1022 if ( WDesktopProperties.isWindowsProperty(name) 1023 || name.startsWith(awtPrefix) 1024 || name.startsWith(dndPrefix)) 1025 { 1026 // someone is interested in Windows-specific desktop properties 1027 // we should initialize wprops 1028 lazilyInitWProps(); 1029 } 1030 super.addPropertyChangeListener(name, pcl); 1031 } 1032 1033 /* 1034 * initialize only static props here and do not try to initialize props which depends on wprops, 1035 * this should be done in lazilyLoadDesktopProperty() only. 1036 */ 1037 @Override 1038 protected synchronized void initializeDesktopProperties() { 1039 desktopProperties.put("DnD.Autoscroll.initialDelay", 1040 Integer.valueOf(50)); 1041 desktopProperties.put("DnD.Autoscroll.interval", 1042 Integer.valueOf(50)); 1043 desktopProperties.put("DnD.isDragImageSupported", 1044 Boolean.TRUE); 1045 desktopProperties.put("Shell.shellFolderManager", 1046 "sun.awt.shell.Win32ShellFolderManager2"); 1047 } 1048 1049 /* 1050 * This returns the value for the desktop property "awt.font.desktophints" 1051 * This requires that the Windows properties have already been gathered. 1052 */ 1053 @Override 1054 protected synchronized RenderingHints getDesktopAAHints() { 1055 if (wprops == null) { 1056 return null; 1057 } else { 1058 return wprops.getDesktopAAHints(); 1059 } 1060 } 1061 1062 @Override 1063 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { 1064 return (modalityType == null) || 1065 (modalityType == Dialog.ModalityType.MODELESS) || 1066 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) || 1067 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) || 1068 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL); 1069 } 1070 1071 @Override 1072 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { 1073 return (exclusionType == null) || 1074 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) || 1075 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) || 1076 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); 1077 } 1078 1079 public static WToolkit getWToolkit() { 1080 WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit(); 1081 return toolkit; 1082 } 1083 1084 /** 1085 * There are two reasons why we don't use buffer per window when 1086 * Vista's DWM (aka Aero) is enabled: 1087 * - since with DWM all windows are already double-buffered, the application 1088 * doesn't get expose events so we don't get to use our true back-buffer, 1089 * wasting memory and performance (this is valid for both d3d and gdi 1090 * pipelines) 1091 * - in some cases with buffer per window enabled it is possible for the 1092 * paint manager to redirect rendering to the screen for some operations 1093 * (like copyArea), and since bpw uses its own BufferStrategy the 1094 * d3d onscreen rendering support is disabled and rendering goes through 1095 * GDI. This doesn't work well with Vista's DWM since one 1096 * can not perform GDI and D3D operations on the same surface 1097 * (see 6630702 for more info) 1098 * 1099 * Note: even though DWM composition state can change during the lifetime 1100 * of the application it is a rare event, and it is more often that it 1101 * is temporarily disabled (because of some app) than it is getting 1102 * permanently enabled so we can live with this approach without the 1103 * complexity of dwm state listeners and such. This can be revisited if 1104 * proved otherwise. 1105 */ 1106 @Override 1107 public boolean useBufferPerWindow() { 1108 return !Win32GraphicsEnvironment.isDWMCompositionEnabled(); 1109 } 1110 1111 @Override 1112 @SuppressWarnings("deprecation") 1113 public void grab(Window w) { 1114 if (w.getPeer() != null) { 1115 ((WWindowPeer)w.getPeer()).grab(); 1116 } 1117 } 1118 1119 @Override 1120 @SuppressWarnings("deprecation") 1121 public void ungrab(Window w) { 1122 if (w.getPeer() != null) { 1123 ((WWindowPeer)w.getPeer()).ungrab(); 1124 } 1125 } 1126 1127 /////////////////////////////////////////////////////////////////////////// 1128 // The following code is used for support of automatic showing of the touch 1129 // keyboard for text components and is accessed only from EDT. 1130 /////////////////////////////////////////////////////////////////////////// 1131 private static final WeakReference<Component> NULL_COMPONENT_WR = 1132 new WeakReference<>(null); 1133 private volatile WeakReference<Component> compOnTouchDownEvent = 1134 NULL_COMPONENT_WR; 1135 private volatile WeakReference<Component> compOnMousePressedEvent = 1136 NULL_COMPONENT_WR; 1137 1138 private boolean isComponentValidForTouchKeyboard(Component comp) { 1139 if ((comp != null) && comp.isEnabled() && comp.isFocusable() && 1140 (((comp instanceof TextComponent) && 1141 ((TextComponent) comp).isEditable()) || 1142 ((comp instanceof JTextComponent) && 1143 ((JTextComponent) comp).isEditable()))) { 1144 return true; 1145 } 1146 return false; 1147 } 1148 1149 @Override 1150 public void showOrHideTouchKeyboard(Component comp, AWTEvent e) { 1151 if (!(comp instanceof TextComponent) && 1152 !(comp instanceof JTextComponent)) { 1153 return; 1154 } 1155 1156 if ((e instanceof MouseEvent) && isComponentValidForTouchKeyboard(comp)) { 1157 MouseEvent me = (MouseEvent) e; 1158 if (me.getID() == MouseEvent.MOUSE_PRESSED) { 1159 if (AWTAccessor.getMouseEventAccessor().isCausedByTouchEvent(me)) { 1160 compOnTouchDownEvent = new WeakReference<>(comp); 1161 } else { 1162 compOnMousePressedEvent = new WeakReference<>(comp); 1163 } 1164 } else if (me.getID() == MouseEvent.MOUSE_RELEASED) { 1165 if (AWTAccessor.getMouseEventAccessor().isCausedByTouchEvent(me)) { 1166 if (compOnTouchDownEvent.get() == comp) { 1167 showTouchKeyboard(true); 1168 } 1169 compOnTouchDownEvent = NULL_COMPONENT_WR; 1170 } else { 1171 if (compOnMousePressedEvent.get() == comp) { 1172 showTouchKeyboard(false); 1173 } 1174 compOnMousePressedEvent = NULL_COMPONENT_WR; 1175 } 1176 } 1177 } else if (e instanceof FocusEvent) { 1178 FocusEvent fe = (FocusEvent) e; 1179 if (fe.getID() == FocusEvent.FOCUS_LOST) { 1180 // Hide the touch keyboard, if not a text component gains focus. 1181 if (!isComponentValidForTouchKeyboard(fe.getOppositeComponent())) { 1182 hideTouchKeyboard(); 1183 } 1184 } 1185 } 1186 } 1187 1188 private native void showTouchKeyboard(boolean causedByTouchEvent); 1189 private native void hideTouchKeyboard(); 1190 /////////////////////////////////////////////////////////////////////////// 1191 // End of the touch keyboard related code. 1192 /////////////////////////////////////////////////////////////////////////// 1193 1194 @Override 1195 public native boolean syncNativeQueue(final long timeout); 1196 @Override 1197 public boolean isDesktopSupported() { 1198 return true; 1199 } 1200 1201 @Override 1202 public DesktopPeer createDesktopPeer(Desktop target) { 1203 return new WDesktopPeer(); 1204 } 1205 1206 private static native void setExtraMouseButtonsEnabledNative(boolean enable); 1207 1208 @Override 1209 public boolean areExtraMouseButtonsEnabled() throws HeadlessException { 1210 return areExtraMouseButtonsEnabled; 1211 } 1212 1213 private native synchronized int getNumberOfButtonsImpl(); 1214 1215 @Override 1216 public int getNumberOfButtons(){ 1217 if (numberOfButtons == 0) { 1218 numberOfButtons = getNumberOfButtonsImpl(); 1219 } 1220 return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons; 1221 } 1222 1223 @Override 1224 public boolean isWindowOpacitySupported() { 1225 // supported in Win2K and later 1226 return true; 1227 } 1228 1229 @Override 1230 public boolean isWindowShapingSupported() { 1231 return true; 1232 } 1233 1234 @Override 1235 public boolean isWindowTranslucencySupported() { 1236 // supported in Win2K and later 1237 return true; 1238 } 1239 1240 @Override 1241 public boolean isTranslucencyCapable(GraphicsConfiguration gc) { 1242 //XXX: worth checking if 8-bit? Anyway, it doesn't hurt. 1243 return true; 1244 } 1245 1246 // On MS Windows one must use the peer.updateWindow() to implement 1247 // non-opaque windows. 1248 @Override 1249 public boolean needUpdateWindow() { 1250 return true; 1251 } 1252 }