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