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 }