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