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