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 }