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