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