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