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