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