1 /*
   2  * Copyright (c) 1997, 2015, 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;
  27 
  28 import java.awt.AWTPermission;
  29 import java.awt.GraphicsDevice;
  30 import java.awt.GraphicsConfiguration;
  31 import java.awt.GraphicsEnvironment;
  32 import java.awt.DisplayMode;
  33 import java.awt.EventQueue;
  34 import java.awt.Frame;
  35 import java.awt.Rectangle;
  36 import java.awt.Window;
  37 import java.awt.event.WindowAdapter;
  38 import java.awt.event.WindowEvent;
  39 import java.awt.event.WindowListener;
  40 import java.awt.geom.Point2D;
  41 import java.awt.image.ColorModel;
  42 import java.util.ArrayList;
  43 import java.util.Vector;
  44 import java.awt.peer.WindowPeer;
  45 import java.security.AccessController;
  46 import sun.awt.windows.WWindowPeer;
  47 import sun.java2d.opengl.WGLGraphicsConfig;
  48 import sun.java2d.windows.WindowsFlags;
  49 import sun.security.action.GetPropertyAction;
  50 
  51 /**
  52  * This is an implementation of a GraphicsDevice object for a single
  53  * Win32 screen.
  54  *
  55  * @see GraphicsEnvironment
  56  * @see GraphicsConfiguration
  57  */
  58 public class Win32GraphicsDevice extends GraphicsDevice implements
  59  DisplayChangedListener {
  60     int screen;
  61     ColorModel dynamicColorModel;   // updated with dev changes
  62     ColorModel colorModel;          // static for device
  63     protected GraphicsConfiguration[] configs;
  64     protected GraphicsConfiguration defaultConfig;
  65 
  66     private final String idString;
  67     protected String descString;
  68     // Note that we do not synchronize access to this variable - it doesn't
  69     // really matter if a thread does an operation on graphics device which is
  70     // about to become invalid (or already become) - we are prepared to deal
  71     // with this on the native level.
  72     private boolean valid;
  73 
  74     // keep track of top-level windows on this display
  75     private SunDisplayChanger topLevels = new SunDisplayChanger();
  76     // REMIND: we may disable the use of pixel formats for some accelerated
  77     // pipelines which are mutually exclusive with opengl, for which
  78     // pixel formats were added in the first place
  79     protected static boolean pfDisabled;
  80     private static AWTPermission fullScreenExclusivePermission;
  81     // the original display mode we had before entering the fullscreen
  82     // mode
  83     private DisplayMode defaultDisplayMode;
  84     // activation/deactivation listener for the full-screen window
  85     private WindowListener fsWindowListener;
  86 
  87     private static final boolean uiScaleEnabled;
  88     private static final float propsScaleX;
  89     private static final float propsScaleY;
  90     private float scaleX = 1.0f;
  91     private float scaleY = 1.0f;
  92 
  93     static {
  94 
  95         // 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when
  96         // pixel format calls are made.  This causes problems when a Java app
  97         // is run as an NT service.  To prevent the loading of ddraw.dll
  98         // completely, sun.awt.nopixfmt should be set as well.  Apps which use
  99         // OpenGL w/ Java probably don't want to set this.
 100         String nopixfmt = java.security.AccessController.doPrivileged(
 101             new sun.security.action.GetPropertyAction("sun.awt.nopixfmt"));
 102         pfDisabled = (nopixfmt != null);
 103         initIDs();
 104 
 105         uiScaleEnabled = "true".equals(AccessController.doPrivileged(
 106                 new GetPropertyAction("sun.java2d.uiScale.enabled", "true")));
 107 
 108         if (uiScaleEnabled) {
 109             float sx = getScaleFactor("sun.java2d.win.uiScaleX");
 110             float sy = getScaleFactor("sun.java2d.win.uiScaleY");
 111             if (sx > 0 && sy > 0) {
 112                 propsScaleX = sx;
 113                 propsScaleY = sy;
 114             } else {
 115                 float scale = getScaleFactor("sun.java2d.uiScale");
 116                 propsScaleX = scale;
 117                 propsScaleY = scale;
 118             }
 119         } else {
 120             propsScaleX = -1;
 121             propsScaleY = -1;
 122         }
 123     }
 124 
 125     private static native void initIDs();
 126 
 127     native void initDevice(int screen);
 128     native void initNativeScale(int screen);
 129     native void setNativeScale(int screen, float scaleX, float scaleY);
 130     native float getNativeScaleX(int screen);
 131     native float getNativeScaleY(int screen);
 132 
 133     public Win32GraphicsDevice(int screennum) {
 134         this.screen = screennum;
 135         // we cache the strings because we want toString() and getIDstring
 136         // to reflect the original screen number (which may change if the
 137         // device is removed)
 138         idString = "\\Display"+screen;
 139         // REMIND: may be should use class name?
 140         descString = "Win32GraphicsDevice[screen=" + screen;
 141         valid = true;
 142 
 143         initDevice(screennum);
 144         initScaleFactors();
 145     }
 146 
 147     /**
 148      * Returns the type of the graphics device.
 149      * @see #TYPE_RASTER_SCREEN
 150      * @see #TYPE_PRINTER
 151      * @see #TYPE_IMAGE_BUFFER
 152      */
 153     public int getType() {
 154         return TYPE_RASTER_SCREEN;
 155     }
 156 
 157     /**
 158      * Returns the Win32 screen of the device.
 159      */
 160     public int getScreen() {
 161         return screen;
 162     }
 163 
 164     public float getDefaultScaleX() {
 165         return scaleX;
 166     }
 167 
 168     public float getDefaultScaleY() {
 169         return scaleY;
 170     }
 171 
 172     private void initScaleFactors() {
 173         if (uiScaleEnabled) {
 174             if (propsScaleX > 0 && propsScaleY > 0) {
 175                 scaleX = propsScaleX;
 176                 scaleY = propsScaleY;
 177                 setNativeScale(screen, scaleX, scaleY);
 178             } else {
 179                 initNativeScale(screen);
 180                 scaleX = getNativeScaleX(screen);
 181                 scaleY = getNativeScaleY(screen);
 182             }
 183         }
 184     }
 185 
 186     private static float getScaleFactor(String name) {
 187 
 188         String scaleFactor = AccessController.doPrivileged(
 189                 new GetPropertyAction(name, "-1"));
 190 
 191         if (scaleFactor == null || scaleFactor.equals("-1")) {
 192             return -1;
 193         }
 194         try {
 195 
 196             if (scaleFactor.endsWith("dpi")) {
 197                 scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3);
 198                 float scale = Float.parseFloat(scaleFactor);
 199                 return scale <= 0 ? -1 : scale / 96;
 200             }
 201 
 202             if (scaleFactor.endsWith("%")) {
 203                 scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);
 204                 float scale = Float.parseFloat(scaleFactor);
 205                 return scale <= 0 ? -1 : scale / 100;
 206             }
 207 
 208             float scale = Float.parseFloat(scaleFactor);
 209             return (scale <=0) ? -1 : scale;
 210 
 211         } catch (NumberFormatException ignore) {
 212         }
 213         return -1;
 214     }
 215 
 216     /**
 217      * Returns whether this is a valid devicie. Device can become
 218      * invalid as a result of device removal event.
 219      */
 220     public boolean isValid() {
 221         return valid;
 222     }
 223 
 224     /**
 225      * Called from native code when the device was removed.
 226      *
 227      * @param defaultScreen the current default screen
 228      */
 229     protected void invalidate(int defaultScreen) {
 230         valid = false;
 231         screen = defaultScreen;
 232     }
 233 
 234     /**
 235      * Returns the identification string associated with this graphics
 236      * device.
 237      */
 238     public String getIDstring() {
 239         return idString;
 240     }
 241 
 242 
 243     /**
 244      * Returns all of the graphics
 245      * configurations associated with this graphics device.
 246      */
 247     public GraphicsConfiguration[] getConfigurations() {
 248         if (configs==null) {
 249             if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {
 250                 defaultConfig = getDefaultConfiguration();
 251                 if (defaultConfig != null) {
 252                     configs = new GraphicsConfiguration[1];
 253                     configs[0] = defaultConfig;
 254                     return configs.clone();
 255                 }
 256             }
 257 
 258             int max = getMaxConfigs(screen);
 259             int defaultPixID = getDefaultPixID(screen);
 260             Vector<GraphicsConfiguration> v = new Vector<>( max );
 261             if (defaultPixID == 0) {
 262                 // Workaround for failing GDI calls
 263                 defaultConfig = Win32GraphicsConfig.getConfig(this,
 264                                                               defaultPixID);
 265                 v.addElement(defaultConfig);
 266             }
 267             else {
 268                 for (int i = 1; i <= max; i++) {
 269                     if (isPixFmtSupported(i, screen)) {
 270                         if (i == defaultPixID) {
 271                             defaultConfig = Win32GraphicsConfig.getConfig(
 272                              this, i);
 273                             v.addElement(defaultConfig);
 274                         }
 275                         else {
 276                             v.addElement(Win32GraphicsConfig.getConfig(
 277                              this, i));
 278                         }
 279                     }
 280                 }
 281             }
 282             configs = new GraphicsConfiguration[v.size()];
 283             v.copyInto(configs);
 284         }
 285         return configs.clone();
 286     }
 287 
 288     /**
 289      * Returns the maximum number of graphics configurations available, or 1
 290      * if PixelFormat calls fail or are disabled.
 291      * This number is less than or equal to the number of graphics
 292      * configurations supported.
 293      */
 294     protected int getMaxConfigs(int screen) {
 295         if (pfDisabled) {
 296             return 1;
 297         } else {
 298             return getMaxConfigsImpl(screen);
 299         }
 300     }
 301 
 302     private native int getMaxConfigsImpl(int screen);
 303 
 304     /**
 305      * Returns whether or not the PixelFormat indicated by index is
 306      * supported.  Supported PixelFormats support drawing to a Window
 307      * (PFD_DRAW_TO_WINDOW), support GDI (PFD_SUPPORT_GDI), and in the
 308      * case of an 8-bit format (cColorBits <= 8) uses indexed colors
 309      * (iPixelType == PFD_TYPE_COLORINDEX).
 310      * We use the index 0 to indicate that PixelFormat calls don't work, or
 311      * are disabled.  Do not call this function with an index of 0.
 312      * @param index a PixelFormat index
 313      */
 314     private native boolean isPixFmtSupported(int index, int screen);
 315 
 316     /**
 317      * Returns the PixelFormatID of the default graphics configuration
 318      * associated with this graphics device, or 0 if PixelFormats calls fail or
 319      * are disabled.
 320      */
 321     protected int getDefaultPixID(int screen) {
 322         if (pfDisabled) {
 323             return 0;
 324         } else {
 325             return getDefaultPixIDImpl(screen);
 326         }
 327     }
 328 
 329     /**
 330      * Returns the default PixelFormat ID from GDI.  Do not call if PixelFormats
 331      * are disabled.
 332      */
 333     private native int getDefaultPixIDImpl(int screen);
 334 
 335     /**
 336      * Returns the default graphics configuration
 337      * associated with this graphics device.
 338      */
 339     public GraphicsConfiguration getDefaultConfiguration() {
 340         if (defaultConfig == null) {
 341             // first try to create a WGLGraphicsConfig if OGL is enabled
 342             // REMIND: the WGL code does not yet work properly in multimon
 343             // situations, so we will fallback on GDI if we are not on the
 344             // default device...
 345             if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {
 346                 int defPixID = WGLGraphicsConfig.getDefaultPixFmt(screen);
 347                 defaultConfig = WGLGraphicsConfig.getConfig(this, defPixID);
 348                 if (WindowsFlags.isOGLVerbose()) {
 349                     if (defaultConfig != null) {
 350                         System.out.print("OpenGL pipeline enabled");
 351                     } else {
 352                         System.out.print("Could not enable OpenGL pipeline");
 353                     }
 354                     System.out.println(" for default config on screen " +
 355                                        screen);
 356                 }
 357             }
 358 
 359             // Fix for 4669614.  Most apps are not concerned with PixelFormats,
 360             // yet we ALWAYS used them for determining ColorModels and such.
 361             // By passing in 0 as the PixelFormatID here, we signal that
 362             // PixelFormats should not be used, thus avoid loading the opengl
 363             // library.  Apps concerned with PixelFormats can still use
 364             // GraphicsConfiguration.getConfigurations().
 365             // Note that calling native pixel format functions tends to cause
 366             // problems between those functions (which are OpenGL-related)
 367             // and our use of DirectX.  For example, some Matrox boards will
 368             // crash or hang calling these functions when any app is running
 369             // in DirectX fullscreen mode.  So avoiding these calls unless
 370             // absolutely necessary is preferable.
 371             if (defaultConfig == null) {
 372                 defaultConfig = Win32GraphicsConfig.getConfig(this, 0);
 373             }
 374         }
 375         return defaultConfig;
 376     }
 377 
 378     public String toString() {
 379         return valid ? descString + "]" : descString + ", removed]";
 380     }
 381 
 382     /**
 383      * Returns true if this is the default GraphicsDevice for the
 384      * GraphicsEnvironment.
 385      */
 386     private boolean isDefaultDevice() {
 387         return (this ==
 388                 GraphicsEnvironment.
 389                     getLocalGraphicsEnvironment().getDefaultScreenDevice());
 390     }
 391 
 392     private static boolean isFSExclusiveModeAllowed() {
 393         SecurityManager security = System.getSecurityManager();
 394         if (security != null) {
 395             if (fullScreenExclusivePermission == null) {
 396                 fullScreenExclusivePermission =
 397                     new AWTPermission("fullScreenExclusive");
 398             }
 399             try {
 400                 security.checkPermission(fullScreenExclusivePermission);
 401             } catch (SecurityException e) {
 402                 return false;
 403             }
 404         }
 405         return true;
 406     }
 407 
 408     /**
 409      * returns true unless we're not allowed to use fullscreen mode.
 410      */
 411     @Override
 412     public boolean isFullScreenSupported() {
 413         return isFSExclusiveModeAllowed();
 414     }
 415 
 416     @Override
 417     public synchronized void setFullScreenWindow(Window w) {
 418         Window old = getFullScreenWindow();
 419         if (w == old) {
 420             return;
 421         }
 422         if (!isFullScreenSupported()) {
 423             super.setFullScreenWindow(w);
 424             return;
 425         }
 426 
 427         // Enter windowed mode.
 428         if (old != null) {
 429             // restore the original display mode
 430             if (defaultDisplayMode != null) {
 431                 setDisplayMode(defaultDisplayMode);
 432                 // we set the default display mode to null here
 433                 // because the default mode could change during
 434                 // the life of the application (user can change it through
 435                 // the desktop properties dialog, for example), so
 436                 // we need to record it every time prior to
 437                 // entering the fullscreen mode.
 438                 defaultDisplayMode = null;
 439             }
 440             WWindowPeer peer = AWTAccessor.getComponentAccessor().getPeer(old);
 441             if (peer != null) {
 442                 peer.setFullScreenExclusiveModeState(false);
 443                 // we used to destroy the buffers on exiting fs mode, this
 444                 // is no longer needed since fs change will cause a surface
 445                 // data replacement
 446                 synchronized(peer) {
 447                     exitFullScreenExclusive(screen, peer);
 448                 }
 449             }
 450             removeFSWindowListener(old);
 451         }
 452         super.setFullScreenWindow(w);
 453         if (w != null) {
 454             // always record the default display mode prior to going
 455             // fullscreen
 456             defaultDisplayMode = getDisplayMode();
 457             addFSWindowListener(w);
 458             // Enter full screen exclusive mode.
 459             WWindowPeer peer = AWTAccessor.getComponentAccessor().getPeer(w);
 460             if (peer != null) {
 461                 synchronized(peer) {
 462                     enterFullScreenExclusive(screen, peer);
 463                     // Note: removed replaceSurfaceData() call because
 464                     // changing the window size or making it visible
 465                     // will cause this anyway, and both of these events happen
 466                     // as part of switching into fullscreen mode.
 467                 }
 468                 peer.setFullScreenExclusiveModeState(true);
 469             }
 470 
 471             // fix for 4868278
 472             peer.updateGC();
 473         }
 474     }
 475 
 476     // Entering and exiting full-screen mode are done within a
 477     // tree-lock and should never lock on any resources which are
 478     // required by other threads which may have them and may require
 479     // the tree-lock.
 480     // REMIND: in the future these methods may need to become protected so that
 481     // subclasses could override them and use appropriate api other than GDI
 482     // for implementing these functions.
 483     protected native void enterFullScreenExclusive(int screen, WindowPeer w);
 484     protected native void exitFullScreenExclusive(int screen, WindowPeer w);
 485 
 486     @Override
 487     public boolean isDisplayChangeSupported() {
 488         return (isFullScreenSupported() && getFullScreenWindow() != null);
 489     }
 490 
 491     @Override
 492     public synchronized void setDisplayMode(DisplayMode dm) {
 493         if (!isDisplayChangeSupported()) {
 494             super.setDisplayMode(dm);
 495             return;
 496         }
 497         if (dm == null || (dm = getMatchingDisplayMode(dm)) == null) {
 498             throw new IllegalArgumentException("Invalid display mode");
 499         }
 500         if (getDisplayMode().equals(dm)) {
 501             return;
 502         }
 503         Window w = getFullScreenWindow();
 504         if (w != null) {
 505             WWindowPeer peer = AWTAccessor.getComponentAccessor().getPeer(w);
 506             configDisplayMode(screen, peer, dm.getWidth(), dm.getHeight(),
 507                 dm.getBitDepth(), dm.getRefreshRate());
 508             // resize the fullscreen window to the dimensions of the new
 509             // display mode
 510             Rectangle screenBounds = getDefaultConfiguration().getBounds();
 511             w.setBounds(screenBounds.x, screenBounds.y,
 512                         dm.getWidth(), dm.getHeight());
 513             // Note: no call to replaceSurfaceData is required here since
 514             // replacement will be caused by an upcoming display change event
 515         } else {
 516             throw new IllegalStateException("Must be in fullscreen mode " +
 517                                             "in order to set display mode");
 518         }
 519     }
 520 
 521     protected native DisplayMode getCurrentDisplayMode(int screen);
 522     protected native void configDisplayMode(int screen, WindowPeer w, int width,
 523                                           int height, int bitDepth,
 524                                           int refreshRate);
 525     protected native void enumDisplayModes(int screen, ArrayList<DisplayMode> modes);
 526 
 527     @Override
 528     public synchronized DisplayMode getDisplayMode() {
 529         DisplayMode res = getCurrentDisplayMode(screen);
 530         return res;
 531     }
 532 
 533     @Override
 534     public synchronized DisplayMode[] getDisplayModes() {
 535         ArrayList<DisplayMode> modes = new ArrayList<>();
 536         enumDisplayModes(screen, modes);
 537         int listSize = modes.size();
 538         DisplayMode[] retArray = new DisplayMode[listSize];
 539         for (int i = 0; i < listSize; i++) {
 540             retArray[i] = modes.get(i);
 541         }
 542         return retArray;
 543     }
 544 
 545     protected synchronized DisplayMode getMatchingDisplayMode(DisplayMode dm) {
 546         if (!isDisplayChangeSupported()) {
 547             return null;
 548         }
 549         DisplayMode[] modes = getDisplayModes();
 550         for (DisplayMode mode : modes) {
 551             if (dm.equals(mode) ||
 552                 (dm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN &&
 553                  dm.getWidth() == mode.getWidth() &&
 554                  dm.getHeight() == mode.getHeight() &&
 555                  dm.getBitDepth() == mode.getBitDepth()))
 556             {
 557                 return mode;
 558             }
 559         }
 560         return null;
 561     }
 562 
 563     /*
 564      * From the DisplayChangeListener interface.
 565      * Called from Win32GraphicsEnvironment when the display settings have
 566      * changed.
 567      */
 568     public void displayChanged() {
 569         dynamicColorModel = null;
 570         defaultConfig = null;
 571         configs = null;
 572         // pass on to all top-level windows on this display
 573         topLevels.notifyListeners();
 574         initScaleFactors();
 575     }
 576 
 577     /**
 578      * Part of the DisplayChangedListener interface: devices
 579      * do not need to react to this event
 580      */
 581     public void paletteChanged() {
 582     }
 583 
 584     /*
 585      * Add a DisplayChangeListener to be notified when the display settings
 586      * are changed.  Typically, only top-level containers need to be added
 587      * to Win32GraphicsDevice.
 588      */
 589     public void addDisplayChangedListener(DisplayChangedListener client) {
 590         topLevels.add(client);
 591     }
 592 
 593     /*
 594      * Remove a DisplayChangeListener from this Win32GraphicsDevice
 595      */
 596      public void removeDisplayChangedListener(DisplayChangedListener client) {
 597         topLevels.remove(client);
 598     }
 599 
 600     /**
 601      * Creates and returns the color model associated with this device
 602      */
 603     private native ColorModel makeColorModel (int screen,
 604                                               boolean dynamic);
 605 
 606     /**
 607      * Returns a dynamic ColorModel which is updated when there
 608      * are any changes (e.g., palette changes) in the device
 609      */
 610     public ColorModel getDynamicColorModel() {
 611         if (dynamicColorModel == null) {
 612             dynamicColorModel = makeColorModel(screen, true);
 613         }
 614         return dynamicColorModel;
 615     }
 616 
 617     /**
 618      * Returns the non-dynamic ColorModel associated with this device
 619      */
 620     public ColorModel getColorModel() {
 621         if (colorModel == null)  {
 622             colorModel = makeColorModel(screen, false);
 623         }
 624         return colorModel;
 625     }
 626 
 627     /**
 628      * WindowAdapter class responsible for de/iconifying full-screen window
 629      * of this device.
 630      *
 631      * The listener restores the default display mode when window is iconified
 632      * and sets it back to the one set by the user on de-iconification.
 633      */
 634     private static class Win32FSWindowAdapter extends WindowAdapter {
 635         private Win32GraphicsDevice device;
 636         private DisplayMode dm;
 637 
 638         Win32FSWindowAdapter(Win32GraphicsDevice device) {
 639             this.device = device;
 640         }
 641 
 642         private void setFSWindowsState(Window other, int state) {
 643             GraphicsDevice gds[] =
 644                     GraphicsEnvironment.getLocalGraphicsEnvironment().
 645                     getScreenDevices();
 646             // check if the de/activation was caused by other
 647             // fs window and ignore the event if that's the case
 648             if (other != null) {
 649                 for (GraphicsDevice gd : gds) {
 650                     if (other == gd.getFullScreenWindow()) {
 651                         return;
 652                     }
 653                 }
 654             }
 655             // otherwise apply state to all fullscreen windows
 656             for (GraphicsDevice gd : gds) {
 657                 Window fsw = gd.getFullScreenWindow();
 658                 if (fsw instanceof Frame) {
 659                     ((Frame)fsw).setExtendedState(state);
 660                 }
 661             }
 662         }
 663 
 664         @Override
 665         public void windowDeactivated(WindowEvent e) {
 666             setFSWindowsState(e.getOppositeWindow(), Frame.ICONIFIED);
 667         }
 668 
 669         @Override
 670         public void windowActivated(WindowEvent e) {
 671             setFSWindowsState(e.getOppositeWindow(), Frame.NORMAL);
 672         }
 673 
 674         @Override
 675         public void windowIconified(WindowEvent e) {
 676             // restore the default display mode for this device
 677             DisplayMode ddm = device.defaultDisplayMode;
 678             if (ddm != null) {
 679                 dm = device.getDisplayMode();
 680                 device.setDisplayMode(ddm);
 681             }
 682         }
 683 
 684         @Override
 685         public void windowDeiconified(WindowEvent e) {
 686             // restore the user-set display mode for this device
 687             if (dm != null) {
 688                 device.setDisplayMode(dm);
 689                 dm = null;
 690             }
 691         }
 692     }
 693 
 694     /**
 695      * Adds a WindowListener to be used as
 696      * activation/deactivation listener for the current full-screen window.
 697      *
 698      * @param w full-screen window
 699      */
 700     protected void addFSWindowListener(final Window w) {
 701         // Note: even though we create a listener for Window instances of
 702         // fs windows they will not receive window events.
 703         fsWindowListener = new Win32FSWindowAdapter(this);
 704 
 705         // Fix for 6709453. Using invokeLater to avoid listening
 706         // for the events already posted to the queue.
 707         EventQueue.invokeLater(new Runnable() {
 708             public void run() {
 709                 w.addWindowListener(fsWindowListener);
 710             }
 711         });
 712     }
 713 
 714     /**
 715      * Removes the fs window listener.
 716      *
 717      * @param w full-screen window
 718      */
 719     protected void removeFSWindowListener(Window w) {
 720         w.removeWindowListener(fsWindowListener);
 721         fsWindowListener = null;
 722     }
 723 }