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