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