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