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