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