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