1 /*
   2  * Copyright (c) 1997, 2018, 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.AWTError;
  29 import java.awt.GraphicsConfiguration;
  30 import java.awt.GraphicsDevice;
  31 import java.awt.peer.ComponentPeer;
  32 import java.lang.ref.WeakReference;
  33 import java.util.ArrayList;
  34 import java.util.ListIterator;
  35 
  36 import sun.awt.windows.WToolkit;
  37 import sun.java2d.SunGraphicsEnvironment;
  38 import sun.java2d.SurfaceManagerFactory;
  39 import sun.java2d.WindowsSurfaceManagerFactory;
  40 import sun.java2d.d3d.D3DGraphicsDevice;
  41 import sun.java2d.windows.WindowsFlags;
  42 
  43 /**
  44  * This is an implementation of a GraphicsEnvironment object for the
  45  * default local GraphicsEnvironment used by the Java Runtime Environment
  46  * for Windows.
  47  *
  48  * @see GraphicsDevice
  49  * @see GraphicsConfiguration
  50  */
  51 
  52 public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
  53 
  54     static final float debugScaleX;
  55     static final float debugScaleY;
  56 
  57     static {
  58         // Ensure awt is loaded already.  Also, this forces static init
  59         // of WToolkit and Toolkit, which we depend upon
  60         WToolkit.loadLibraries();
  61         // setup flags before initializing native layer
  62         WindowsFlags.initFlags();
  63         initDisplayWrapper();
  64 
  65         // Install correct surface manager factory.
  66         SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory());
  67 
  68         double sx = -1;
  69         double sy = -1;
  70         if (isUIScaleEnabled()) {
  71             sx = getScaleFactor("sun.java2d.win.uiScaleX");
  72             sy = getScaleFactor("sun.java2d.win.uiScaleY");
  73             if (sx <= 0 || sy <= 0) {
  74                 double s = getDebugScale();
  75                 sx = s;
  76                 sy = s;
  77             }
  78         }
  79 
  80         debugScaleX = (float) sx;
  81         debugScaleY = (float) sy;
  82     }
  83 
  84     /**
  85      * Initializes native components of the graphics environment.  This
  86      * includes everything from the native GraphicsDevice elements to
  87      * the DirectX rendering layer.
  88      */
  89     private static native void initDisplay();
  90 
  91     private static boolean displayInitialized;      // = false;
  92     public static void initDisplayWrapper() {
  93         if (!displayInitialized) {
  94             displayInitialized = true;
  95             initDisplay();
  96         }
  97     }
  98 
  99     public Win32GraphicsEnvironment() {
 100     }
 101 
 102     protected native int getNumScreens();
 103     private native int getDefaultScreen();
 104 
 105     public GraphicsDevice getDefaultScreenDevice() {
 106         GraphicsDevice[] screens = getScreenDevices();
 107         if (screens.length == 0) {
 108             throw new AWTError("no screen devices");
 109         }
 110         int index = getDefaultScreen();
 111         return screens[0 < index && index < screens.length ? index : 0];
 112     }
 113 
 114     /**
 115      * Returns the number of pixels per logical inch along the screen width.
 116      * In a system with multiple display monitors, this value is the same for
 117      * all monitors.
 118      * @return number of pixels per logical inch in X direction
 119      */
 120     public native int getXResolution();
 121     /**
 122      * Returns the number of pixels per logical inch along the screen height.
 123      * In a system with multiple display monitors, this value is the same for
 124      * all monitors.
 125      * @return number of pixels per logical inch in Y direction
 126      */
 127     public native int getYResolution();
 128 
 129 
 130 /*
 131  * ----DISPLAY CHANGE SUPPORT----
 132  */
 133 
 134     // list of invalidated graphics devices (those which were removed)
 135     private ArrayList<WeakReference<Win32GraphicsDevice>> oldDevices;
 136     /*
 137      * From DisplayChangeListener interface.
 138      * Called from WToolkit and executed on the event thread when the
 139      * display settings are changed.
 140      */
 141     @Override
 142     public void displayChanged() {
 143         // getNumScreens() will return the correct current number of screens
 144         GraphicsDevice[] newDevices = new GraphicsDevice[getNumScreens()];
 145         GraphicsDevice[] oldScreens = screens;
 146         // go through the list of current devices and determine if they
 147         // could be reused, or will have to be replaced
 148         if (oldScreens != null) {
 149             for (int i = 0; i < oldScreens.length; i++) {
 150                 if (!(screens[i] instanceof Win32GraphicsDevice)) {
 151                     // REMIND: can we ever have anything other than Win32GD?
 152                     assert (false) : oldScreens[i];
 153                     continue;
 154                 }
 155                 Win32GraphicsDevice gd = (Win32GraphicsDevice)oldScreens[i];
 156                 // devices may be invalidated from the native code when the
 157                 // display change happens (device add/removal also causes a
 158                 // display change)
 159                 if (!gd.isValid()) {
 160                     if (oldDevices == null) {
 161                         oldDevices =
 162                             new ArrayList<WeakReference<Win32GraphicsDevice>>();
 163                     }
 164                     oldDevices.add(new WeakReference<Win32GraphicsDevice>(gd));
 165                 } else if (i < newDevices.length) {
 166                     // reuse the device
 167                     newDevices[i] = gd;
 168                 }
 169             }
 170             oldScreens = null;
 171         }
 172         // create the new devices (those that weren't reused)
 173         for (int i = 0; i < newDevices.length; i++) {
 174             if (newDevices[i] == null) {
 175                 newDevices[i] = makeScreenDevice(i);
 176             }
 177         }
 178         // install the new array of devices
 179         // Note: no synchronization here, it doesn't matter if a thread gets
 180         // a new or an old array this time around
 181         screens = newDevices;
 182         for (GraphicsDevice gd : screens) {
 183             if (gd instanceof DisplayChangedListener) {
 184                 ((DisplayChangedListener)gd).displayChanged();
 185             }
 186         }
 187         // re-invalidate all old devices. It's needed because those in the list
 188         // may become "invalid" again - if the current default device is removed,
 189         // for example. Also, they need to be notified about display
 190         // changes as well.
 191         if (oldDevices != null) {
 192             int defScreen = getDefaultScreen();
 193             for (ListIterator<WeakReference<Win32GraphicsDevice>> it =
 194                     oldDevices.listIterator(); it.hasNext();)
 195             {
 196                 Win32GraphicsDevice gd = it.next().get();
 197                 if (gd != null) {
 198                     gd.invalidate(defScreen);
 199                     gd.displayChanged();
 200                 } else {
 201                     // no more references to this device, remove it
 202                     it.remove();
 203                 }
 204             }
 205         }
 206         // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and
 207         // CachingSurfaceManagers) about the display change event
 208         displayChanger.notifyListeners();
 209         // note: do not call super.displayChanged, we've already done everything
 210     }
 211 
 212 
 213 /*
 214  * ----END DISPLAY CHANGE SUPPORT----
 215  */
 216 
 217     protected GraphicsDevice makeScreenDevice(int screennum) {
 218         GraphicsDevice device = null;
 219         if (WindowsFlags.isD3DEnabled()) {
 220             device = D3DGraphicsDevice.createDevice(screennum);
 221         }
 222         if (device == null) {
 223             device = new Win32GraphicsDevice(screennum);
 224         }
 225         return device;
 226     }
 227 
 228     public boolean isDisplayLocal() {
 229         return true;
 230     }
 231 
 232     @Override
 233     public boolean isFlipStrategyPreferred(ComponentPeer peer) {
 234         GraphicsConfiguration gc;
 235         if (peer != null && (gc = peer.getGraphicsConfiguration()) != null) {
 236             GraphicsDevice gd = gc.getDevice();
 237             if (gd instanceof D3DGraphicsDevice) {
 238                 return ((D3DGraphicsDevice)gd).isD3DEnabledOnDevice();
 239             }
 240         }
 241         return false;
 242     }
 243 
 244     private static volatile boolean isDWMCompositionEnabled;
 245     /**
 246      * Returns true if dwm composition is currently enabled, false otherwise.
 247      *
 248      * @return true if dwm composition is enabled, false otherwise
 249      */
 250     public static boolean isDWMCompositionEnabled() {
 251         return isDWMCompositionEnabled;
 252     }
 253 
 254     /**
 255      * Called from the native code when DWM composition state changed.
 256      * May be called multiple times during the lifetime of the application.
 257      * REMIND: we may want to create a listener mechanism for this.
 258      *
 259      * Note: called on the Toolkit thread, no user code or locks are allowed.
 260      *
 261      * @param enabled indicates the state of dwm composition
 262      */
 263     private static void dwmCompositionChanged(boolean enabled) {
 264         isDWMCompositionEnabled = enabled;
 265     }
 266 
 267     /**
 268      * Used to find out if the OS is Windows Vista or later.
 269      *
 270      * @return {@code true} if the OS is Vista or later, {@code false} otherwise
 271      */
 272     public static native boolean isVistaOS();
 273 }