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