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