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<String,FontPeer> 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 AccessController.doPrivileged( 114 new PrivilegedAction <Void> () 115 { 116 public Void 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<Void>() { 265 public Void 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 @SuppressWarnings("deprecation") 403 public void disableBackgroundErase(Canvas canvas) { 404 WCanvasPeer peer = (WCanvasPeer)canvas.getPeer(); 405 if (peer == null) { 406 throw new IllegalStateException("Canvas must have a valid peer"); 407 } 408 peer.disableBackgroundErase(); 409 } 410 411 public PanelPeer createPanel(Panel target) { 412 PanelPeer peer = new WPanelPeer(target); 413 targetCreatedPeer(target, peer); 414 return peer; 415 } 416 417 public WindowPeer createWindow(Window target) { 418 WindowPeer peer = new WWindowPeer(target); 419 targetCreatedPeer(target, peer); 420 return peer; 421 } 422 423 public DialogPeer createDialog(Dialog target) { 424 DialogPeer peer = new WDialogPeer(target); 425 targetCreatedPeer(target, peer); 426 return peer; 427 } 428 429 public FileDialogPeer createFileDialog(FileDialog target) { 430 FileDialogPeer peer = new WFileDialogPeer(target); 431 targetCreatedPeer(target, peer); 432 return peer; 433 } 434 435 public MenuBarPeer createMenuBar(MenuBar target) { 436 MenuBarPeer peer = new WMenuBarPeer(target); 437 targetCreatedPeer(target, peer); 438 return peer; 439 } 440 441 public MenuPeer createMenu(Menu target) { 442 MenuPeer peer = new WMenuPeer(target); 443 targetCreatedPeer(target, peer); 444 return peer; 445 } 446 447 public PopupMenuPeer createPopupMenu(PopupMenu target) { 448 PopupMenuPeer peer = new WPopupMenuPeer(target); 449 targetCreatedPeer(target, peer); 450 return peer; 451 } 452 453 public MenuItemPeer createMenuItem(MenuItem target) { 454 MenuItemPeer peer = new WMenuItemPeer(target); 455 targetCreatedPeer(target, peer); 456 return peer; 457 } 458 459 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 460 CheckboxMenuItemPeer peer = new WCheckboxMenuItemPeer(target); 461 targetCreatedPeer(target, peer); 462 return peer; 463 } 464 465 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 466 // (target is unused for now) 467 // Robot's don't need to go in the peer map since 468 // they're not Component's 469 return new WRobotPeer(screen); 470 } 471 472 public WEmbeddedFramePeer createEmbeddedFrame(WEmbeddedFrame target) { 473 WEmbeddedFramePeer peer = new WEmbeddedFramePeer(target); 474 targetCreatedPeer(target, peer); 475 return peer; 476 } 477 478 WPrintDialogPeer createWPrintDialog(WPrintDialog target) { 479 WPrintDialogPeer peer = new WPrintDialogPeer(target); 480 targetCreatedPeer(target, peer); 481 return peer; 482 } 483 484 WPageDialogPeer createWPageDialog(WPageDialog target) { 485 WPageDialogPeer peer = new WPageDialogPeer(target); 486 targetCreatedPeer(target, peer); 487 return peer; 488 } 489 490 public TrayIconPeer createTrayIcon(TrayIcon target) { 491 WTrayIconPeer peer = new WTrayIconPeer(target); 492 targetCreatedPeer(target, peer); 493 return peer; 494 } 495 496 public SystemTrayPeer createSystemTray(SystemTray target) { 497 return new WSystemTrayPeer(target); 498 } 499 500 public boolean isTraySupported() { 501 return true; 502 } 503 504 public KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager) 505 throws HeadlessException 506 { 507 return new WKeyboardFocusManagerPeer(manager); 508 } 509 510 protected native void setDynamicLayoutNative(boolean b); 511 512 public void setDynamicLayout(boolean b) { 513 if (b == dynamicLayoutSetting) { 514 return; 515 } 516 517 dynamicLayoutSetting = b; 518 setDynamicLayoutNative(b); 519 } 520 521 protected boolean isDynamicLayoutSet() { 522 return dynamicLayoutSetting; 523 } 524 525 /* 526 * Called from lazilyLoadDynamicLayoutSupportedProperty because 527 * Windows doesn't always send WM_SETTINGCHANGE when it should. 528 */ 529 protected native boolean isDynamicLayoutSupportedNative(); 530 531 public boolean isDynamicLayoutActive() { 532 return (isDynamicLayoutSet() && isDynamicLayoutSupported()); 533 } 534 535 /** 536 * Returns <code>true</code> if this frame state is supported. 537 */ 538 public boolean isFrameStateSupported(int state) { 539 switch (state) { 540 case Frame.NORMAL: 541 case Frame.ICONIFIED: 542 case Frame.MAXIMIZED_BOTH: 543 return true; 544 default: 545 return false; 546 } 547 } 548 549 static native ColorModel makeColorModel(); 550 static ColorModel screenmodel; 551 552 static ColorModel getStaticColorModel() { 553 if (GraphicsEnvironment.isHeadless()) { 554 throw new IllegalArgumentException(); 555 } 556 if (config == null) { 557 resetGC(); 558 } 559 return config.getColorModel(); 560 } 561 562 public ColorModel getColorModel() { 563 return getStaticColorModel(); 564 } 565 566 public Insets getScreenInsets(GraphicsConfiguration gc) 567 { 568 return getScreenInsets(((Win32GraphicsDevice) gc.getDevice()).getScreen()); 569 } 570 571 public int getScreenResolution() { 572 Win32GraphicsEnvironment ge = (Win32GraphicsEnvironment) 573 GraphicsEnvironment.getLocalGraphicsEnvironment(); 574 return ge.getXResolution(); 575 } 576 protected native int getScreenWidth(); 577 protected native int getScreenHeight(); 578 protected native Insets getScreenInsets(int screen); 579 580 581 public FontMetrics getFontMetrics(Font font) { 582 // This is an unsupported hack, but left in for a customer. 583 // Do not remove. 584 FontManager fm = FontManagerFactory.getInstance(); 585 if (fm instanceof SunFontManager 586 && ((SunFontManager) fm).usePlatformFontMetrics()) { 587 return WFontMetrics.getFontMetrics(font); 588 } 589 return super.getFontMetrics(font); 590 } 591 592 public FontPeer getFontPeer(String name, int style) { 593 FontPeer retval = null; 594 String lcName = name.toLowerCase(); 595 if (null != cacheFontPeer) { 596 retval = cacheFontPeer.get(lcName + style); 597 if (null != retval) { 598 return retval; 599 } 600 } 601 retval = new WFontPeer(name, style); 602 if (retval != null) { 603 if (null == cacheFontPeer) { 604 cacheFontPeer = new Hashtable<>(5, 0.9f); 605 } 606 if (null != cacheFontPeer) { 607 cacheFontPeer.put(lcName + style, retval); 608 } 609 } 610 return retval; 611 } 612 613 private native void nativeSync(); 614 615 public void sync() { 616 // flush the GDI/DD buffers 617 nativeSync(); 618 // now flush the OGL pipeline (this is a no-op if OGL is not enabled) 619 OGLRenderQueue.sync(); 620 // now flush the D3D pipeline (this is a no-op if D3D is not enabled) 621 D3DRenderQueue.sync(); 622 } 623 624 public PrintJob getPrintJob(Frame frame, String doctitle, 625 Properties props) { 626 return getPrintJob(frame, doctitle, null, null); 627 } 628 629 public PrintJob getPrintJob(Frame frame, String doctitle, 630 JobAttributes jobAttributes, 631 PageAttributes pageAttributes) 632 { 633 if (frame == null) { 634 throw new NullPointerException("frame must not be null"); 635 } 636 637 PrintJob2D printJob = new PrintJob2D(frame, doctitle, 638 jobAttributes, pageAttributes); 639 640 if (printJob.printDialog() == false) { 641 printJob = null; 642 } 643 644 return printJob; 645 } 646 647 public native void beep(); 648 649 public boolean getLockingKeyState(int key) { 650 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK || 651 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) { 652 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState"); 653 } 654 return getLockingKeyStateNative(key); 655 } 656 657 public native boolean getLockingKeyStateNative(int key); 658 659 public void setLockingKeyState(int key, boolean on) { 660 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK || 661 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) { 662 throw new IllegalArgumentException("invalid key for Toolkit.setLockingKeyState"); 663 } 664 setLockingKeyStateNative(key, on); 665 } 666 667 public native void setLockingKeyStateNative(int key, boolean on); 668 669 public Clipboard getSystemClipboard() { 670 SecurityManager security = System.getSecurityManager(); 671 if (security != null) { 672 security.checkSystemClipboardAccess(); 673 } 674 synchronized (this) { 675 if (clipboard == null) { 676 clipboard = new WClipboard(); 677 } 678 } 679 return clipboard; 680 } 681 682 protected native void loadSystemColors(int[] systemColors); 683 684 public static final Object targetToPeer(Object target) { 685 return SunToolkit.targetToPeer(target); 686 } 687 688 public static final void targetDisposedPeer(Object target, Object peer) { 689 SunToolkit.targetDisposedPeer(target, peer); 690 } 691 692 /** 693 * Returns a new input method adapter descriptor for native input methods. 694 */ 695 public InputMethodDescriptor getInputMethodAdapterDescriptor() { 696 return new WInputMethodDescriptor(); 697 } 698 699 /** 700 * Returns a style map for the input method highlight. 701 */ 702 public Map<java.awt.font.TextAttribute,?> mapInputMethodHighlight( 703 InputMethodHighlight highlight) 704 { 705 return WInputMethod.mapInputMethodHighlight(highlight); 706 } 707 708 /** 709 * Returns whether enableInputMethods should be set to true for peered 710 * TextComponent instances on this platform. 711 */ 712 public boolean enableInputMethodsForTextComponent() { 713 return true; 714 } 715 716 /** 717 * Returns the default keyboard locale of the underlying operating system 718 */ 719 public Locale getDefaultKeyboardLocale() { 720 Locale locale = WInputMethod.getNativeLocale(); 721 722 if (locale == null) { 723 return super.getDefaultKeyboardLocale(); 724 } else { 725 return locale; 726 } 727 } 728 729 /** 730 * Returns a new custom cursor. 731 */ 732 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) 733 throws IndexOutOfBoundsException { 734 return new WCustomCursor(cursor, hotSpot, name); 735 } 736 737 /** 738 * Returns the supported cursor size (Win32 only has one). 739 */ 740 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) { 741 return new Dimension(WCustomCursor.getCursorWidth(), 742 WCustomCursor.getCursorHeight()); 743 } 744 745 public native int getMaximumCursorColors(); 746 747 static void paletteChanged() { 748 ((Win32GraphicsEnvironment)GraphicsEnvironment 749 .getLocalGraphicsEnvironment()) 750 .paletteChanged(); 751 } 752 753 /* 754 * Called from Toolkit native code when a WM_DISPLAYCHANGE occurs. 755 * Have Win32GraphicsEnvironment execute the display change code on the 756 * Event thread. 757 */ 758 static public void displayChanged() { 759 EventQueue.invokeLater(new Runnable() { 760 public void run() { 761 ((Win32GraphicsEnvironment)GraphicsEnvironment 762 .getLocalGraphicsEnvironment()) 763 .displayChanged(); 764 } 765 }); 766 } 767 768 /** 769 * create the peer for a DragSourceContext 770 */ 771 772 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { 773 return WDragSourceContextPeer.createDragSourceContextPeer(dge); 774 } 775 776 public <T extends DragGestureRecognizer> T 777 createDragGestureRecognizer(Class<T> abstractRecognizerClass, 778 DragSource ds, Component c, int srcActions, 779 DragGestureListener dgl) 780 { 781 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) 782 return (T)new WMouseDragGestureRecognizer(ds, c, srcActions, dgl); 783 else 784 return null; 785 } 786 787 /** 788 * 789 */ 790 791 private static final String prefix = "DnD.Cursor."; 792 private static final String postfix = ".32x32"; 793 private static final String awtPrefix = "awt."; 794 private static final String dndPrefix = "DnD."; 795 796 protected Object lazilyLoadDesktopProperty(String name) { 797 if (name.startsWith(prefix)) { 798 String cursorName = name.substring(prefix.length(), name.length()) + postfix; 799 800 try { 801 return Cursor.getSystemCustomCursor(cursorName); 802 } catch (AWTException awte) { 803 throw new RuntimeException("cannot load system cursor: " + cursorName, awte); 804 } 805 } 806 807 if (name.equals("awt.dynamicLayoutSupported")) { 808 return Boolean.valueOf(isDynamicLayoutSupported()); 809 } 810 811 if (WDesktopProperties.isWindowsProperty(name) || 812 name.startsWith(awtPrefix) || name.startsWith(dndPrefix)) 813 { 814 synchronized(this) { 815 lazilyInitWProps(); 816 return desktopProperties.get(name); 817 } 818 } 819 820 return super.lazilyLoadDesktopProperty(name); 821 } 822 823 private synchronized void lazilyInitWProps() { 824 if (wprops == null) { 825 wprops = new WDesktopProperties(this); 826 updateProperties(); 827 } 828 } 829 830 /* 831 * Called from lazilyLoadDesktopProperty because Windows doesn't 832 * always send WM_SETTINGCHANGE when it should. 833 */ 834 private synchronized boolean isDynamicLayoutSupported() { 835 boolean nativeDynamic = isDynamicLayoutSupportedNative(); 836 lazilyInitWProps(); 837 Boolean prop = (Boolean) desktopProperties.get("awt.dynamicLayoutSupported"); 838 839 if (log.isLoggable(PlatformLogger.FINER)) { 840 log.finer("In WTK.isDynamicLayoutSupported()" + 841 " nativeDynamic == " + nativeDynamic + 842 " wprops.dynamic == " + prop); 843 } 844 845 if ((prop == null) || (nativeDynamic != prop.booleanValue())) { 846 // We missed the WM_SETTINGCHANGE, so we pretend 847 // we just got one - fire the propertyChange, etc. 848 windowsSettingChange(); 849 return nativeDynamic; 850 } 851 852 return prop.booleanValue(); 853 } 854 855 /* 856 * Called from native toolkit code when WM_SETTINGCHANGE message received 857 * Also called from lazilyLoadDynamicLayoutSupportedProperty because 858 * Windows doesn't always send WM_SETTINGCHANGE when it should. 859 */ 860 private void windowsSettingChange() { 861 EventQueue.invokeLater(new Runnable() { 862 public void run() { 863 updateProperties(); 864 } 865 }); 866 } 867 868 private synchronized void updateProperties() { 869 if (null == wprops) { 870 // wprops has not been initialized, so we have nothing to update 871 return; 872 } 873 874 Map<String, Object> props = wprops.getProperties(); 875 for (String propName : props.keySet()) { 876 Object val = props.get(propName); 877 if (log.isLoggable(PlatformLogger.FINER)) { 878 log.finer("changed " + propName + " to " + val); 879 } 880 setDesktopProperty(propName, val); 881 } 882 } 883 884 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) { 885 if (name == null) { 886 // See JavaDoc for the Toolkit.addPropertyChangeListener() method 887 return; 888 } 889 if ( WDesktopProperties.isWindowsProperty(name) 890 || name.startsWith(awtPrefix) 891 || name.startsWith(dndPrefix)) 892 { 893 // someone is interested in Windows-specific desktop properties 894 // we should initialize wprops 895 lazilyInitWProps(); 896 } 897 super.addPropertyChangeListener(name, pcl); 898 } 899 900 /* 901 * initialize only static props here and do not try to initialize props which depends on wprops, 902 * this should be done in lazilyLoadDesktopProperty() only. 903 */ 904 protected synchronized void initializeDesktopProperties() { 905 desktopProperties.put("DnD.Autoscroll.initialDelay", 906 Integer.valueOf(50)); 907 desktopProperties.put("DnD.Autoscroll.interval", 908 Integer.valueOf(50)); 909 desktopProperties.put("DnD.isDragImageSupported", 910 Boolean.TRUE); 911 desktopProperties.put("Shell.shellFolderManager", 912 "sun.awt.shell.Win32ShellFolderManager2"); 913 } 914 915 /* 916 * This returns the value for the desktop property "awt.font.desktophints" 917 * This requires that the Windows properties have already been gathered. 918 */ 919 protected synchronized RenderingHints getDesktopAAHints() { 920 if (wprops == null) { 921 return null; 922 } else { 923 return wprops.getDesktopAAHints(); 924 } 925 } 926 927 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { 928 return (modalityType == null) || 929 (modalityType == Dialog.ModalityType.MODELESS) || 930 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) || 931 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) || 932 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL); 933 } 934 935 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { 936 return (exclusionType == null) || 937 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) || 938 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) || 939 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); 940 } 941 942 public static WToolkit getWToolkit() { 943 WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit(); 944 return toolkit; 945 } 946 947 /** 948 * There are two reasons why we don't use buffer per window when 949 * Vista's DWM (aka Aero) is enabled: 950 * - since with DWM all windows are already double-buffered, the application 951 * doesn't get expose events so we don't get to use our true back-buffer, 952 * wasting memory and performance (this is valid for both d3d and gdi 953 * pipelines) 954 * - in some cases with buffer per window enabled it is possible for the 955 * paint manager to redirect rendering to the screen for some operations 956 * (like copyArea), and since bpw uses its own BufferStrategy the 957 * d3d onscreen rendering support is disabled and rendering goes through 958 * GDI. This doesn't work well with Vista's DWM since one 959 * can not perform GDI and D3D operations on the same surface 960 * (see 6630702 for more info) 961 * 962 * Note: even though DWM composition state can change during the lifetime 963 * of the application it is a rare event, and it is more often that it 964 * is temporarily disabled (because of some app) than it is getting 965 * permanently enabled so we can live with this approach without the 966 * complexity of dwm state listeners and such. This can be revisited if 967 * proved otherwise. 968 */ 969 @Override 970 public boolean useBufferPerWindow() { 971 return !Win32GraphicsEnvironment.isDWMCompositionEnabled(); 972 } 973 974 @SuppressWarnings("deprecation") 975 public void grab(Window w) { 976 if (w.getPeer() != null) { 977 ((WWindowPeer)w.getPeer()).grab(); 978 } 979 } 980 981 @SuppressWarnings("deprecation") 982 public void ungrab(Window w) { 983 if (w.getPeer() != null) { 984 ((WWindowPeer)w.getPeer()).ungrab(); 985 } 986 } 987 988 public native boolean syncNativeQueue(final long timeout); 989 public boolean isDesktopSupported() { 990 return true; 991 } 992 993 public DesktopPeer createDesktopPeer(Desktop target) { 994 return new WDesktopPeer(); 995 } 996 997 public static native void setExtraMouseButtonsEnabledNative(boolean enable); 998 999 public boolean areExtraMouseButtonsEnabled() throws HeadlessException { 1000 return areExtraMouseButtonsEnabled; 1001 } 1002 1003 private native synchronized int getNumberOfButtonsImpl(); 1004 1005 @Override 1006 public int getNumberOfButtons(){ 1007 if (numberOfButtons == 0) { 1008 numberOfButtons = getNumberOfButtonsImpl(); 1009 } 1010 return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons; 1011 } 1012 1013 @Override 1014 public boolean isWindowOpacitySupported() { 1015 // supported in Win2K and later 1016 return true; 1017 } 1018 1019 @Override 1020 public boolean isWindowShapingSupported() { 1021 return true; 1022 } 1023 1024 @Override 1025 public boolean isWindowTranslucencySupported() { 1026 // supported in Win2K and later 1027 return true; 1028 } 1029 1030 @Override 1031 public boolean isTranslucencyCapable(GraphicsConfiguration gc) { 1032 //XXX: worth checking if 8-bit? Anyway, it doesn't hurt. 1033 return true; 1034 } 1035 1036 // On MS Windows one must use the peer.updateWindow() to implement 1037 // non-opaque windows. 1038 @Override 1039 public boolean needUpdateWindow() { 1040 return true; 1041 } 1042 }