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