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