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