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