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