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