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