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