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