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