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