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