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