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