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 }