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