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