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