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