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.AWTEventMulticaster; 30 import java.awt.Color; 31 import java.awt.Component; 32 import java.awt.Container; 33 import java.awt.Dialog; 34 import java.awt.Dimension; 35 import java.awt.Graphics; 36 import java.awt.GraphicsConfiguration; 37 import java.awt.GraphicsDevice; 38 import java.awt.GraphicsEnvironment; 39 import java.awt.Image; 40 import java.awt.Insets; 41 import java.awt.KeyboardFocusManager; 42 import java.awt.Rectangle; 43 import java.awt.Shape; 44 import java.awt.SystemColor; 45 import java.awt.Window; 46 import java.awt.event.FocusEvent; 47 import java.awt.event.WindowEvent; 48 import java.awt.event.WindowListener; 49 import java.awt.geom.AffineTransform; 50 import java.awt.image.DataBufferInt; 51 import java.awt.peer.WindowPeer; 52 import java.beans.PropertyChangeEvent; 53 import java.beans.PropertyChangeListener; 54 import java.util.LinkedList; 55 import java.util.List; 56 57 import sun.awt.AWTAccessor; 58 import sun.awt.AppContext; 59 import sun.awt.DisplayChangedListener; 60 import sun.awt.SunToolkit; 61 import sun.awt.Win32GraphicsConfig; 62 import sun.awt.Win32GraphicsDevice; 63 import sun.awt.Win32GraphicsEnvironment; 64 import sun.java2d.SunGraphicsEnvironment; 65 import sun.java2d.pipe.Region; 66 import sun.util.logging.PlatformLogger; 67 68 public class WWindowPeer extends WPanelPeer implements WindowPeer, 69 DisplayChangedListener 70 { 71 72 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WWindowPeer"); 73 private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.windows.screen.WWindowPeer"); 74 75 // we can't use WDialogPeer as blocker may be an instance of WPrintDialogPeer that 76 // extends WWindowPeer, not WDialogPeer 77 private WWindowPeer modalBlocker = null; 78 79 private boolean isOpaque; 80 81 private TranslucentWindowPainter painter; 82 83 /* 84 * A key used for storing a list of active windows in AppContext. The value 85 * is a list of windows, sorted by the time of activation: later a window is 86 * activated, greater its index is in the list. 87 */ 88 private static final StringBuffer ACTIVE_WINDOWS_KEY = 89 new StringBuffer("active_windows_list"); 90 91 /* 92 * Listener for 'activeWindow' KFM property changes. It is added to each 93 * AppContext KFM. See ActiveWindowListener inner class below. 94 */ 95 private static PropertyChangeListener activeWindowListener = 96 new ActiveWindowListener(); 97 98 /* 99 * The object is a listener for the AppContext.GUI_DISPOSED property. 100 */ 101 private static final PropertyChangeListener guiDisposedListener = 102 new GuiDisposedListener(); 103 104 /* 105 * Called (on the Toolkit thread) before the appropriate 106 * WindowStateEvent is posted to the EventQueue. 107 */ 108 private WindowListener windowListener; 109 private float scaleX; 110 private float scaleY; 111 112 /** 113 * Initialize JNI field IDs 114 */ 115 private static native void initIDs(); 116 static { 117 initIDs(); 118 } 119 120 // WComponentPeer overrides 121 @Override 122 @SuppressWarnings("unchecked") 123 protected void disposeImpl() { 124 AppContext appContext = SunToolkit.targetToAppContext(target); 125 synchronized (appContext) { 126 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 127 if (l != null) { 128 l.remove(this); 129 } 130 } 131 132 // Remove ourself from the Map of DisplayChangeListeners 133 GraphicsConfiguration gc = getGraphicsConfiguration(); 134 ((Win32GraphicsDevice)gc.getDevice()).removeDisplayChangedListener(this); 135 136 synchronized (getStateLock()) { 137 TranslucentWindowPainter currentPainter = painter; 138 if (currentPainter != null) { 139 currentPainter.flush(); 140 // don't set the current one to null here; reduces the chances of 141 // MT issues (like NPEs) 142 } 143 } 144 145 super.disposeImpl(); 146 } 147 148 // WindowPeer implementation 149 150 @Override 151 public void toFront() { 152 updateFocusableWindowState(); 153 _toFront(); 154 } 155 private native void _toFront(); 156 157 @Override 158 public native void toBack(); 159 160 private native void setAlwaysOnTopNative(boolean value); 161 162 public void setAlwaysOnTop(boolean value) { 163 if ((value && ((Window)target).isVisible()) || !value) { 164 setAlwaysOnTopNative(value); 165 } 166 } 167 168 @Override 169 public void updateAlwaysOnTopState() { 170 setAlwaysOnTop(((Window)target).isAlwaysOnTop()); 171 } 172 173 @Override 174 public void updateFocusableWindowState() { 175 setFocusableWindow(((Window)target).isFocusableWindow()); 176 } 177 native void setFocusableWindow(boolean value); 178 179 // FramePeer & DialogPeer partial shared implementation 180 181 public void setTitle(String title) { 182 // allow a null title to pass as an empty string. 183 if (title == null) { 184 title = ""; 185 } 186 _setTitle(title); 187 } 188 private native void _setTitle(String title); 189 190 public void setResizable(boolean resizable) { 191 _setResizable(resizable); 192 } 193 194 private native void _setResizable(boolean resizable); 195 196 // Toolkit & peer internals 197 198 WWindowPeer(Window target) { 199 super(target); 200 } 201 202 @Override 203 void initialize() { 204 super.initialize(); 205 206 updateInsets(insets_); 207 208 if (!((Window) target).isFontSet()) { 209 ((Window) target).setFont(defaultFont); 210 setFont(defaultFont); 211 } 212 if (!((Window) target).isForegroundSet()) { 213 ((Window) target).setForeground(SystemColor.windowText); 214 } 215 if (!((Window) target).isBackgroundSet()) { 216 ((Window) target).setBackground(SystemColor.window); 217 } 218 219 // Express our interest in display changes 220 GraphicsConfiguration gc = getGraphicsConfiguration(); 221 Win32GraphicsDevice gd = (Win32GraphicsDevice) gc.getDevice(); 222 gd.addDisplayChangedListener(this); 223 scaleX = gd.getDefaultScaleX(); 224 scaleY = gd.getDefaultScaleY(); 225 226 initActiveWindowsTracking((Window)target); 227 228 updateIconImages(); 229 230 Shape shape = ((Window)target).getShape(); 231 if (shape != null) { 232 applyShape(Region.getInstance(shape, null)); 233 } 234 235 float opacity = ((Window)target).getOpacity(); 236 if (opacity < 1.0f) { 237 setOpacity(opacity); 238 } 239 240 synchronized (getStateLock()) { 241 // default value of a boolean field is 'false', so set isOpaque to 242 // true here explicitly 243 this.isOpaque = true; 244 setOpaque(((Window)target).isOpaque()); 245 } 246 } 247 248 native void createAwtWindow(WComponentPeer parent); 249 250 private volatile Window.Type windowType = Window.Type.NORMAL; 251 252 // This method must be called for Window, Dialog, and Frame before creating 253 // the hwnd 254 void preCreate(WComponentPeer parent) { 255 windowType = ((Window)target).getType(); 256 } 257 258 @Override 259 void create(WComponentPeer parent) { 260 preCreate(parent); 261 createAwtWindow(parent); 262 } 263 264 @Override 265 final WComponentPeer getNativeParent() { 266 final Container owner = ((Window) target).getOwner(); 267 return (WComponentPeer) WToolkit.targetToPeer(owner); 268 } 269 270 // should be overriden in WDialogPeer 271 protected void realShow() { 272 super.show(); 273 } 274 275 @Override 276 public void show() { 277 updateFocusableWindowState(); 278 279 boolean alwaysOnTop = ((Window)target).isAlwaysOnTop(); 280 281 // Fix for 4868278. 282 // If we create a window with a specific GraphicsConfig, and then move it with 283 // setLocation() or setBounds() to another one before its peer has been created, 284 // then calling Window.getGraphicsConfig() returns wrong config. That may lead 285 // to some problems like wrong-placed tooltips. It is caused by calling 286 // super.displayChanged() in WWindowPeer.displayChanged() regardless of whether 287 // GraphicsDevice was really changed, or not. So we need to track it here. 288 updateGC(); 289 290 realShow(); 291 updateMinimumSize(); 292 293 if (((Window)target).isAlwaysOnTopSupported() && alwaysOnTop) { 294 setAlwaysOnTop(alwaysOnTop); 295 } 296 297 synchronized (getStateLock()) { 298 if (!isOpaque) { 299 updateWindow(true); 300 } 301 } 302 303 // See https://javafx-jira.kenai.com/browse/RT-32570 304 WComponentPeer owner = getNativeParent(); 305 if (owner != null && owner.isLightweightFramePeer()) { 306 Rectangle b = getBounds(); 307 handleExpose(0, 0, b.width, b.height); 308 } 309 } 310 311 // Synchronize the insets members (here & in helper) with actual window 312 // state. 313 native void updateInsets(Insets i); 314 315 static native int getSysMinWidth(); 316 static native int getSysMinHeight(); 317 static native int getSysIconWidth(); 318 static native int getSysIconHeight(); 319 static native int getSysSmIconWidth(); 320 static native int getSysSmIconHeight(); 321 /**windows/classes/sun/awt/windows/ 322 * Creates native icon from specified raster data and updates 323 * icon for window and all descendant windows that inherit icon. 324 * Raster data should be passed in the ARGB form. 325 * Note that raster data format was changed to provide support 326 * for XP icons with alpha-channel 327 */ 328 native void setIconImagesData(int[] iconRaster, int w, int h, 329 int[] smallIconRaster, int smw, int smh); 330 331 synchronized native void reshapeFrame(int x, int y, int width, int height); 332 333 native Dimension getNativeWindowSize(); 334 335 public Dimension getScaledWindowSize() { 336 return getNativeWindowSize(); 337 } 338 339 public boolean requestWindowFocus(FocusEvent.Cause cause) { 340 if (!focusAllowedFor()) { 341 return false; 342 } 343 return requestWindowFocus(cause == FocusEvent.Cause.MOUSE_EVENT); 344 } 345 private native boolean requestWindowFocus(boolean isMouseEventCause); 346 347 public boolean focusAllowedFor() { 348 Window window = (Window)this.target; 349 if (!window.isVisible() || 350 !window.isEnabled() || 351 !window.isFocusableWindow()) 352 { 353 return false; 354 } 355 if (isModalBlocked()) { 356 return false; 357 } 358 return true; 359 } 360 361 @Override 362 void hide() { 363 WindowListener listener = windowListener; 364 if (listener != null) { 365 // We're not getting WINDOW_CLOSING from the native code when hiding 366 // the window programmatically. So, create it and notify the listener. 367 listener.windowClosing(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 368 } 369 super.hide(); 370 } 371 372 // WARNING: it's called on the Toolkit thread! 373 @Override 374 void preprocessPostEvent(AWTEvent event) { 375 if (event instanceof WindowEvent) { 376 WindowListener listener = windowListener; 377 if (listener != null) { 378 switch(event.getID()) { 379 case WindowEvent.WINDOW_CLOSING: 380 listener.windowClosing((WindowEvent)event); 381 break; 382 case WindowEvent.WINDOW_ICONIFIED: 383 listener.windowIconified((WindowEvent)event); 384 break; 385 } 386 } 387 } 388 } 389 390 synchronized void addWindowListener(WindowListener l) { 391 windowListener = AWTEventMulticaster.add(windowListener, l); 392 } 393 394 synchronized void removeWindowListener(WindowListener l) { 395 windowListener = AWTEventMulticaster.remove(windowListener, l); 396 } 397 398 @Override 399 public void updateMinimumSize() { 400 Dimension minimumSize = null; 401 if (((Component)target).isMinimumSizeSet()) { 402 minimumSize = ((Component)target).getMinimumSize(); 403 } 404 if (minimumSize != null) { 405 int w = Math.max(minimumSize.width, scaleDownX(getSysMinWidth())); 406 int h = Math.max(minimumSize.height, scaleDownY(getSysMinHeight())); 407 setMinSize(w, h); 408 } else { 409 setMinSize(0, 0); 410 } 411 } 412 413 @Override 414 public void updateIconImages() { 415 java.util.List<Image> imageList = ((Window)target).getIconImages(); 416 if (imageList == null || imageList.size() == 0) { 417 setIconImagesData(null, 0, 0, null, 0, 0); 418 } else { 419 int w = getSysIconWidth(); 420 int h = getSysIconHeight(); 421 int smw = getSysSmIconWidth(); 422 int smh = getSysSmIconHeight(); 423 AffineTransform tx = getGraphicsConfiguration().getDefaultTransform(); 424 w = Region.clipScale(w, tx.getScaleX()); 425 h = Region.clipScale(h, tx.getScaleY()); 426 smw = Region.clipScale(smw, tx.getScaleX()); 427 smh = Region.clipScale(smh, tx.getScaleY()); 428 DataBufferInt iconData = SunToolkit.getScaledIconData(imageList, 429 w, h); 430 DataBufferInt iconSmData = SunToolkit.getScaledIconData(imageList, 431 smw, smh); 432 if (iconData != null && iconSmData != null) { 433 setIconImagesData(iconData.getData(), w, h, 434 iconSmData.getData(), smw, smh); 435 } else { 436 setIconImagesData(null, 0, 0, null, 0, 0); 437 } 438 } 439 } 440 441 native void setMinSize(int width, int height); 442 443 /* 444 * ---- MODALITY SUPPORT ---- 445 */ 446 447 /** 448 * Some modality-related code here because WFileDialogPeer, WPrintDialogPeer and 449 * WPageDialogPeer are descendants of WWindowPeer, not WDialogPeer 450 */ 451 452 public boolean isModalBlocked() { 453 return modalBlocker != null; 454 } 455 456 @Override 457 public void setModalBlocked(Dialog dialog, boolean blocked) { 458 synchronized (((Component)getTarget()).getTreeLock()) // State lock should always be after awtLock 459 { 460 // use WWindowPeer instead of WDialogPeer because of FileDialogs and PrintDialogs 461 WWindowPeer blockerPeer = AWTAccessor.getComponentAccessor() 462 .getPeer(dialog); 463 if (blocked) 464 { 465 modalBlocker = blockerPeer; 466 // handle native dialogs separately, as they may have not 467 // got HWND yet; modalEnable/modalDisable is called from 468 // their setHWnd() methods 469 if (blockerPeer instanceof WFileDialogPeer) { 470 ((WFileDialogPeer)blockerPeer).blockWindow(this); 471 } else if (blockerPeer instanceof WPrintDialogPeer) { 472 ((WPrintDialogPeer)blockerPeer).blockWindow(this); 473 } else { 474 modalDisable(dialog, blockerPeer.getHWnd()); 475 } 476 } else { 477 modalBlocker = null; 478 if (blockerPeer instanceof WFileDialogPeer) { 479 ((WFileDialogPeer)blockerPeer).unblockWindow(this); 480 } else if (blockerPeer instanceof WPrintDialogPeer) { 481 ((WPrintDialogPeer)blockerPeer).unblockWindow(this); 482 } else { 483 modalEnable(dialog); 484 } 485 } 486 } 487 } 488 489 native void modalDisable(Dialog blocker, long blockerHWnd); 490 native void modalEnable(Dialog blocker); 491 492 /* 493 * Returns all the ever active windows from the current AppContext. 494 * The list is sorted by the time of activation, so the latest 495 * active window is always at the end. 496 */ 497 @SuppressWarnings("unchecked") 498 public static long[] getActiveWindowHandles(Component target) { 499 AppContext appContext = SunToolkit.targetToAppContext(target); 500 if (appContext == null) return null; 501 synchronized (appContext) { 502 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 503 if (l == null) { 504 return null; 505 } 506 long[] result = new long[l.size()]; 507 for (int j = 0; j < l.size(); j++) { 508 result[j] = l.get(j).getHWnd(); 509 } 510 return result; 511 } 512 } 513 514 /* 515 * ----DISPLAY CHANGE SUPPORT---- 516 */ 517 518 /* 519 * Called from native code when we have been dragged onto another screen. 520 */ 521 void draggedToNewScreen() { 522 displayChanged(); 523 } 524 525 public void updateGC() { 526 int scrn = getScreenImOn(); 527 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 528 log.finer("Screen number: " + scrn); 529 } 530 531 // get current GD 532 Win32GraphicsDevice oldDev = winGraphicsConfig.getDevice(); 533 534 Win32GraphicsDevice newDev; 535 GraphicsDevice[] devs = GraphicsEnvironment 536 .getLocalGraphicsEnvironment() 537 .getScreenDevices(); 538 // Occasionally during device addition/removal getScreenImOn can return 539 // a non-existing screen number. Use the default device in this case. 540 if (scrn >= devs.length) { 541 newDev = (Win32GraphicsDevice)GraphicsEnvironment 542 .getLocalGraphicsEnvironment().getDefaultScreenDevice(); 543 } else { 544 newDev = (Win32GraphicsDevice)devs[scrn]; 545 } 546 547 // Set winGraphicsConfig to the default GC for the monitor this Window 548 // is now mostly on. 549 winGraphicsConfig = (Win32GraphicsConfig)newDev 550 .getDefaultConfiguration(); 551 if (screenLog.isLoggable(PlatformLogger.Level.FINE)) { 552 if (winGraphicsConfig == null) { 553 screenLog.fine("Assertion (winGraphicsConfig != null) failed"); 554 } 555 } 556 557 // if on a different display, take off old GD and put on new GD 558 if (oldDev != newDev) { 559 oldDev.removeDisplayChangedListener(this); 560 newDev.addDisplayChangedListener(this); 561 } 562 563 AWTAccessor.getComponentAccessor(). 564 setGraphicsConfiguration((Component)target, winGraphicsConfig); 565 566 checkDPIChange(oldDev, newDev); 567 } 568 569 private void checkDPIChange(Win32GraphicsDevice oldDev, 570 Win32GraphicsDevice newDev) { 571 float newScaleX = newDev.getDefaultScaleX(); 572 float newScaleY = newDev.getDefaultScaleY(); 573 574 if (scaleX != newScaleX || scaleY != newScaleY) { 575 windowDPIChange(oldDev.getScreen(), scaleX, scaleY, 576 newDev.getScreen(), newScaleX, newScaleY); 577 scaleX = newScaleX; 578 scaleY = newScaleY; 579 } 580 } 581 582 /** 583 * From the DisplayChangedListener interface. 584 * 585 * This method handles a display change - either when the display settings 586 * are changed, or when the window has been dragged onto a different 587 * display. 588 * Called after a change in the display mode. This event 589 * triggers replacing the surfaceData object (since that object 590 * reflects the current display depth information, which has 591 * just changed). 592 */ 593 @Override 594 public void displayChanged() { 595 SunToolkit.executeOnEventHandlerThread(target, this::updateGC); 596 } 597 598 /** 599 * Part of the DisplayChangedListener interface: components 600 * do not need to react to this event 601 */ 602 @Override 603 public void paletteChanged() { 604 } 605 606 private native int getScreenImOn(); 607 608 // Used in Win32GraphicsDevice. 609 public final native void setFullScreenExclusiveModeState(boolean state); 610 611 /* 612 * ----END DISPLAY CHANGE SUPPORT---- 613 */ 614 615 public void grab() { 616 nativeGrab(); 617 } 618 619 public void ungrab() { 620 nativeUngrab(); 621 } 622 private native void nativeGrab(); 623 private native void nativeUngrab(); 624 625 private boolean hasWarningWindow() { 626 return ((Window)target).getWarningString() != null; 627 } 628 629 boolean isTargetUndecorated() { 630 return true; 631 } 632 633 // These are the peer bounds. They get updated at: 634 // 1. the WWindowPeer.setBounds() method. 635 // 2. the native code (on WM_SIZE/WM_MOVE) 636 private volatile int sysX = 0; 637 private volatile int sysY = 0; 638 private volatile int sysW = 0; 639 private volatile int sysH = 0; 640 641 @Override 642 public native void repositionSecurityWarning(); 643 644 @Override 645 public void setBounds(int x, int y, int width, int height, int op) { 646 sysX = x; 647 sysY = y; 648 sysW = width; 649 sysH = height; 650 651 int cx = x + width / 2; 652 int cy = y + height / 2; 653 GraphicsConfiguration current = getGraphicsConfiguration(); 654 GraphicsConfiguration other = SunGraphicsEnvironment 655 .getGraphicsConfigurationAtPoint(current, cx, cy); 656 if (!current.equals(other)) { 657 AffineTransform tx = other.getDefaultTransform(); 658 double otherScaleX = tx.getScaleX(); 659 double otherScaleY = tx.getScaleY(); 660 initScales(); 661 if (scaleX != otherScaleX || scaleY != otherScaleY) { 662 x = (int) Math.floor(x * otherScaleX / scaleX); 663 y = (int) Math.floor(y * otherScaleY / scaleY); 664 } 665 } 666 667 super.setBounds(x, y, width, height, op); 668 } 669 670 private void initScales() { 671 672 if (scaleX >= 1 && scaleY >= 1) { 673 return; 674 } 675 676 GraphicsConfiguration gc = getGraphicsConfiguration(); 677 if (gc instanceof Win32GraphicsConfig) { 678 Win32GraphicsDevice gd = ((Win32GraphicsConfig) gc).getDevice(); 679 scaleX = gd.getDefaultScaleX(); 680 scaleY = gd.getDefaultScaleY(); 681 } else { 682 AffineTransform tx = gc.getDefaultTransform(); 683 scaleX = (float) tx.getScaleX(); 684 scaleY = (float) tx.getScaleY(); 685 } 686 } 687 688 final int scaleUpX(int x) { 689 return Region.clipRound(x * scaleX); 690 } 691 692 final int scaleUpY(int y) { 693 return Region.clipRound(y * scaleY); 694 } 695 696 final int scaleDownX(int x) { 697 return Region.clipRound(x / scaleX); 698 } 699 700 final int scaleDownY(int y) { 701 return Region.clipRound(y / scaleY); 702 } 703 704 @Override 705 public void print(Graphics g) { 706 // We assume we print the whole frame, 707 // so we expect no clip was set previously 708 Shape shape = ((Window)target).getShape(); 709 if (shape != null) { 710 g.setClip(shape); 711 } 712 super.print(g); 713 } 714 715 private void replaceSurfaceDataRecursively(Component c) { 716 if (c instanceof Container) { 717 for (Component child : ((Container)c).getComponents()) { 718 replaceSurfaceDataRecursively(child); 719 } 720 } 721 final Object cp = AWTAccessor.getComponentAccessor().getPeer(c); 722 if (cp instanceof WComponentPeer) { 723 ((WComponentPeer)cp).replaceSurfaceDataLater(); 724 } 725 } 726 727 public final Graphics getTranslucentGraphics() { 728 synchronized (getStateLock()) { 729 return isOpaque ? null : painter.getGraphics(false); 730 } 731 } 732 733 @Override 734 public void setBackground(Color c) { 735 super.setBackground(c); 736 synchronized (getStateLock()) { 737 if (!isOpaque && ((Window)target).isVisible()) { 738 updateWindow(true); 739 } 740 } 741 } 742 743 private native void setOpacity(int iOpacity); 744 private float opacity = 1.0f; 745 746 @Override 747 public void setOpacity(float opacity) { 748 if (!((SunToolkit)((Window)target).getToolkit()). 749 isWindowOpacitySupported()) 750 { 751 return; 752 } 753 754 if (opacity < 0.0f || opacity > 1.0f) { 755 throw new IllegalArgumentException( 756 "The value of opacity should be in the range [0.0f .. 1.0f]."); 757 } 758 759 if (((this.opacity == 1.0f && opacity < 1.0f) || 760 (this.opacity < 1.0f && opacity == 1.0f)) && 761 !Win32GraphicsEnvironment.isVistaOS()) 762 { 763 // non-Vista OS: only replace the surface data if opacity status 764 // changed (see WComponentPeer.isAccelCapable() for more) 765 replaceSurfaceDataRecursively((Component)getTarget()); 766 } 767 768 this.opacity = opacity; 769 770 final int maxOpacity = 0xff; 771 int iOpacity = (int)(opacity * maxOpacity); 772 if (iOpacity < 0) { 773 iOpacity = 0; 774 } 775 if (iOpacity > maxOpacity) { 776 iOpacity = maxOpacity; 777 } 778 779 setOpacity(iOpacity); 780 781 synchronized (getStateLock()) { 782 if (!isOpaque && ((Window)target).isVisible()) { 783 updateWindow(true); 784 } 785 } 786 } 787 788 private native void setOpaqueImpl(boolean isOpaque); 789 790 @Override 791 public void setOpaque(boolean isOpaque) { 792 synchronized (getStateLock()) { 793 if (this.isOpaque == isOpaque) { 794 return; 795 } 796 } 797 798 Window target = (Window)getTarget(); 799 800 if (!isOpaque) { 801 SunToolkit sunToolkit = (SunToolkit)target.getToolkit(); 802 if (!sunToolkit.isWindowTranslucencySupported() || 803 !sunToolkit.isTranslucencyCapable(target.getGraphicsConfiguration())) 804 { 805 return; 806 } 807 } 808 809 boolean isVistaOS = Win32GraphicsEnvironment.isVistaOS(); 810 811 if (this.isOpaque != isOpaque && !isVistaOS) { 812 // non-Vista OS: only replace the surface data if the opacity 813 // status changed (see WComponentPeer.isAccelCapable() for more) 814 replaceSurfaceDataRecursively(target); 815 } 816 817 synchronized (getStateLock()) { 818 this.isOpaque = isOpaque; 819 setOpaqueImpl(isOpaque); 820 if (isOpaque) { 821 TranslucentWindowPainter currentPainter = painter; 822 if (currentPainter != null) { 823 currentPainter.flush(); 824 painter = null; 825 } 826 } else { 827 painter = TranslucentWindowPainter.createInstance(this); 828 } 829 } 830 831 if (isVistaOS) { 832 // On Vista: setting the window non-opaque makes the window look 833 // rectangular, though still catching the mouse clicks within 834 // its shape only. To restore the correct visual appearance 835 // of the window (i.e. w/ the correct shape) we have to reset 836 // the shape. 837 Shape shape = target.getShape(); 838 if (shape != null) { 839 target.setShape(shape); 840 } 841 } 842 843 if (target.isVisible()) { 844 updateWindow(true); 845 } 846 } 847 848 native void updateWindowImpl(int[] data, int width, int height); 849 850 @Override 851 public void updateWindow() { 852 updateWindow(false); 853 } 854 855 private void updateWindow(boolean repaint) { 856 Window w = (Window)target; 857 synchronized (getStateLock()) { 858 if (isOpaque || !w.isVisible() || 859 (w.getWidth() <= 0) || (w.getHeight() <= 0)) 860 { 861 return; 862 } 863 TranslucentWindowPainter currentPainter = painter; 864 if (currentPainter != null) { 865 currentPainter.updateWindow(repaint); 866 } else if (log.isLoggable(PlatformLogger.Level.FINER)) { 867 log.finer("Translucent window painter is null in updateWindow"); 868 } 869 } 870 } 871 872 native void windowDPIChange(int prevScreen, float prevScaleX, float prevScaleY, 873 int newScreen, float newScaleX, float newScaleY); 874 875 /* 876 * The method maps the list of the active windows to the window's AppContext, 877 * then the method registers ActiveWindowListener, GuiDisposedListener listeners; 878 * it executes the initilialization only once per AppContext. 879 */ 880 @SuppressWarnings("unchecked") 881 private static void initActiveWindowsTracking(Window w) { 882 AppContext appContext = AppContext.getAppContext(); 883 synchronized (appContext) { 884 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 885 if (l == null) { 886 l = new LinkedList<WWindowPeer>(); 887 appContext.put(ACTIVE_WINDOWS_KEY, l); 888 appContext.addPropertyChangeListener(AppContext.GUI_DISPOSED, guiDisposedListener); 889 890 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 891 kfm.addPropertyChangeListener("activeWindow", activeWindowListener); 892 } 893 } 894 } 895 896 /* 897 * The GuiDisposedListener class listens for the AppContext.GUI_DISPOSED property, 898 * it removes the list of the active windows from the disposed AppContext and 899 * unregisters ActiveWindowListener listener. 900 */ 901 private static class GuiDisposedListener implements PropertyChangeListener { 902 @Override 903 public void propertyChange(PropertyChangeEvent e) { 904 boolean isDisposed = (Boolean)e.getNewValue(); 905 if (isDisposed != true) { 906 if (log.isLoggable(PlatformLogger.Level.FINE)) { 907 log.fine(" Assertion (newValue != true) failed for AppContext.GUI_DISPOSED "); 908 } 909 } 910 AppContext appContext = AppContext.getAppContext(); 911 synchronized (appContext) { 912 appContext.remove(ACTIVE_WINDOWS_KEY); 913 appContext.removePropertyChangeListener(AppContext.GUI_DISPOSED, this); 914 915 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 916 kfm.removePropertyChangeListener("activeWindow", activeWindowListener); 917 } 918 } 919 } 920 921 /* 922 * Static inner class, listens for 'activeWindow' KFM property changes and 923 * updates the list of active windows per AppContext, so the latest active 924 * window is always at the end of the list. The list is stored in AppContext. 925 */ 926 @SuppressWarnings("unchecked") 927 private static class ActiveWindowListener implements PropertyChangeListener { 928 @Override 929 public void propertyChange(PropertyChangeEvent e) { 930 Window w = (Window)e.getNewValue(); 931 if (w == null) { 932 return; 933 } 934 AppContext appContext = SunToolkit.targetToAppContext(w); 935 synchronized (appContext) { 936 WWindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w); 937 // add/move wp to the end of the list 938 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 939 if (l != null) { 940 l.remove(wp); 941 l.add(wp); 942 } 943 } 944 } 945 } 946 }