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