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