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