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